tags, falling back to all
), trimmed // and capped at MaxBodyChars. Returns "" on any fetch failure. func FetchArticleBody(articleURL string) string { if articleURL == "" { return "" } ctx, cancel := context.WithTimeout(context.Background(), 12*time.Second) defer cancel() req, err := http.NewRequestWithContext(ctx, "GET", articleURL, nil) if err != nil { return "" } req.Header.Set("User-Agent", userAgent) req.Header.Set("Accept", "text/html,application/xhtml+xml") resp, err := articleClient.Do(req) if err != nil { return "" } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return "" } doc, err := goquery.NewDocumentFromReader(resp.Body) if err != nil { return "" } return extractBodyText(doc) } func extractBodyText(doc *goquery.Document) string { sel := doc.Find("article p, main p") if sel.Length() == 0 { sel = doc.Find("p") } var b strings.Builder sel.Each(func(_ int, s *goquery.Selection) { t := strings.TrimSpace(s.Text()) if t == "" { return } if b.Len() > 0 { b.WriteString("\n\n") } b.WriteString(t) if b.Len() >= MaxBodyChars { return } }) out := strings.TrimSpace(b.String()) if len(out) > MaxBodyChars { out = out[:MaxBodyChars] } return out } func extractOGImage(doc *goquery.Document, base string) string { selectors := []string{ `meta[property="og:image:secure_url"]`, `meta[property="og:image:url"]`, `meta[property="og:image"]`, `meta[name="twitter:image:src"]`, `meta[name="twitter:image"]`, } for _, sel := range selectors { if v, ok := doc.Find(sel).First().Attr("content"); ok && strings.TrimSpace(v) != "" { return resolveURL(base, strings.TrimSpace(v)) } } return "" } // extractBodyChars concatenates the text of
tags inside tags, and returns the trimmed length.
func extractBodyChars(doc *goquery.Document) int {
sel := doc.Find("article p, main p")
if sel.Length() == 0 {
sel = doc.Find("p")
}
var b strings.Builder
sel.Each(func(_ int, s *goquery.Selection) {
t := strings.TrimSpace(s.Text())
if t == "" {
return
}
if b.Len() > 0 {
b.WriteByte(' ')
}
b.WriteString(t)
})
return len(strings.TrimSpace(b.String()))
}