Introduced the `OpenSearch` method and `SearchPage` interface to streamline search operations and allow for loading more results dynamically. Updated dependencies and modified the DuckDuckGo CLI to utilize these enhancements.
69 lines
1.1 KiB
Go
69 lines
1.1 KiB
Go
package duckduckgo
|
|
|
|
import (
|
|
"fmt"
|
|
"gitea.stevedudenhoeffer.com/steve/go-extractor"
|
|
"io"
|
|
"log/slog"
|
|
)
|
|
|
|
type SearchPage interface {
|
|
io.Closer
|
|
GetResults() []Result
|
|
LoadMore() error
|
|
}
|
|
|
|
type searchPage struct {
|
|
doc extractor.Document
|
|
}
|
|
|
|
func (s searchPage) GetResults() []Result {
|
|
var res []Result
|
|
var err error
|
|
|
|
err = s.doc.ForEach(`article[id^="r1-"]`, func(n extractor.Node) error {
|
|
var r Result
|
|
|
|
links := n.Select(`a[href][target="_self"]`)
|
|
|
|
if len(links) == 0 {
|
|
return nil
|
|
}
|
|
|
|
r.URL, err = links[0].Attr(`href`)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get link: %w", err)
|
|
}
|
|
|
|
titles := n.Select("h2")
|
|
|
|
if len(titles) != 0 {
|
|
r.Title, _ = titles[0].Text()
|
|
}
|
|
|
|
descriptions := n.Select("span > span")
|
|
|
|
if len(descriptions) != 0 {
|
|
r.Description, _ = descriptions[0].Text()
|
|
}
|
|
|
|
res = append(res, r)
|
|
|
|
return nil
|
|
})
|
|
|
|
return res
|
|
}
|
|
|
|
func (s searchPage) LoadMore() error {
|
|
return s.doc.ForEach(`button#more-results`, func(n extractor.Node) error {
|
|
slog.Info("clicking load more", "node", n)
|
|
return n.Click()
|
|
})
|
|
}
|
|
|
|
func (s searchPage) Close() error {
|
|
return s.doc.Close()
|
|
}
|