在这一组带标注、以文章为中心的样本中,newspaper4k 在 全部 22 个样本 上都成功输出结果,找回了 98.65% 的评分文章单元,并且没有包含任何标注为 boilerplate 的标记。就这三个维度来看,它非常贴合这次测试的优先目标;但这并不意味着它就是放之四海而皆准的最佳选择。
在这组样本里,没有任何其他工具能同时达到这三个观察结果。Mozilla Readability 找回了所有评分内容单元,但混入了更多标注 boilerplate;goose3 没有引入任何标注 boilerplate,但有两次返回空字符串。不同的判断标准下,其他库也可能更合适。
在正式部署前,有一个默认抓取行为尤其值得单独留意。
newspaper4k 是什么
newspaper4k 是 newspaper3k 的一个维护分支,而 newspaper3k 本身又是原始 newspaper 的 Python 3 延续。这个传承很重要,因为当你在网上找帮助时,大多数资料讲的都是它的前身,而部分 API 也已经发生了变化。
官方参考:newspaper4k 官方仓库。

这类库最容易用错的地方之一,就是去调用 set_html()。这个方法并不存在。HTML 应该通过 download() 传入:
from newspaper import Article
a = Article(url="https://example.com/story")
a.download(input_html=html) # 不是 set_html()
a.parse()
text = a.text
我第一次运行时就把这一点搞错了,在确认问题是不是出在我自己之前,一度把这个库在 22 个样本上记成了 0 分。事实证明是我搞错了。
它返回的不只是文本。Article 对象还会暴露 text、title、authors、publish_date、top_image、images、movies、meta_description、meta_lang、tags 和 article_html 等字段。keywords 和 summary 则需要额外安装 NLP 相关组件,并完成下文提到的语料配置。这里虽然盘点了字段覆盖面,但没有对元数据准确性做评分。
测试版本:0.9.6,MIT 许可证,1,135 个 GitHub stars,仓库最近一次推送日期为 2026-07-31。这个时间点只代表一个快照,不能直接等同于维护健康状况。Python 3.14.2。
测试结果
| 库 | 文章召回率(共 22 个) | boilerplate 泄漏 | 内容 token 精度 | 污染 token 数 | 输出样本数 |
|---|---|---|---|---|---|
| Readability | 1.0000 | 0.2353 | 0.9109 | 35 | 22/22 |
| trafilatura | 0.9865 | 0.0588 | 0.9411 | 4 | 22/22 |
| newspaper4k | 0.9865 | 0.0000 | 0.9452 | 0 | 22/22 |
| resiliparse | 0.9054 | 0.0588 | 0.9381 | 7 | 22/22 |
| jusText | 0.8378 | 0.4706 | 0.8760 | 74 | 19/22 |
| goose3 | 0.8243 | 0.0000 | 1.0000 | 0 | 20/22 |
sixway-scores.json。每个样本中的每个单元都带有唯一的哨兵 token,因此“找回”和“泄漏”都不是相似度分数,而是精确的子串包含判断。召回率统计覆盖全部 22 个样本;泄漏率和精度则统计同时包含文章内容和 boilerplate 的 11 个样本。
有三列需要分开看。
它回答了每一页。 goose3 和 jusText 没做到这一点——分别只覆盖了 22 个中的 20 个和 19 个。这个差异比表面看起来更重要,因为像这里这样的 precision 和 F1,都建立在“已经输出结果”这个前提上:如果某个库返回空字符串,它既不会拉高也不会拉低比例,因此“拒答”反而是免费的。goose3 的 1.0000 precision 只是在 11 个样本中的 10 个上计算出来的;newspaper4k 的 0.9452 则覆盖了 11 个中的 11 个。这两者并不是完全同一种测量口径。
它没有泄漏任何内容。 这些样本里故意加入了带对抗性的 boilerplate——例如与文章并列出现的中性类促销块、使用看似无害类名的评论线程、以及不会直接写“ad”的广告块。Readability 的 sibling-append 规则吞进去了好几个,而 newspaper4k 一个都没漏。
它在 74 个单元里只漏了 1 个,而且漏掉的还是共享项。
漏掉的是非纯文本样本——这是一页由表格、代码块、短条目和图片说明组成,而不是普通段落;它丢失的单元是 caption。不过它并不是唯一一个在这里出问题的库:
| 库 | 非纯文本页面召回率 | 丢失的单元 |
|---|---|---|
| Readability | 1.000 | — |
| jusText | 1.000 | — |
| trafilatura | 0.875 | caption |
| resiliparse | 0.875 | caption |
| newspaper4k | 0.875 | caption |
| goose3 | 0.250 | 两个表格、代码块、两个短条目、caption |
有三个库都丢掉了同一个 caption,没有其他单元,这更像是它们共享了某种“caption 应该有多重要”的继承性假设,而不是三个独立 bug。如果你的内容是文档、食谱,或者任何 caption 里包含段落外关键信息的页面,那么在正式采用前最好先做验证——Readability 和 jusText 在这点上都保住了它。
同一个样本也是 goose3 完全失手的地方,它丢掉了整页四分之三的内容,因此“非纯文本内容”是一个维度,而这六个库之间在这个维度上的差异,比总览表格看起来要大得多。
在速度方面,newspaper4k 在这 22 个样本上的中位抽取时间是 2.69 ms,是六个库里最慢的,最差一次达到 199.81 ms。对比 resiliparse 的 0.06 ms 中位数,在这次受控测试中差了 45 倍。单页流程里这个中位数也许不算什么,但高负载下的吞吐量和尾延迟并没有测试。冷启动导入时间会在下文单独说明。
第一行我会改掉的默认值

官方参考:newspaper4k 文档。
查看随包提供的 Configuration 对象会发现有 22 个设置。其中一个是:

_honor_robotstxt = False
如果你不特别说明,newspaper4k 默认并不遵守 robots.txt。如果你让它自己去抓取——也就是直接调用 Article(url).download(),而不传 input_html——它会抓取你指定的任何地址,不管站点的 robots 文件怎么写。
对于主要用途是解析你手上已有 HTML 的库来说,这个默认行为在工程上说得通;但如果你在生产环境里把它指向了一千个 URL,之后才发现这一点,那就完全站不住脚了。要么在 Configuration 里把 honor_robotstxt=True 打开,要么像我在这次测试里一样,直接传入 input_html,让自己负责抓取。
还有两个默认值也值得知道:
number_threads = 10。 它的多文章辅助方法默认并发数是 10。并发不等于每秒请求数,但如果你没有为单个主机设置明确限速和调度,它仍然可能制造一波并发请求。
fetch_images = True。 图片抓取默认开启,这会带来离线使用方面的问题。在阻断 socket.connect 的情况下,本次测试的 newspaper4k 0.9.6 路径——对单个已持有 HTML 的输入执行 download(input_html=…) 然后 parse()——成功完成,返回了 1,292 个字符,并尝试了 0 次网络连接。这只能说明这一条明确路径可行,并不能代表所有配置、插件、内容类型或未来版本都同样如此。
其余默认值都比较合理:min_word_count 300,min_sent_count 7,max_text 100,000,http_success_only 为 True,memorize_articles 为 True,follow_meta_refresh 为 False,allow_binary_content 为 False。
安装现实情况
执行 pip install newspaper4k 会拉取 22 个包 和 47.5 MiB 内容,大约耗时六秒。在全新的子进程里进行冷导入:2.812 秒——这是对比中最慢的。
| 库 | 包数量 | site-packages 大小 | 冷导入时间 | 抽取 p50 |
|---|---|---|---|---|
| resiliparse | 5 | 21.0 MiB | 0.015 s | 0.06 ms |
| jusText | 3 | 22.4 MiB | 0.777 s | 0.56 ms |
| goose3 | 16 | 44.3 MiB | 2.181 s | 1.85 ms |
| newspaper4k | 22 | 47.5 MiB | 2.812 s | 2.69 ms |
| trafilatura | 17 | 69.9 MiB | 1.584 s | 0.51 ms |
install-and-import.json。每个库都在独立的空虚拟环境中测试,因此不会继承其他库的依赖。
2.812 秒的导入时间是 resiliparse 15 毫秒的 187 倍。如果你运行的是长生命周期 worker,这个成本只付一次,问题不大;但如果你在 serverless 函数里跑,每次冷启动都要付这笔账,那 newspaper4k 就不是合适的选择,不管它的抽取质量有多好。
安装方面还有一个小瑕疵。导入时会打印警告:
UserWarning: nltk is not installed. Some NLP features will be unavailable. Install it with: pip install 'newspaper4k[nlp]'
本次测试并没有用到这些功能,而且即使没有它们,抽取也完全正常;但基础安装并不等于完整安装,而 newspaper4k[nlp] 会额外引入更重的依赖树以及语料下载。只有在你确实需要关键词和摘要时,才值得为它预留这部分成本。
内存,以及坏 HTML 会把它变成什么样
这批评测里,另有两项在各篇评测中都标为“未测试”的内容,现在也补上了测量结果。
更完整的压力测试背景见:十个库的内存与畸形 HTML 对比。
峰值常驻内存,通过 /usr/bin/time -l 获取,每个单元都在一个全新进程中运行——导入底线代表库在“加载并空闲”时的成本,峰值则包含了文档处理开销。
| 库 | 运行环境 | 导入底线(MiB) | 226 KB HTML 峰值(MiB) | 10 MB HTML 峰值(MiB) |
|---|---|---|---|---|
| html2text | python3.14 | 18.7 | 19.9 | 71.2 |
| pyquery | python3.14 | 30.3 | 33.9 | 172.5 |
| resiliparse | python3.14 | 20.5 | 25.1 | 225.1 |
| markdownify | python3.14 | 23.9 | 28.9 | 278.5 |
| goose3 | python3.14 | 44.1 | 52.4 | 398.5 |
| cheerio | node22 | 66.8 | 76.5 | 398.5 |
| justext | python3.14 | 30.3 | 36.6 | 431.2 |
| newspaper4k | python3.14 | 52.6 | 61.8 | 668.5 |
| trafilatura | python3.14 | 52.5 | 64.8 | 927.1 |
| turndown | node22 | 47.8 | 68.4 | 2947.1 |
memory-results.json。Python 和 Node 的基线不适合直接横向比较;解释器本身就包含在两者之内。
newspaper4k 的导入底线是 52.6 MiB,10 MB HTML 的峰值达到 668.5 MiB——在 Python 库里是第二重的。对于普通网页来说,这两个数字都不算问题;但如果你在内存受限的 worker 里批量处理大文档,它们就很关键了。
畸形 HTML。 这里有 12 个文档,每个都只破坏一件事——例如未闭合标签、嵌套错误的行内元素、带空格却未加引号的属性、多余的闭合标签、完全没有 <html>、重复属性、文档在标签中间被截断、错误实体、未闭合的 <script>、错误的 charset 声明、包含 markup 的注释,以及 600 层嵌套——另外再加上 2 个格式正确但尺寸匹配的对照样本,因为“它什么都没返回”只有在库面对同样大小的正常文档也一样沉默时,才说明它真的受到了 malformed 的影响。
原始结果里,正常对照和畸形样本分得很清楚:
| 分组 | 文档数 | 报错 | 空输出 | 找回的评分哨兵 token |
|---|---|---|---|---|
| 正常且尺寸匹配的对照样本 | 2 | 0 | 0 | 不计入畸形评分 |
| 畸形样本 | 12 | 0 | 10 | 5/33,不含未闭合的<script> 情况 |
那两个对照样本分别输出了 70 和 1,351 个字符,而 12 个畸形输入中有 10 个返回了空字符串。这样就能把“沉默”明确归因于样本的畸形性,而不是单纯输入太短。评分器会在 11 个可计分的畸形文档中检查标题、段落和链接哨兵 token。未闭合的 <script> 样本被排除在外,因为按照 HTML5 解析规则,后续标记会继续被视为 script 内容。见 malformed-results.json。这是一项重要的恢复能力限制,在选型时必须带上,而不只是“没有报错”这么简单。
优缺点
优点。 在这次对比中没有引入任何标注 boilerplate token,22 个受控文章样本全部有输出,文章召回率达到 0.9865。它会暴露文章文本以及元数据字段,不过元数据准确性并未测试。在 socket.connect 被阻断时,测试用的已持有 HTML 路径没有尝试网络连接。检查时仓库最近有过时间明确的推送;但更广义的维护健康度没有评估。
缺点。 这组测试里冷启动导入最慢,达到 2.812 秒,而且 measured 的 site-packages 体积为 22 个包 / 47.5 MiB。honor_robotstxt 默认是 False,多文章辅助方法默认开启 10 线程。基础安装还会提示缺少 NLTK,因此关键词和摘要功能需要更重的可选安装。最关键的是,12 个畸形样本里有 10 个返回空输出,尽管两个格式正确的对照样本都能正常产出文本。
谁适合用,谁不适合用
适合考虑 newspaper4k 的场景:你的优先级是——在受控的文章类语料上产出非空文本、尽量减少该语料中的标注 boilerplate、并且可以接受较慢的冷启动导入。如果按这个明确规则,它在本次样本对比里是领先的。若标准不同,Readability 可能更适合追求最高内容保留率,而 resiliparse 更适合追求启动和中位抽取速度。
建议跳过或先认真做 bake test 的场景:冷启动非常关键、47.5 MiB 的 measured site-packages 体积已经成为问题、或者你很在意畸形 HTML 的恢复能力。这里 resiliparse 的导入速度快了 187 倍,但它在整体质量列上并没有和 trafilatura 完全打平:trafilatura 的文章召回率更高,而它们在泄漏和精度上的表现也不同。newspaper4k 是面向文章的;商品列表和仪表盘并没有测试,所以这里不能对它们做任何结论。
无论如何,只要你让它抓取,就把 honor_robotstxt 打开。 这不是一条性能建议。
托管 API 适合放在哪里
newspaper4k 既可以解析调用方提供的 HTML,也有自己的抓取路径。托管式抽取服务则把获取、渲染和 schema 处理放到供应商边界之后。我们自己在做 Thunderbit,但这次并没有把它放进这组样本里跑,所以这里不能拿它做质量、渲染、反爬、延迟或成本对比。对于已经拿到手的文章 HTML,这里的证据只说明 newspaper4k 本身;非文章目标需要单独评估。
想看这六个抽取器在同一批样本上的表现,可以参考 六库抽取对比。
如果你关注的是托管方案,我们的 网页抓取 API 盘点 提供更大的视角;如果你想看自托管替代方案,可以读 开源爬虫总览。如果最终文本要送进模型,Python 中把 HTML 转成 Markdown 这篇会说明信息在什么环节开始流失。
该不该用 newspaper4k?
如果你已经有 HTML,newspaper4k 是文章文本抽取的强力候选;但在正式采用前,最好先用自己的真实站点语料做一次对比测试。受控样本显示,它的文章召回率很高、没有标注 boilerplate,而且在全部 22 个文章类样本上都能输出非空结果。与此同时,它并不覆盖真实网页或元数据准确性,而且 12 个畸形样本里有 10 个返回了空输出。
如果你会用它的抓取路径,请明确检查 honor_robotstxt=False、10 线程并发,以及按主机设置限速控制。如果冷启动或依赖体积很重要,请把本地 2.812 秒导入时间和 47.5 MiB site-packages 的观察结果放到你的实际部署环境里测,而不要把它们想当然地当成通用容器成本。
试试 Thunderbit 进行网页数据提取 Get Started Free
常见问题
为什么 set_html() 不能用?
因为 newspaper4k 里根本没有这个方法。HTML 应该通过 download(input_html=html) 传入,然后再调用 parse()。搜索结果里可能会出现 newspaper3k 的示例,所以这个错误很容易犯;我第一次跑的时候就犯了,后来在打分前把测试框架修正了。
newspaper4k 会遵守 robots.txt 吗?
默认不会。honor_robotstxt 的出厂值是 False。如果你让库自己抓取,请在 Configuration 里设成 True;或者直接传入 input_html,由你自己负责抓取。多文章任务默认还会使用 10 线程并发。这只是未经你选择的并发度,不是固定请求速率;抓取时请自行设置明确的主机级限速。
parse() 会发起网络请求吗?
在 newspaper4k 0.9.6 上,本次测试的 download(input_html=…) 加 parse() 路径,在 socket.connect 被阻断时,对一个已持有 HTML 的输入没有发起任何连接尝试。这并不能证明所有解析配置、插件、内容类型或未来版本都不会联网。
导入时的 NLTK 警告是什么意思?
基础安装不包含 NLTK,所以关键词提取和摘要功能不可用,库会在导入时明确提示。抽取本身不受影响——这里测到的所有结果都来自基础安装。pip install 'newspaper4k[nlp]' 会把这些功能装上,但也会带来更重的依赖树和语料下载。
这次评测没有测试什么? 没有测试真实世界网页——这里全都是带标注的受控样本。元数据字段虽然有盘点,但没有对标题、作者、日期或图片准确性打分。也没有测试多语言抽取、NLP 扩展、多线程源站抓取,以及高负载下的吞吐量。进程峰值内存只在一个 226 KB 和一个 10 MB 的 HTML 输入上测过,没有并发和持续负载场景。


