四个浏览器爬虫,实测后我分层用

我机器上跑着四个浏览器抓取后端:Chrome、Lightpanda、bb-browser、wigolo。

听着像重复投资。但每装一个都是因为前一个在某件事上不灵——装 Lightpanda 是嫌 Chrome 吃内存,装 bb-browser 是发现 Lightpanda 根本没有登录态,装 wigolo 是想要能标注来源的搜索结果。

装完之后我做了件事:把它们放在同一个页面上同时刻跑一遍,看数据说话。

先说结论

它们不是四个竞品,是四层。

后端唯一不可替代的地方
bb-browser唯一有真实 Chrome 登录态
wigolo唯一自带搜索引擎(不用爬 SERP)
Lightpanda唯一省内存(45–75 MB 级)
Chrome唯一兜底(JS 重站、截图、爬站)

如果只记一句:要登录后的数据用 bb-browser,要带引用编号的搜索用 wigolo,要批量轻量抓取用 Lightpanda,其余全交给 Chrome。

一、搜索:分水岭是有没有自带引擎

这一栏先要分清两类东西,否则比出来的结论是假的:

  • wigolo 自带引擎池,一次请求就返回结果——它是个搜索工具
  • bb-browser / Lightpanda / Chrome 本身没有搜索引擎,只能自己爬 SERP 再解析——它们是浏览器

同一个查询词,实测:

工具本质耗时条数返回形态
bb-browser145 站 adapterbing 3.78s / baidu 3.81s / google 6.11s / ddg 7.46s各 10 条结构化 JSON
wigolo自带引擎池(一跳)2.6–4.4s5–10 条结果内嵌正文
Lightpanda自爬 SERP(两跳)5.0–5.4sbing 10 条裸 HTML
Chrome自爬 SERP(两跳)7.9–19.2sbing 10 条裸 HTML

两个反直觉的发现。

第一,Lightpanda 搜得比 Chrome 快。 同一个 Bing SERP,Lightpanda 6.86 秒拿 10 条,Chrome 要 14.03 秒。虽然 Lightpanda 完全不执行 JS,但 Bing 的结果页在服务端就渲染好了,纯 HTML 解析反而更快。“不能跑 JS” 不等于"抓不到东西"。

第二,DuckDuckGo 谁爬都过不去。 Lightpanda 和 Chrome 抓 DDG 都拿到一张 “Select all squares containing a duck” 的验证页——0 条结果。而 bb-browser 走它的 duckduckgo/search adapter,7.46 秒拿满 10 条。这就是 adapter 的价值:别人已经替你处理过反爬。

但别自己去爬 SERP

我一开始也想把 Bing 爬虫写进脚本,直到发现:Bing 返回的 URL 全是 bing.com/ck/a 跳转链,得先 HTML 反转义、再 base64 解出 u=a1 参数才能拿到真地址。Baidu 是 /link?url=,Google 是 /goto?url=。

引擎改一次版,正则就废一次。 维护成本远超收益,这条路线我放弃了,改用 adapter。

二、抓取:快 4–7 倍,但快不代表好用

同一时刻、同一个页面,三种抓取方式对比:

站点bb eval innerTextbb snap(可访问性树)crawl4ai markdown
gov.cn1310 字符 / 0.11s39102 / 0.19s14613 / 0.81s
ithome15643 / 0.12s167648 / 0.45s66468 / 0.88s
news.qq1736 / 0.11s70668 / 0.33s4391 / 1.15s

bb-browser 快 4–7 倍,因为它根本不用新建页面——直接在你已经开着的标签页里执行 JS。

但这里有个陷阱:eval document.body.innerText 在 JS 重站上严重偏低。gov.cn 只有 1310 字符、news.qq 1736 字符。我一开始以为是抓取失败,逐字核对后发现是真的——这两个页面首屏图多字少,正文是滚动懒加载的。数字小不等于抓错了。

snap(可访问性树)能拿全量(ithome 167648 字符),但吐出来的是树结构噪声,做正文反而要再清洗。要干净 markdown 还得 crawl4ai。

另外两个实测细节:

  • fetch 命令在 bb-browser 0.14.2 里不存在。 README 写了,代码没有。整页正文只能用 snap 或 eval。
  • get text 需要 ref 参数(元素引用),不是给个 URL 就能用。

145 个 adapter 不等于 145 个都能用

bb-browser 标称 145 个站点 adapter。实测边界很清楚:

  • twitter/search → 报 SecurityError: cookie Access is denied,拿不到
  • reddit/search → 相对路径 fetch 直接挂
  • 小红书 search → 正常,20 条

别按标称数量规划工作流,先拿你的目标站点实跑一遍。

三、登录态:这是唯一真正的分水岭

前三个能力,Chrome 配合代码都能补上。登录态补不上。

bb-browser 的机制是复用你真实的 Chrome 用户目录(~/.bb-browser),所以它看到的就是你登录后的页面。实测三个需要登录的场景:

目标结果
微博热榜✓
知乎热榜✓(标签页里能看到「12 封私信」——登录态是真的)
B 站热榜✓

3/3 通过。 这是其他三个工具做不到的——Lightpanda 没有 cookie 存储,wigolo 走的是 HTTP 请求,Chrome 直连要自己写登录脚本。

钥匙孔后的已登录界面:登录态是唯一补不上的能力

四、内存:我撤回一个错误结论

先看数据:

后端实测常驻
bb-browser2097 MB(chrome 1980.6 / 16 进程 + node 77.1 + 其它 38.9)
wigolo3917 MB
Lightpanda45–75 MB(空闲 5.4 MB,工作峰值 75.8 MB)
Chrome 栈505 MB

Lightpanda 和 bb-browser 差了 30 倍。 这就是我装 Lightpanda 的全部理由——批量抓静态页时,Chrome 开一个标签就是几百兆,Lightpanda 一个容器才几十兆。

但这里我要撤回一个自己犯的错。

早先我看 wigolo 占 5.4 GiB,算出"占了本机三分之一",准备写进报告。后来一查:那个 15.39 GiB 根本不是本机物理内存,是 WSL 虚拟机的上限。 本机是 31.54 GiB,wigolo 3917 MB 实际占 12.4%。

更关键的是那 5.4 GiB → 3.9 GiB 的回落:不是内存泄漏,是标签页堆积。 它常驻着 12 个标签没关,清掉就回落了,完全可控。

教训:内存数字先确认口径——是宿主机物理内存,还是容器/WSL 的上限。 差一个量级。

小容器与大机架的体积对比

五、踩坑:端口冲突让一个后端静默失效

这是最值得记的一段,因为它不报错。

我把四个后端接进同一个路由脚本 s,其中 Lightpanda 走 CDP(Chrome DevTools 协议)连容器。跑得好好的,直到 bb-browser 进场——它硬编码 CDP 端口 9222。

于是 Lightpanda 让位,宿主端口从 9222 改到 9322(容器内保持 9222):

端口归属
9222bb-browser CDP
9322Lightpanda
19824bb-browser daemon 控制口
3333wigolo

改完之后 s lpstat 显示 UP、容器探活也通,我以为完事了。结果回归测试发现 s lp 返回 0 字符,而 s auto 悄悄回退到了 Chrome。

没有任何报错。 就是空结果。

查下来根因:改端口要同步三处硬编码,我漏了一处。

文件变量我漏的
_lp.pyLP_CDP已改
_c4a.pyLIGHTPANDA_CDP漏改,仍指向 9222
sLP_CDP_HTTP已改

_c4a.py 那行还写着 ws://127.0.0.1:9222——而 9222 现在是 bb-browser 的 Chrome。它连上了,只是连错了对象。 所以探活全通,抓取全空。

还有个更阴的坑

Lightpanda 的 /json/version 接口会返回一个 webSocketDebuggerUrl 字段。这个字段里写的是容器内的 9222,不是宿主映射的 9322。 照着它抄,你又会连回 bb-browser探活接口返回的地址不一定是能用的地址。

bb-browser daemon 起不来的三个根因

同样排查了很久,因为 daemon start 只报超时,看不到真实错误:

  1. 9222 被 Lightpanda 容器占着
  2. 19824 被上一次残留的 daemon 进程占着
  3. “找不到 Chrome” —— 其实 6016 就是它自己的 Chrome 实例

排查三步:netstat 查端口 → 看 node 进程命令行找残留 daemon → 前台跑 node dist/daemon.js 才能看到真实错误。

六、踩坑汇总

问题原因解法
s lp 返回 0 字符、无报错CDP 端口改了但漏同步一处硬编码三处一起改,改完必须回归
探活通但抓取空连到了同端口上的另一个服务确认端口归属,别只看连通性
daemon 启动只报超时真实错误被吞前台跑 daemon.js
fetch 命令不存在README 超前于实现用 snap 或 eval
twitter adapter 报 cookie 拒绝站点安全策略换站点,别硬刚
DDG 爬不到结果bot 挑战页用 adapter,别自己爬 SERP
内存"占三分之一"把 WSL VM 上限当成了物理内存先确认口径
抓取字符数异常低JS 重站首屏图多字少,真实值核对页面本身,别急着当 bug

贯穿全程的一条:那次"端口改完就好了"的判断,是被回归测试推翻的。如果我只跑探活不跑端到端,这个 bug 会一直静默存在。

七、怎么选

你要干什么用
要登录后的数据(热榜、私信、收藏)bb-browser
要带引用编号、可溯源的搜索结果wigolo
要断网查历史结果(4ms 缓存命中)wigolo
批量抓静态页、省内存Lightpanda
要截图 / 爬整站 / 抽结构化字段crawl4ai + Chrome
JS 重站、复杂交互Chrome
日常查资料anysearch(s 默认)

三条别

  1. 别自己写 SERP 爬虫 —— 引擎一改版正则就废,跳转链还要反转义 + base64 解码。
  2. 别只看探活就下结论 —— 端口通了不代表连对了对象,端到端跑一遍才算数。
  3. 别把标称能力当实际能力 —— 145 个 adapter、README 里的 fetch,实测都有缺口。

收尾

四个后端,一个入口。真正省下的不是机器资源,是我不用再记住什么时候该用哪个。

但更值钱的是这轮排查的副产品:我修正了两个自己的错误结论——内存口径搞错了一个量级,端口改完以为万事大吉。这两个错都不是工具的问题,是我验证得不够。

文档会滞后,探活会说谎,只有端到端跑一遍是可信的。


如果觉得有帮助,点个「赞」和「在看」支持一下 👇

← 返回文章列表