func ExtractContent(page io.Reader) (string, error) {
	document, err := goquery.NewDocumentFromReader(page)
	if err != nil {
		return "", err
	}
	document.Find("script,style").Each(func(i int, s *goquery.Selection) {
		removeNodes(s)
	})
	transformMisusedDivsIntoParagraphs(document)
	removeUnlikelyCandidates(document)
	candidates := getCandidates(document)
	logger.Debug("[Readability] Candidates: %v", candidates)
	topCandidate := getTopCandidate(document, candidates)
	logger.Debug("[Readability] TopCandidate: %v", topCandidate)
	output := getArticle(topCandidate, candidates)
	return output, nil
}
ExtractContent returns relevant content.
package readability  
import (
	"bytes"
	"fmt"
	"io"
	"math"
	"regexp"
	"strings"
	"miniflux.app/logger"
	"github.com/PuerkitoBio/goquery"
	"golang.org/x/net/html"
)
const (
	defaultTagsToScore = "section,h2,h3,h4,h5,h6,p,td,pre,div"
)
var (
	divToPElementsRegexp = regexp.MustCompile(`(?i)<(a|blockquote|dl|div|img|ol|p|pre|table|ul)`)
	sentenceRegexp       = regexp.MustCompile(`\.( |$)`)
	blacklistCandidatesRegexp  = regexp.MustCompile(`(?i)popupbody|-ad|g-plus`)
	okMaybeItsACandidateRegexp = regexp.MustCompile(`(?i)and|article|body|column|main|shadow`)
	unlikelyCandidatesRegexp   = regexp.MustCompile(`(?i)banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|header|legends|menu|modal|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote`)
	negativeRegexp = regexp.MustCompile(`(?i)hidden|^hid$|hid$|hid|^hid |banner|combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|modal|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget|byline|author|dateline|writtenby|p-author`)
	positiveRegexp = regexp.MustCompile(`(?i)article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story`)
)
type candidate struct {
	selection *goquery.Selection
	score     float32
}
func (c *candidate) Node() *html.Node {
	return c.selection.Get(0)
}
func (c *candidate) String() string {
	id, _ := c.selection.Attr("id")
	class, _ := c.selection.Attr("class")
	if id != "" && class != "" {
		return fmt.Sprintf("%s#%s.%s => %f", c.Node().DataAtom, id, class, c.score)
	} else if id != "" {
		return fmt.Sprintf("%s#%s => %f", c.Node().DataAtom, id, c.score)
	} else if class != "" {
		return fmt.Sprintf("%s.%s => %f", c.Node().DataAtom, class, c.score)
	}
	return fmt.Sprintf("%s => %f", c.Node().DataAtom, c.score)
}
type candidateList map[*html.Node]*candidate
func (c candidateList) String() string {
	var output []string
	for _, candidate := range c {
		output = append(output, candidate.String())
	}
	return strings.Join(output, ", ")
}