Documentation
¶
Overview ¶
Package newspaper is a Go implementation of Python's newspaper3k library: a toolkit for downloading web pages and extracting the *article* from the surrounding clutter (navigation, ads, comments, sidebars, footers).
What problem does this solve? ¶
A news web page is mostly NOT the article. A typical page is 95% template (menus, related-links, newsletter prompts, social buttons, legal boilerplate) and 5% the story you actually want. "Article extraction" is the art of throwing away the 95% and keeping the 5% — plus the structured metadata that describes it (title, author, publish date, lead image, and so on).
newspaper3k popularised a pragmatic pipeline for doing this. This package reproduces that pipeline in idiomatic Go. If you have never seen newspaper3k, here is the whole mental model in four steps:
a := newspaper.NewArticle("https://example.com/story")
a.Download() // 1. fetch the raw HTML over HTTP
a.Parse() // 2. turn HTML into structured fields (title, text, author…)
a.NLP() // 3. (optional) derive keywords + a summary from the text
fmt.Println(a.Text)
The same three verbs — Download, Parse, NLP — are the spine of the original library, and we keep them so prior knowledge transfers directly.
The pipeline, stage by stage ¶
DOWNLOAD (network.go): an HTTP GET with a browser-like User-Agent and a timeout. The only output is the raw HTML string. Kept deliberately separate from parsing so you can also feed in HTML you already have (see Article.SetHTML) without touching the network.
PARSE (article.go + internal/extractors): the raw HTML is loaded into a DOM (we use goquery, Go's jQuery-like wrapper over golang.org/x/net/html). A series of focused "extractors" then each pull one kind of information out of that DOM:
- metadata: title, authors, publish date, meta description/keywords, canonical URL, language, favicon, OpenGraph tags. - content: the main article body. This is the hard part and uses a text-density heuristic (internal/extractors/density.go) or an optional train-free HMM (internal/extractors/hmm.go). - media: the lead ("top") image and embedded videos.
NLP (internal/nlp): with clean article text in hand, we compute keywords (most significant non-stopword terms) and an extractive summary (the few sentences that best represent the whole). This stage is intentionally optional and dependency-light — it is classic frequency analysis, not a neural model.
Why is everything driven by "stopwords"? ¶
Stopwords are the ultra-common words of a language ("the", "is", "and"). newspaper3k uses them as a cheap, language-agnostic signal in two places:
- Extraction: real prose is dense with stopwords; navigation menus and link lists are not. Counting stopwords per DOM node is therefore a surprisingly good proxy for "this node contains a paragraph of an article."
- NLP: keywords are interesting precisely because they are NOT stopwords, so we filter stopwords out before ranking term frequency.
Because the stopword list is per-language, swapping the language swaps the whole behaviour — which is how one extractor handles dozens of languages. See internal/stopwords.
Sources: crawling a whole site, not just one article ¶
Beyond single articles, newspaper3k can point at a news *site* and discover its sections and article links. That lives in source.go (the Source type), built on category detection and RSS/Atom feed parsing.
Package layout (a map for the reader) ¶
newspaper/ (this package — the public API) doc.go — you are here config.go — Config: timeouts, user-agent, language, limits network.go — HTTP fetching article.go — Article: the Download/Parse/NLP orchestration source.go — Source: site-level crawling & feed discovery internal/extractors/ — pure DOM-in, data-out extraction functions internal/stopwords/ — embedded per-language stopword sets + tokenizer internal/nlp/ — keyword & summary algorithms internal/urls/ — URL classification helpers (is this an article?) cmd/newspaper/ — the CLI (urfave/cli subcommands)
The internal/ packages are pure and side-effect free where possible: they take a DOM or a string and return data. All the stateful orchestration lives in the root package. That separation is what makes the library easy to test (feed fixtures, no network) and easy to extend (add an extractor without touching the pipeline).
Index ¶
- func Languages() []string
- func Version() string
- type Article
- type Config
- type ContentExtractor
- type ContentResult
- type Downloader
- type Entity
- type EntityRecognizer
- type ExtractorKind
- type Keyworder
- type MediaExtractor
- type MediaResult
- type Metadata
- type MetadataExtractor
- type Source
- type Summarizer
- type Topic
- type TopicModeler
- type URLClassifier
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Languages ¶
func Languages() []string
Languages returns the ISO-639-1 codes of the stopword sets bundled in the binary. These are the languages extraction and NLP fully support.
func Version ¶
func Version() string
Version returns the library/CLI version, resolved in order of precedence:
- the value injected at build time with -ldflags (release builds);
- the module version from the build info, e.g. when installed with `go install github.com/rangertaha/newspaper/cmd/newspaper@v1.2.3`;
- a "dev" value annotated with the VCS revision when building from source.
Types ¶
type Article ¶
type Article struct {
// URL is the address requested.
URL string `json:"url"`
// Metadata (filled by Parse).
Title string `json:"title"`
Authors []string `json:"authors"`
PublishDate time.Time `json:"publish_date"`
Description string `json:"description"`
MetaKeywords []string `json:"meta_keywords"`
Language string `json:"language"`
CanonicalURL string `json:"canonical_url"`
Favicon string `json:"favicon"`
SiteName string `json:"site_name"`
Tags []string `json:"tags"`
// Body and media (filled by Parse).
Text string `json:"text"`
TopImage string `json:"top_image"`
Images []string `json:"images"`
Movies []string `json:"movies"`
// NLP results (filled by NLP).
Keywords []string `json:"keywords"`
Summary string `json:"summary"`
Entities []Entity `json:"entities"`
// HTML is the downloaded markup, kept for re-parsing but excluded from JSON.
HTML string `json:"-"`
// contains filtered or unexported fields
}
Article is the central type: it represents one web article and walks it through the pipeline. The three stages mirror newspaper3k and are meant to be called in order:
a := newspaper.NewArticle(url) a.Download() // network: URL → raw HTML a.Parse() // HTML → Title, Authors, Text, TopImage, … a.NLP() // Text → Keywords, Summary, Entities
Build() runs all three. For offline use (tests, cached HTML), skip Download and call SetHTML before Parse.
The struct's exported fields are the result of parsing; they are populated as each stage runs. Fields are JSON-tagged so the whole Article serialises cleanly (the raw HTML and internal DOM are excluded).
func NewArticle ¶
NewArticle creates an Article for url using the default configuration.
func NewArticleWithConfig ¶
NewArticleWithConfig creates an Article with a custom configuration. A nil cfg uses the defaults.
func (*Article) Config ¶
Config returns the article's configuration, allowing callers to inspect or adjust it before running stages.
func (*Article) Download ¶
Download fetches the page via the configured Downloader and stores its HTML.
func (*Article) NLP ¶
NLP derives keywords, an extractive summary, and named entities from the parsed text. Call Parse first.
type Config ¶
type Config struct {
// UserAgent is sent on every HTTP request. Many news sites serve different
// (or no) markup to clients that look like bots, so we default to a
// realistic desktop browser string.
UserAgent string
// RequestTimeout bounds a single HTTP fetch end-to-end.
RequestTimeout time.Duration
// MaxBytes caps how much of a response body we read. Article pages are
// small; this protects against accidentally downloading a huge file.
MaxBytes int64
// Headers are extra request headers merged into every fetch.
Headers map[string]string
// IgnoreRobotsTxt disables robots.txt compliance during crawling. It
// defaults to false (we respect robots.txt). Set true only for sites you
// own or are authorised to crawl.
IgnoreRobotsTxt bool
// Language is an ISO-639-1 code ("en", "es", "de", …). It selects the
// stopword set, which in turn drives BOTH content extraction (text-density
// scoring) and NLP (keyword filtering). Empty means "auto-detect from the
// page's lang attribute / meta tags, falling back to English."
Language string
// MinWordCount is the minimum number of words a block of text must have to
// be considered part of the article body. Filters out one-line cruft.
MinWordCount int
// MinSentenceLength (in words) below which a "sentence" is treated as a
// caption/label rather than prose during cleaning.
MinSentenceLength int
// MaxKeywords is how many keywords NLP() keeps.
MaxKeywords int
// SummarySentences is how many sentences the extractive summary keeps.
SummarySentences int
// MaxConcurrency caps parallel downloads when crawling a Source.
MaxConcurrency int
// FetchImages toggles whether Parse() bothers locating the top image.
FetchImages bool
// Extractor selects which built-in body extractor to use when
// ContentExtractor is nil. Defaults to ExtractorDensity.
Extractor ExtractorKind
Downloader Downloader // default: Colly-backed fetcher
ContentExtractor ContentExtractor // default: per Extractor (density/hmm)
MetadataExtractor MetadataExtractor // default: priority-ladder extractor
MediaExtractor MediaExtractor // default: og:image + largest-in-body
Keyworder Keyworder // default: frequency + title bonus
Summarizer Summarizer // default: Luhn-style sentence scoring
EntityRecognizer EntityRecognizer // default: heuristic proper-noun NER
TopicModeler TopicModeler // default: collapsed-Gibbs LDA
URLClassifier URLClassifier // default: URL-shape heuristic
}
Config holds every tunable knob for the download → parse → NLP pipeline.
In newspaper3k this is the `Configuration` object. We bundle the settings in one struct (instead of scattering function arguments) so that an Article and a Source can share identical behaviour, and so callers can tweak one field without re-specifying the rest. Use DefaultConfig() and then override.
func DefaultConfig ¶
func DefaultConfig() *Config
DefaultConfig returns sensible defaults. Copy and tweak:
cfg := newspaper.DefaultConfig() cfg.Language = "es" a := newspaper.NewArticleWithConfig(url, cfg)
func (*Config) LanguageOrDefault ¶
LanguageOrDefault returns the configured language, or "en" when unset. Extraction always needs *some* stopword set to score against.
type ContentExtractor ¶
type ContentExtractor interface {
// Name identifies the strategy (e.g. "density", "hmm").
Name() string
// Extract returns the article body for doc.
Extract(doc *goquery.Document, lang string, cfg *Config) (ContentResult, error)
}
ContentExtractor finds the article body within a parsed document. Two built-ins ship — the newspaper3k-faithful density heuristic and a train-free HMM (see Config.Extractor). Assign Config.ContentExtractor to supply a custom one, e.g. a trained CRF. lang is the resolved ISO-639-1 language code.
type ContentResult ¶
ContentResult is the output of a ContentExtractor: the article body text and, when available, the DOM subtree it was taken from (used to locate the top image within the body).
type Downloader ¶
type Downloader interface {
// Download returns the page HTML and the final URL after redirects.
Download(rawURL string) (html, finalURL string, err error)
}
Downloader fetches raw HTML for a URL. The default is a Colly-backed client (network.go). Override Config.Downloader to read from a cache, local fixtures, or a headless browser.
type EntityRecognizer ¶
EntityRecognizer extracts named entities (people, organizations, places) from the text. The default is a heuristic, train-free recognizer.
type ExtractorKind ¶
type ExtractorKind string
ExtractorKind names a built-in content-extraction strategy.
const ( // ExtractorDensity is the newspaper3k-faithful stopword-density heuristic. ExtractorDensity ExtractorKind = "density" // ExtractorHMM is the train-free HMM extractor (Viterbi over the block // sequence) that adds a contiguity prior the density heuristic lacks. ExtractorHMM ExtractorKind = "hmm" )
type MediaExtractor ¶
type MediaExtractor interface {
Extract(doc *goquery.Document, body *goquery.Selection, pageURL string) MediaResult
}
MediaExtractor finds the lead image and other media. body is the extracted article subtree (may be nil) and lets the extractor prefer in-article images.
type MediaResult ¶
MediaResult holds discovered media URLs (already resolved to absolute form).
type Metadata ¶
type Metadata struct {
Title string
Authors []string
PublishDate time.Time
Description string
MetaKeywords []string // publisher-declared <meta name="keywords">
Language string
Canonical string
Favicon string
SiteName string
Tags []string
}
Metadata is the structured, non-body information about an article.
type MetadataExtractor ¶
MetadataExtractor recovers structured fields from the document. pageURL is the final (post-redirect) URL, used to resolve relative links to absolute ones.
type Source ¶
type Source struct {
// URL is the site's base/home URL.
URL string `json:"url"`
// Discovered during Build (sorted, de-duplicated).
Categories []string `json:"categories"`
Feeds []string `json:"feeds"`
Articles []string `json:"articles"`
// contains filtered or unexported fields
}
Source represents a news *site* (as opposed to a single Article) and discovers what to read on it: its sections, its RSS/Atom feeds, and candidate article URLs. This mirrors newspaper3k's Source / newspaper.build. See docs/sources.md.
Build crawls one level into the site using Colly (which gives concurrency, same-domain scoping, and optional robots.txt compliance), then enriches the article list from any feeds it finds.
func NewSourceWithConfig ¶
NewSourceWithConfig creates a Source with a custom configuration. A nil cfg uses the defaults.
func (*Source) ArticleList ¶
ArticleList returns up to limit discovered article URLs (all of them when limit <= 0).
type Summarizer ¶
Summarizer produces an extractive summary (a selection of the text's own sentences) of at most the requested number of sentences.
type TopicModeler ¶
TopicModeler discovers latent topics across a corpus of documents (LDA). It is a corpus-level operation: a single article carries no topic structure, so this runs over a collection (e.g. a Source crawl).
type URLClassifier ¶
URLClassifier decides whether a discovered link points at an article (vs. a section, tag, or pagination page). Used while crawling a Source.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
extractors
Package extractors holds the pure, DOM-in/data-out functions that recover an article's body, metadata, and media from a parsed page.
|
Package extractors holds the pure, DOM-in/data-out functions that recover an article's body, metadata, and media from a parsed page. |
|
nlp
Package nlp implements the light, train-free natural-language stage of the pipeline: keyword extraction, extractive summarization, and named-entity recognition.
|
Package nlp implements the light, train-free natural-language stage of the pipeline: keyword extraction, extractive summarization, and named-entity recognition. |
|
stopwords
Package stopwords loads the embedded per-language stopword sets and provides the tokenizer and counting primitives that the rest of the library is built on.
|
Package stopwords loads the embedded per-language stopword sets and provides the tokenizer and counting primitives that the rest of the library is built on. |
|
topics
Package topics implements Latent Dirichlet Allocation (LDA) with collapsed Gibbs sampling.
|
Package topics implements Latent Dirichlet Allocation (LDA) with collapsed Gibbs sampling. |
|
urls
Package urls contains small URL utilities shared by extraction and crawling: resolving relative links to absolute, comparing hosts, and the heuristic that decides whether a link points at an article.
|
Package urls contains small URL utilities shared by extraction and crawling: resolving relative links to absolute, comparing hosts, and the heuristic that decides whether a link points at an article. |