From newspaper3k¶
newspaper3k is a news-article scraper built on requests and lxml. An
Article downloads a URL, then parse() fills article.text, article.title, article.authors,
article.publish_date, article.meta_description and the rest by scoring the lxml tree and running
regex-driven metadata scans. On top of extraction it bundles fetching, per-source article discovery, multi-language
stopword lists, and NLP (nlp() for keywords and a summary). It is widely used for one-shot “give me the body of this
news page” scripts and small crawlers.
turbohtml covers the extraction half of that surface. article() scores the parsed tree and
harvests the same metadata in one C pass over a WHATWG-conformant DOM, returning a typed Article
record. It does not fetch URLs and has no NLP; you bring the markup and turbohtml gives back the content and metadata.
turbohtml vs newspaper3k¶
Dimension |
turbohtml |
newspaper3k |
|---|---|---|
Scope |
Parse plus content and metadata extraction from markup you supply |
Fetch, extract, source discovery, and NLP end to end |
Feature breadth |
Content body, |
The same fields (authors as a list) plus downloading, keywords, and summarization |
Performance |
One C pass over the arena; see the table below |
Builds an |
Typing |
Typed API, |
Untyped; attributes are populated after |
Dependencies |
Self-contained C extension, no Python runtime deps |
|
Maintenance |
Actively maintained |
Original |
Feature overlap¶
The extraction fields map 1:1 onto the Article record from article():
article.text->doc.article().text(or themain_text()shortcut)article.title->doc.article().titlearticle.authors->doc.article().byline(one string, not a list)article.publish_date->doc.article().datearticle.meta_description->doc.article().descriptionarticle.meta_lang->doc.article().langarticle.top_node->doc.article().element(the scored element, orNone)
What turbohtml adds¶
A WHATWG-conformant parser, so malformed markup produces the same tree a browser would rather than lxml’s recovery.
CSS selector and XPath querying over the parsed tree, so you can pull fields newspaper does not expose without a second library.
A typed surface:
Articleis aNamedTuplewith shipped stubs, so field access is checked.No third-party dependency chain to install or pin; the extraction is a single C extension.
What newspaper3k has that turbohtml does not¶
URL downloading and caching. turbohtml takes parsed HTML; fetch the page yourself with
urlliborhttpxand pass the markup toturbohtml.parse().Source-level article discovery (
newspaper.build(url), category and feed detection). No equivalent; drive your own crawl and callarticle()per page.NLP:
article.keywordsandarticle.summaryvianlp(). No equivalent and out of scope; run an NLP library onarticle().textif you need it.authorsas a full list of names.article().bylinekeeps only the first author source as one string; split it yourself if you need the individual names.Top-image and image-set extraction (
article.top_image,article.images). No equivalent; query the scoredelementfor<img>yourself.
Performance¶
Extracting the content body and metadata from a full page – navigation, a scored article, and a footer.
article() scores and harvests in one C pass over the parsed tree; newspaper3k builds an lxml tree
and runs its own regex-driven metadata scan. Numbers vary with input and hardware.
input |
turbohtml |
|
|---|---|---|
post (4 KiB) |
6.88 µs |
2.08 ms (303x) |
longform (16 KiB) |
26.2 µs |
5.85 ms (224x) |
How to migrate¶
Swap the download-then-parse dance for a fetch you own plus one turbohtml.parse() call. newspaper’s Article
combines both; turbohtml only does the parse and extract, so the network call is yours.
newspaper3k |
turbohtml |
|---|---|
|
fetch yourself, then |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
doc = parse(
"<html lang=en><head><title>Comets</title>"
"<meta name=description content='A short guide to comets.'></head>"
"<body><article class=post><h1>Comets</h1>"
"<p>By <a rel=author href='/u'>Ada Lovelace</a></p>"
"<p>A comet is an icy body that releases gas, forming a visible tail, as it nears the Sun.</p>"
"</article></body></html>"
)
art = doc.article()
print(art.title, "|", art.byline, "|", art.description, "|", art.lang)
Comets | Ada Lovelace | A short guide to comets. | en
Gotchas and pitfalls¶
newspaper3k downloads and caches URLs;
article()takes parsed HTML. Fetch the page yourself (urlliborhttpx) and pass the markup toturbohtml.parse().article().bylineis a single whitespace-folded string from the first author source, where newspaper’sarticle.authorsis a list; split it yourself if you need the individual names.article().dateis the harvested string; newspaper’spublish_dateis adatetime. Parse it yourself if you need a date object.A page with no scoring article leaves
elementNoneandtextempty while still filling the metadata, so branch onart.elementrather than assuming a body.newspaper’s keyword extraction, summarization, and other NLP have no turbohtml equivalent and are out of scope.