AI Agent 网页内容提取实测:三种方案的 Token 成本差了 3 倍

上周用 AI 批量写技术文章,跑完一看账单——token 用量比预期多了两倍。排查下来,问题不在模型推理,而是每次抓网页喂给 AI 的内容太脏了。导航栏、侧边栏、页脚、推荐列表全塞进去,真正有用的正文可能只占 30%。

这让我开始认真对比市面上几种网页内容提取方案。拿同一篇 Substack 文章做横向测试,结果差别大到值得专门写一篇。

问题出在哪:70% 的 token 在喂垃圾

AI 内容创作的典型流程是:找参考文章 → 抓全文 → AI 消化后写稿。一篇普通技术博客,抓下来轻松 8000 到 15000 token。如果一篇文章要参考 3-5 个信息源,光"读"这个动作就烧掉几万 token。

更关键的是,大部分抓取工具返回的是整个页面的内容。HTML 转 Markdown 之后,导航菜单、广告、"相关推荐"这些噪音全混在正文里。AI 模型不会自动过滤这些——它会老老实实地"阅读"每一个 token,包括那些"点击订阅"和"关注我们"。

所以优化的核心不是压缩正文,而是在喂给 AI 之前把噪音干掉。

实测对比:同一篇文章,三种提取方式

测试素材是一篇 Substack 文章,统一限制 30000 字符,对比三种方案的输出质量。

Jina Reader:干净,但有天花板

Jina 是专门做网页内容提取的服务,用法很简单——在原始 URL 前面加 https://r.jina.ai/ 前缀就行:

https://r.jina.ai/https://原始文章URL

它会自动渲染页面、识别正文区域、去掉导航和广告,返回格式干净的 Markdown。标题层级、链接、图片、列表全保留,速度大概 1.4 秒。

问题是每天免费限额 200 次。听起来不少,但如果你在批量跑内容生产流水线,两三天就能用完。超了要么等第二天,要么付费。

web_fetch:只能对付静态页面

直接用 web_fetch 抓同一篇 Substack 文章,结果直接报错——fetch failed。Substack 有反爬机制,请求被拦截了。

Medium、部分付费博客、微信公众号,同样的问题。即使是能抓到的页面(比如 GitHub README、普通技术博客),返回的也是全页 HTML 转 Markdown,噪音多,token 浪费严重。

结论:只适合没有反爬的静态页面,覆盖面太窄。

Scrapling + html2text:效果对标 Jina,没有限额

Scrapling 是一个开源 Python 爬虫框架,定位是"为现代 Web 设计的自适应爬虫"。三个核心能力:

  • 内置反反爬:StealthyFetcher 能绕过 Cloudflare Turnstile 等主流防护,不需要额外配置
  • 自适应选择器:网站改版导致 CSS selector 失效时,能自动重新定位元素
  • 零配置启动:pip install scrapling,没有浏览器驱动的依赖地狱

抓取逻辑分四步:用 Fetcher.get() 拿 HTML → 按优先级尝试正文选择器(articlemain.post-content[class*="body"])→ 用 html2text 转 Markdown → 截断到指定字符数。

实测输出和 Jina 几乎一样干净,标题层级、链接、图片 URL、列表格式全保留。速度约 3 秒,比 Jina 慢一倍,但没有调用次数限制,不需要 API Key。

一个关键细节:Scrapling 必须配合 html2text

这个坑值得单独说。一开始我直接用 Scrapling 的 get_all_text() 方法提取文本,以为能省一步。结果拿到的是纯文字流——段落消失,链接消失,图片消失,标题层级消失。

对 AI 写稿来说,链接和图片 URL 都是有价值的素材。引用图片、追溯信息源都要用。纯文本等于丢了一半信息。

正确做法是先拿 html_content,再用 html2text 转换:

import html2text

h = html2text.HTML2Text()
h.ignore_links = False
h.ignore_images = False
h.body_width = 0  # 不自动折行
md = h.handle(element.html_content)

body_width = 0 这个参数容易漏掉。默认值是 78,会在 78 个字符处强制换行,导致代码块和长链接被截断。设成 0 就是不折行,输出更干净。

加上这一步,Scrapling 的输出质量就和 Jina 对齐了。

微信公众号:Scrapling 的差异化优势

测试微信公众号链接(mp.weixin.qq.com)时,出现了有意思的分化:

方案微信公众号原因
Jina Reader403 拦截,内容为空微信专门的反爬策略
web_fetch请求被中断同上
Scrapling完整拿到正文 + 图片链接StealthyFetcher 绕过了防护

这个发现的实际意义很大。之前读公众号文章要么靠搜索引擎拿摘要(信息不全),要么靠浏览器自动化渲染(慢且复杂)。现在一行命令就能拿到完整的 Markdown 格式正文。

如果你的 AI 工作流经常需要处理中文内容源,微信公众号是绕不开的渠道。光这一条,Scrapling 就值得装上。

分级策略:不同场景用不同方案

实测完之后,我确定了这套分级路由:

优先级方案适用场景限制
1Jina Reader英文博客、Substack、Medium200 次/天
2Scrapling + html2textJina 超限、微信公众号、有反爬的平台
3web_fetch静态页面、GitHub、技术文档全页噪音多
4浏览器自动化需要登录态、极端反爬场景最慢

两个实操建议:

域名路由可以做成自动的。比如检测到 mp.weixin.qq.com 直接走 Scrapling,跳过 Jina,不浪费免费配额。

maxChars 统一设 30000。这个值既能保证大部分文章的正文完整,又不会把 context window 撑爆。实测下来,一篇 3000 字的中文文章转 Markdown 大概 8000-12000 字符,30000 的上限留了足够余量。

实际省了多少 Token

拿我自己的内容生产流程算一笔账。之前用 web_fetch 抓一篇文章平均 12000 token(含噪音),换成 Scrapling + html2text 之后平均 4000 token(纯正文)。每篇文章参考 4 个信息源,一篇稿子的"阅读成本"从 48000 token 降到 16000 token。

一个月产出 20 篇,光抓取环节就省了 64 万 token。按 Claude 的定价算,这不是小数目。

而且更干净的输入意味着更好的输出质量。AI 不用在噪音里"找"正文了,生成的内容相关性和准确性都有提升。这个收益比省 token 更值。

落地检查清单

如果你也想优化 AI 工作流的网页抓取环节,按这个顺序来:

  1. pip install scrapling html2text,先把工具装上
  2. 写一个提取函数,核心就是前面那段 html2text 配置代码
  3. 按域名做路由:微信走 Scrapling,英文博客优先 Jina,静态页面用 web_fetch
  4. maxChars 设 30000,别让单次抓取撑爆 context
  5. 跑几篇文章对比一下 token 用量,你会看到明显的差异

网页内容提取这个环节看起来不起眼,但它是 AI 内容工作流的入口。入口的质量决定了后面每一步的效率。把这一层做干净,整条链路都会受益。