我机器上跑着四个浏览器抓取后端: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-browser | 145 站 adapter | bing 3.78s / baidu 3.81s / google 6.11s / ddg 7.46s | 各 10 条 | 结构化 JSON |
| wigolo | 自带引擎池(一跳) | 2.6–4.4s | 5–10 条 | 结果内嵌正文 |
| Lightpanda | 自爬 SERP(两跳) | 5.0–5.4s | bing 10 条 | 裸 HTML |
| Chrome | 自爬 SERP(两跳) | 7.9–19.2s | bing 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 innerText | bb snap(可访问性树) | crawl4ai markdown |
|---|---|---|---|
| gov.cn | 1310 字符 / 0.11s | 39102 / 0.19s | 14613 / 0.81s |
| ithome | 15643 / 0.12s | 167648 / 0.45s | 66468 / 0.88s |
| news.qq | 1736 / 0.11s | 70668 / 0.33s | 4391 / 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-browser | 2097 MB(chrome 1980.6 / 16 进程 + node 77.1 + 其它 38.9) |
| wigolo | 3917 MB |
| Lightpanda | 45–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):
| 端口 | 归属 |
|---|---|
| 9222 | bb-browser CDP |
| 9322 | Lightpanda |
| 19824 | bb-browser daemon 控制口 |
| 3333 | wigolo |
改完之后 s lpstat 显示 UP、容器探活也通,我以为完事了。结果回归测试发现 s lp 返回 0 字符,而 s auto 悄悄回退到了 Chrome。
没有任何报错。 就是空结果。
查下来根因:改端口要同步三处硬编码,我漏了一处。
| 文件 | 变量 | 我漏的 |
|---|---|---|
_lp.py | LP_CDP | 已改 |
_c4a.py | LIGHTPANDA_CDP | 漏改,仍指向 9222 |
s | LP_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 只报超时,看不到真实错误:
- 9222 被 Lightpanda 容器占着
- 19824 被上一次残留的 daemon 进程占着
- “找不到 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 默认) |
三条别
- 别自己写 SERP 爬虫 —— 引擎一改版正则就废,跳转链还要反转义 + base64 解码。
- 别只看探活就下结论 —— 端口通了不代表连对了对象,端到端跑一遍才算数。
- 别把标称能力当实际能力 —— 145 个 adapter、README 里的
fetch,实测都有缺口。
收尾
四个后端,一个入口。真正省下的不是机器资源,是我不用再记住什么时候该用哪个。
但更值钱的是这轮排查的副产品:我修正了两个自己的错误结论——内存口径搞错了一个量级,端口改完以为万事大吉。这两个错都不是工具的问题,是我验证得不够。
文档会滞后,探活会说谎,只有端到端跑一遍是可信的。
如果觉得有帮助,点个「赞」和「在看」支持一下 👇