Browsertrix Crawler 评测:它归档的是浏览器实际发生的行为,而不是代码写了什么

最后更新于 August 17, 2026
Browsertrix Crawler 评测:它归档的是浏览器实际发生的行为,而不是代码写了什么
AI 摘要
Browsertrix Crawler 是 Webrecorder 的归档型爬虫:一个 Docker 镜像,通过 Puppeteer 驱动真实的 Chromium,记录浏览器抓取到的所有内容,并将其写入 WARC——Web 存档的标准格式——还可以选择打包成带有索引、页面列表和日志的 WACZ 包。它和那些表面上看起来很像的抓取工具,最大的区别就在于用途不同。抓取工具追求的是数据,拿到字段后页面就可以丢掉;归档工具保存的则是一次访问本身——字节、响应头、到达顺序——这样即使网站后来发生变化甚至消失,页面也还能被重新打开。

Browsertrix Crawler 是 Webrecorder 的归档型爬虫:一个 Docker 镜像,通过 Puppeteer 驱动真实的 Chromium,记录浏览器抓取到的所有内容,并将其写入 WARC——Web 存档的标准格式——还可以选择打包成带有索引、页面列表和日志的 WACZ 包。它和那些表面上看起来很像的抓取工具,最大的区别就在于用途不同。抓取工具追求的是数据,拿到字段后页面就可以丢掉;归档工具保存的则是一次访问本身——字节、响应头、到达顺序——这样即使网站后来发生变化甚至消失,页面也还能被重新打开。

Webrecorder 一直维护着这层 Web 基础设施,包括相关格式和回放栈,早在“归档”还不像一个产品类别的时候就已经在做了,而图书馆、新闻编辑室和研究人员至今仍在依赖它。

我在 Docker 中运行了 v1.14.0,并对一个本地测试环境进行验证,该环境包含四类刻意设计不同的端点;同时我也从两侧做了观测:一边是用于归档内容的 WARC 记录,另一边是服务器端的真实请求计数器。真正有用的区分并不只是静态和动态。Browsertrix 捕获到了一个运行时创建的链接和一个页面发出的 fetch(),但它没有请求 JavaScript 函数里两个未被调用的 URL 字面量。

链接到的 app.js 被完整归档了,包括那两个字面路径,但这两个端点都没有产生响应记录、请求记录或服务器命中。因为持有它们的函数根本没有执行。所以这篇文章评估的是 Browsertrix 作为“浏览器会话归档器”的能力,而不是“把源代码里提到的所有 URL 都列出来”的能力。

Browsertrix Crawler 到底是什么

很多人带着“抓取器”的预期来,用完却有些失望。默认流程里不会直接给你一份产品价格 CSV,把它当成抓取工具去期待这种结果,就像指望行车记录仪顺手给你写交通报告一样不现实。它输出的是可回放的浏览会话记录,而后续所有设计都围绕这个目标展开。

我在 2026 年 7 月 27 日测试了 v1.14.0webrecorder/browsertrix-crawler:latest,digest 为 sha256:9d6800a8…,并通过 crawl --version 确认了构建版本。该项目采用 AGPL-3.0 许可。所有测量都在 macOS arm64 上通过 Colima 运行 Docker,在受控的本地测试环境中完成;服务器端计数器提供了不依赖 Browsertrix 日志和归档解析的独立证据。

AGPL-3.0 值得单独说一句:这是带网络使用条款的强 copyleft。若 Browsertrix Crawler 要放进商业产品里,而不是只作为独立工具运行,正式发布前务必让人把许可证看明白。这只是提醒,不是法律意见。

归档记录的是会话,不是源代码

我的测试环境提供了四类端点,刻意分开,是因为归档器会对它们做完全不同的处理:

  • A 类——HTML 里的普通 <a href> 四个页面加一个三级深度链路。地球上任何爬虫都能找到这些。
  • B 类——放在从未执行函数中的 URL 字面量。 两个路径,/api/js-endpoint-7/api/js-endpoint-8,作为字符串静静躺在链接到的 app.js 里一个未调用的 loadData() 中。
  • C 类——运行时生成的链接。 一个 <a href> 由 JavaScript 片段拼接而成('endpoint' + (6 * 7)),随后被挂到 DOM 上。连续路径 /runtime-only/endpoint42 并不存在于任何已服务的字节里。
  • D 类——页面确实发出的 fetch() 路径以同样方式拼接('runtime-xhr-' + (33 * 3)),然后在页面加载时真实请求。

对于 C 类和 D 类,完整路径都没有以连续字符串的形式出现在已服务文件中。因此,它们在服务器端的命中和响应记录,恰好说明这个测试环境里确实执行了运行时构造与请求过程。

哪些被捕获了,哪些没有

Measured results chart: Capture ledger by endpoint class

这里用了两个彼此校验的工具:WARC 响应记录(归档里有什么)和测试环境服务器端的命中计数器(到底请求了什么)。两者在每一项上都一致。

端点类别WARC 中是否有响应记录实际是否被抓取(服务器端)结论
A — HTML <a href>4/44/4已捕获
A — 深度链路(3 层)3/33/3已捕获
B — 未执行 JS 中的 URL 字面量0/20/2未捕获
C — 运行时注入的链接已捕获
D — 运行时 fetch()已捕获

C 类之所以重要,是因为它区分了真正的浏览器和静态爬取。默认的链接提取会读取渲染后的 DOM(根据 common options 文档,即 a[href]->href),所以只有 JavaScript 执行后才出现的链接,仍然会被加入队列、抓取并归档。D 类之所以被捕获,是另一个原因:页面自己发起了请求,而归档器正好位于网络路径上,把经过的流量都记录了下来。

关于 C 类有一个必须说明的边界:我的链接是在页面加载时同步注入的。那些在 Browsertrix behaviors 运行期间才出现的链接,属于另一个场景,而且针对这一点还有一个开放 issue——#723, "Links on pages that are discovered during behaviors are not extracted"。我没有测试那个场景,所以也不会对它下结论。

文件被归档了,端点却没有

要确认 B 类为什么漏掉,不能只看汇总数字,而得逐条查看 WARC 记录。

app.js 确实在归档里——一条响应记录,222 字节的 JavaScript 正文——而且 B 类的两个字面量都原封不动地出现在其中。与此同时,整个文件里没有任何一条记录把 /api/js-endpoint-7/api/js-endpoint-8 作为目标 URI:零响应记录,零请求记录。这两个字面字符串在整个归档里各只出现了一次,而这两次都位于 app.js 被保存的正文中。

这就排除了一个最无聊的解释:"app.js 压根没被抓到。" 归档器保存了引用这些端点的文件,却没有对它们发起请求,因为 loadData() 从未被调用。Browsertrix 默认 behaviors 是开启的——autoplayautofetchautoscrollsiteSpecific——但 autofetch 也没把它们救回来;这很合理,因为只要读一下 autofetch 的说明,你就会发现它抓的是 imgsrcset、样式表和 data-* URL,而不是藏在函数体里的字符串字面量。

为了做一个同场对照,我也运行了 Katana v1.6.1,命令是 katana -u <seed> -jc -silent -nc -d 4。它的原始 discovery summary 在这两个刻意构造的 JavaScript 类别上记录了相反的结果:

你想找的内容Browsertrix v1.14.0Katana v1.6.1,标准 -jc
已服务 HTML 中的链接找到找到
运行时注入到 DOM 的链接找到(通过渲染后 DOM 提取)在没有 headless 模式时会漏掉
页面实际发出的 fetch()找到(作为流量记录)漏掉——因为没有执行
从未执行的 JS 中的 URL 字面量漏掉(0/2)找到(同一测试环境下 2/2)
包含这些字面量的 JS 文件完整归档被解析,但没有保留

两个命令使用的是同一套测试环境和同一批端点名称。这个表并不是在给浏览器爬虫和静态爬虫做泛化排名;它只是说明,端点清单和会话保留需要的是不同的覆盖测试。

“是真浏览器,所以 JavaScript 做的事它都能抓到”——这句你会在很多文章里看到。但这说得过头了。它抓到的是已经执行并产生的流量。代码里如果只是引用了某个 URL,却从未真正调用它,就不会有流量,也就不会有记录。

回放正文都在,但有一件事我没验证

对于两个运行时生成的端点,我把 WARC 里的 HTTP 响应正文取出来确认过,里面就是服务端返回的 JSON:运行时注入链接的目标是 206 字节,运行时 fetch() 的目标是 201 字节。所以它们不是只指向空内容的索引占位符——内容本身就在归档里,而这正是回放系统能够把它们展示出来的前提。

但我没有启动 pywb 或 replayweb.page 去真正渲染这个归档。归档里有正文,与能否正确回放,是两件不同的事;这次测试只覆盖了前者。回放行为、真实性控制、证据链保全以及证据可采性,都需要单独验证。

生产级采集需要更宽的验收测试

这个测试环境回答的是一个很窄的问题:同步运行时链接和页面发出的请求,是否真的变成了网络流量和归档记录?而生产级的保存任务,通常还有很多方式会出错,即便最后仍然生成了一个有效的 WACZ。

先从回放开始。用实际要使用的回放系统打开这个包,把一组固定页面与采集时的参考结果进行对比。检查渲染文本、图片、样式、导航,以及对记录有意义的交互。再看回放浏览器的网络面板,确认有没有缺失的子资源。WARC 里可以有响应正文,但回放仍可能失败,因为重写、索引、时序、源站或依赖项对不上。这篇评测没有跨过这条边界。

动态行为也应该单独准备测试集。这里的 C 类链接是在页面加载时同步出现的;真实应用可能是在定时器、滚动、同意弹窗关闭、路由变化、自定义元素或一长串 API 调用之后才出现内容。把每一种你依赖的行为后面都放一个已知目标,并同时验证服务器命中和归档正文。Browsertrix 默认 behaviors 对这个测试是有用的输入,但它们并不能证明所有延迟状态都真的到达了。尤其是当链接是在 behaviors 期间而不是初始页面执行时出现的,issue #723 就更值得关注。

带认证的采集还会引入会话问题。要确认登录状态进入了浏览器配置文件,能否撑过所需的跳转,并且不会泄漏到本应隔离的采集任务中。要跑通 token 刷新和登出路径。如果归档里包含私密或个人信息,还要把访问控制和保留策略一起纳入同一套验收计划。一次技术上完整的采集,后续也可能被处理得一团糟。

如果服务工作线程、流媒体、WebSocket、下载、跨域 frame、签名 URL 对你的目标很重要,那每一种都应该找一个代表页面测试。这 11 页测试环境并不能说明它们的表现。它也没有说明爬虫在页面保持活动数分钟、在常规稳定窗口之后继续发请求、或者需要用户手势时会怎样。不要把“真实 Chromium”理解成一揽子覆盖承诺;应当明确你要保留哪些浏览器行为,并让每一种都能被观察到。

最后,要保留足够的证据来排查漏抓。保存准确的镜像 digest 和命令、Browsertrix 日志、页面列表、索引、WARC/WACZ 校验和、可获得的服务器端请求证据,以及一份小型的 ground-truth 清单。对于重复采集,还要把时间、配置和环境与产物一起记录下来。这些记录不会自动产生法律可采性,但它们能让技术结论可复现,并能暴露后续差异到底来自目标站点、爬虫还是回放栈。

这个小体积测试环境消耗了多少字节

这个测试环境每页只提供几百字节内容,所以它的开销比例不应该被拿去套到大资源网站上。在这个狭窄范围内,我测的是归档的组成,而不只是最终大小:

WARC 记录类型数量内容字节数占比
request146,91240.6%
response(实际页面内容)135,33931.4%
resource(每页一个 urn:pageinfo: JSON)114,52726.6%
revisit(去重的失效链接)11540.9%
warcinfo1920.5%
记录内容合计4017,024100%

各类型数量和字节总量来自公开的 capture-summary.json;占比以 17,024 字节的记录内容总量为分母。

在这个小体积测试里,请求记录比响应内容还多,而且“请求 + urn:pageinfo:”的字节数大约是响应负载的 2.1 倍。这描述的是这个测试环境的记录构成,不是通用的 WARC 比例。

在磁盘上,经过三次独立运行后:

指标最小值中位数最大值
爬取墙钟时间(秒)28.2229.7530.27
WARC.gz 字节数24,17424,25024,262
WACZ 字节数53,44653,52353,533
已捕获响应负载(字节)5,3395,3395,339

按中位数来算,可以得到四个比例:

推导指标(中位数)数值
压缩后的 WARC / 已捕获响应负载4.5×
WACZ / 已捕获响应负载10×
每页 WARC~2.2 KB
每页 WACZ~4.9 KB

而在 WACZ 包内部:

WACZ 组件在整个包中的占比
WARC45%
CDX 索引16%
爬取日志30%

最后这一行最让我意外。对于这么小的一次爬取,归档包里将近三分之一装的不是网页,而是“爬取过程本身”的记录。

这个测量很稳定:三次运行里响应正文都完全一致(每次都是 5,339 B),而 WARC.gz 和 WACZ 的波动都低于 0.4%。

这些比例不能直接套到带图片、字体和大型脚本包的真实页面上。但结构上的结论成立:请求记录和 page-info 记录会带来与负载大小无关的额外开销。在规划生产存储前,要先拿一批具有代表性的样本做测量;不要拿测试环境里 10× 的比例去简单乘以整个语料库。

安装与应提前预留的磁盘空间

只要 Docker 或 Colima 已经安装并运行,Browsertrix 的安装流程就是 docker pull webrecorder/browsertrix-crawler:latest,然后执行 docker run … crawl --url … --generateWACZ。镜像里自带 Chromium,因此不需要另外准备浏览器或 Python 环境。

而这份便利的代价,在我测到的几次运行里是这样的:

你需要预算的项目实测
镜像下载~1 GB
镜像解压后占用磁盘3.51 GB
在一个提供几 KB 内容的测试环境上,经过若干次 11 页运行后,crawls/ 目录(WARC、WACZ、浏览器配置文件数据)~116 MB
11 页测试环境一次爬取的墙钟时间28–30 秒

容器是摩擦成本的主要来源,而下载和解压这一项,正是把浏览器打包进去的代价。我运行时设置了 --shm-size 1g;因为测试环境在宿主机上,而爬取是在容器里执行的,所以我还需要 --add-host:host.docker.internal:host-gateway,并把测试环境绑定到 0.0.0.0 而不是 loopback。如果你爬的是公网,这一步网络配置可以省掉;但如果你要归档的是自己机器或内部测试主机上的内容,最好预留半天来调这些。

输出目录是最容易被低估的那一项。把这种增长趋势外推到真实爬取任务时,请在开始前就规划好存储,而不是等到凌晨三点磁盘满了才补救。

仅凭这 11 页测试,浏览器启动本身大概率就占了相当一部分 28–30 秒的总时长,但我没有把启动、导航和打包时间拆开。因此,这个运行结果无法推出单页吞吐量结论。

不要拿这个测试环境的比例乱做容量规划

更可靠的容量规划方式是经验测量。选取能够代表目标站点真实分布的页面:轻量应用壳、图片很多的落地页、文档下载、长文章,以及如果范围包括认证内容,还要加上登录后的视图。按预期的 behaviors 和打包设置分别采集每一类。测量响应负载、WARC、WACZ、索引、日志、浏览器配置文件残留,以及运行过程中保留的任何临时工作区。如果打包过程会短暂保留多份副本,峰值磁盘使用量和最终包大小一样重要。

要把固定成本和可变成本分开。3.51 GB 的容器镜像是部署开销,在同一 worker 上可以被很多次采集共享。请求记录、page-info 记录、索引和页面列表会随爬取活动增长。响应正文高度依赖目标站点,而日志则依赖运行时长和日志详细程度。保留和复制又会在爬取行为之外,独立放大最终集合的体积。把这些都混成“每页多少字节”的容量模型,会非常脆弱。

压缩和去重也需要代表性内容。这个测试环境的响应正文在三次运行里完全一致,但这并不代表带变化广告、时间戳、个性化响应或防缓存资产 URL 的页面。若重复采集是项目的一部分,就要测同一批页面的连续采集,并查看 revisit 记录,而不是想当然地认为“看起来没变”的页面一定很好去重。同样,也要测试日志和索引是否以与保存负载相同的复制级别保留。

从运维角度看,最好在采集开始前就设置告警阈值。监控可用空间、每个集合的增长、打包失败,以及浏览器配置文件或临时目录的大小。要做一次从已存 WACZ 恢复的演练,而不仅仅是跑一遍校验和。上面的比例之所以有用,是因为它们揭示了系统里有哪些组成部分;而代表性样本才会告诉你,它们在你的站点上会有多大。

把这些假设写在容量估算旁边,并在试点爬取后重新审视。

通过两个控制项测试范围纪律

会乱跑的归档爬虫是现实中的运维风险——你可能一次性得到法律麻烦和存储账单。我的首页链接到了 http://outofscope.test:<port>/page/out,这是指向同一测试环境的不同主机名,所以带着那个 Host 头的命中,能证明发生了越范围请求,而且与真实互联网流量无关。

配置是否抓取到范围外主机?服务器端命中数
--scopeType prefix(默认)0
--scopeType any2

第二行之所以重要,是因为它让第一行有了意义。在 any 模式下,这个链接被访问了两次,所以它确实可达——默认 prefix 范围下的 0 次,说明的是真正的范围约束,而不是爬虫没看见这个链接。上游还有一个关于其他配置下越范围访问的开放报告,#788,但我没有在这个测试环境的默认 prefix 范围下复现出来。知道它存在就够了;我不会声称自己见到了它。

鲁棒性方面,表现得好得很平常:一个返回 HTTP 500 的路由和一个失效链接都被请求到了,爬取过程干净退出,并生成了有效的 WARC 和 WACZ,失效链接则被保存为去重后的 revisit 记录,没有把流程搞崩。

优点和缺点

优点

  • 能捕获运行时注入的 DOM 链接和页面发出的 fetch() 调用——在归档里和服务器端都已确认,而且这些路径在任何源文件里都不存在字面量。
  • 静态 HTML 和深度遍历都完整:4/4 链接、3/3 深度链路,没有漏项。
  • 在 Docker/Colima 运行起来之后,一条 docker run 就能产出 WARC 和 WACZ;Chromium 已经包含在镜像内。
  • 默认 prefix 范围下没有任何越范围抓取;any 会按文档扩大范围,所以这个开关确实按说明工作。
  • 输出是基于标准的归档(WARC,并打包成带 CDX 索引和页面列表的 WACZ),不是某种私有格式的黑箱。
  • 归档几乎可确定:三次运行的负载字节完全一致,磁盘大小波动低于 0.4%。
  • 失败处理干净:500 路由和坏链接都没有中断爬取。

缺点

  • 未执行的 JavaScript 中的 URL 字面量就是不会被发现(0/2),即使包含它们的文件被完整归档了也一样。如果你的目标是端点发现,这虽然符合设计,但仍然是真实的覆盖缺口。
  • 体积重:镜像拉取约 1 GB,落盘后 3.51 GB,而且输出目录增长很快。
  • 在小页面上字节开销很明显——请求记录加 pageinfo 记录甚至超过了实际负载,WACZ 的约 30% 还是爬取日志。
  • AGPL-3.0 意味着商业嵌入需要认真做合规工作。
  • 它不是结构化数据工具。没有 schema,没有字段映射,最后也不会直接给你整齐的表格行。
  • 每页吞吐量是有意放慢的,因为每一页都得经过真实浏览器。

适合谁,不适合谁

Browsertrix 适合那些需要的不是“提取后的行”,而是“浏览器抓取资源的归档”的团队。在这个测试环境里,运行时抓取到的响应正文已经进入了 WARC,并被打包进 WACZ。图书馆、新闻机构和研究人员都是合理的用户,但如果要进入生产环境,还应该单独测试回放、认证、服务工作线程、同意流程、延迟行为、流媒体资源、保留控制,以及任何证据处理要求。

如果你真正要的是数据,就别用它。若目标是“把这 400 个页面里的每个产品和价格都给我做成表格”,归档器会是一个很绕的路径——你会先归档出几 GB 数据,然后还得自己针对 WARC 文件写提取代码。若你是在摸一个应用的 API 面,也别用它,因为 B 类结果已经很明确地说明:静态 JavaScript 解析器能找到 Browsertrix 根本碰不到的端点。还有,如果你天生排斥 Docker,或者你所在的环境连 3.5 GB 镜像都成问题,那它也不会为你改变。

授权与保留

范围控制并不等于授权。开始爬取之前,就要定义允许访问的主机、保留期限和归档访问权限,尤其当持久化采集可能包含个人数据时。prefix/any 的测试说明的是配置会改变网络可达范围;它并不能说明某一次特定采集在法律上是否允许。

相关阅读:网页抓取与归档的法律影响

按所需输出选择替代方案

按产物来选。Browsertrix 面向的是 WARC/WACZ 保存。像 Playwright 这样的浏览器自动化库能提供可编程页面,但捕获和打包要你自己处理。端点发现型爬虫负责枚举 URL,而提取工具则返回文本或结构化记录。它们可以共享浏览器,却解决的是不同的问题。

相关阅读:Heritrix 评测

披露: Thunderbit 是发布方自家产品,但没有在这个 Browsertrix 测试环境中测试。它属于托管式提取工具,输出的是页面文本或结构化数据,而不是标准化归档。此评测只支持关于输出边界的判断,不构成性能或能力对比结论。

试用 Thunderbit 进行网页数据提取

结论

如果你需要的输出是 WARC/WACZ 归档,而且容器化 Chromium 也符合你的部署方式,那就用 Browsertrix Crawler。在这个测试环境里,归档记录和服务器命中在同步运行时 DOM 与页面发出的 fetch 请求上是一致的,默认 prefix 范围成功排除了第二个主机,失败路由也没有阻止有效归档的生成。

在生产使用前,请验证回放、延迟行为、带认证会话、服务工作线程、代表性页面上的存储构成,以及许可证义务。本次测试覆盖的边界更窄:从未执行的代码里引用的 URL,即使对应脚本已经被保存,也不会为它们产生请求或归档记录。

试用 Thunderbit 进行网页数据提取 Get Started Free

常见问题

这里的 WARC 和 WACZ 有什么区别? WARC 里存的是捕获到的请求、响应以及相关记录。WACZ 则把 WARC 与索引、页面列表、元数据和日志一起打包,方便分发和回放工具使用。本文评测了这两种包,但没有实际渲染回放结果。

应该怎样估算存储空间? 要测代表性页面,并把样本中的完整 WACZ 组成部分都保留下来,包括日志和索引。本文中的比例来自响应正文非常小的特殊测试环境,不适合直接乘以生产环境的 URL 数量。

它会不会跑出我指定的网站? 根据我的测试,默认设置下不会。使用 --scopeType prefix 时,指向不同主机名的链接一次都没被抓取;切换到 --scopeType any 后,该链接被抓取了两次,说明它确实可达,也说明默认设置下的 0 次抓取是真正的范围约束。上游有一个关于其他配置下越范围访问的开放报告,我没有在默认模式下复现,因此还是要检查你自己的范围设置,不要想当然。

如果我要证明回放保真度,必须测试什么? 把 WACZ 加载到你打算使用的回放系统里,把渲染页面、交互和必需的子资源与线上或参考采集结果进行对比。WARC 里有正文是必要条件,但这本身不能证明回放渲染正确。

Browsertrix 会不会把归档页面直接变成结构化表格? 不会。它的输出是归档包,不是筛选好的字段表。如果交付物是产品、价格、联系人或其他 schema,你仍然需要在采集后再做一次提取,或者改用一种以结构化数据为主要输出的工具。

Ke
Ke
Thunderbit 首席技术官 | 高级数据科学家与机器学习专家 Ke Shen 拥有近十年的机器学习和数据科学经验,毕业于哥伦比亚大学,曾任 Walmart Labs 高级数据科学家。他在 Python、R、Java 和统计学方面拥有深厚且备受同行认可的专业能力,并分享如何将复杂的 AI 算法从理论落地到生产级架构的实战经验。
目录
Thunderbit · AI 网页数据代理

一键 内提取任意页面数据

深受 250,000+ 用户信赖
提供免费方案
从网页到表格
描述你的需求——Thunderbit 的 AI 代理会帮你抓取并导出到 Excel、Google Sheets、Airtable 或 Notion。可免费开始。
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week