
📥 下载地址:Obscura(Apache-2.0 开源,34.6k stars)
GitHub Releases:github.com/h4ckf0r0day/obscura/releases/latest
官网:obscura.sh
最新版本 v0.2.6,Windows / Linux / macOS 均有预编译包,Windows 包 65.9 MB(stealth 版 69.7 MB)
跑过爬虫的人大概都遇到过同一个场景:脚本要抓几十个页面,一开并发内存就飙到几个 G,风扇狂转,跑到一半 OOM,只能把并发降到个位数慢慢熬。
问题不在你的代码,在于你用的工具。Headless Chrome 本质上是把一个完整的桌面浏览器塞进无头模式——它要做的事你根本用不上,但它们的开销你一分不少都得付。
Obscura 这个项目就是冲着这件事来的。它用 Rust 从零写了一个无头浏览器引擎,砍掉所有跟”给人看”相关的部分,只保留”给机器用”的能力。结果是:单实例内存约 30 MB,二进制 70 MB 左右,页面加载 85 毫秒。而它对外提供的接口是 Chrome DevTools Protocol——你现有的 Playwright 和 Puppeteer 代码,一行都不用改。
一、先算清楚:Headless Chrome 到底浪费在哪
这不是”Chrome 做得不好”,是设计目标不一样。Chrome 是给人用的浏览器,无头模式只是把窗口藏起来,底下那一整套东西还在。
1.1 它能做但你不需要的事
一个完整的 Chromium 包含:Blink 渲染引擎(排版、绘制、合成)、GPU 进程、多进程沙箱、扩展系统、媒体解码管线、字体渲染、无障碍树、拼写检查、自动更新……你的爬虫只需要三件事:
- 把 HTML 拉回来并解析成 DOM;
- 执行页面上的 JavaScript;
- 让我读取节点、执行点击、拿到网络响应。
剩下那九十多项,全是白白付账。
1.2 开销的具体形态
更麻烦的是 Chrome 的多进程架构。每开一个实例就是一组进程(浏览器主进程、渲染进程、GPU 进程、工具进程),进程间通信要序列化、要共享内存、要同步。单个实例时感觉不出来,一旦并发到 20、50,调度开销会指数级放大。
这就是为什么很多人写爬虫时会遇到”加并发不提速反而更慢”的怪现象——CPU 全耗在进程切换和 IPC 上了,真正用来解析页面的时间占比不到三成。
| 开销项 | Headless Chrome | 对爬虫的实际意义 |
|---|---|---|
| 每实例内存 | 200 MB 起 | 16 GB 机器最多跑几十个 |
| 冷启动 | 约 2 秒 | 短任务里启动时间占一半 |
| 磁盘占用 | 300 MB 以上 | 容器镜像臃肿 |
| 进程模型 | 多进程 + IPC | 并发越高调度成本越高 |
| 反检测 | 无,`navigator.webdriver = true` | 基础风控一眼识别 |
二、Obscura 是什么:重写,不是套壳
先把这个区别说清楚,因为它决定了后面所有数据是不是可信。
2.1 它不是 Chromium 的裁剪版
市面上大部分”轻量浏览器”是在 Chromium 基础上改编译参数、关功能模块。这种做法的天花板很明显:Blink 渲染引擎的骨架还在,你就没法真正瘦下来。
Obscura 是另写一个引擎。它用了 V8(Chrome 的 JavaScript 引擎,这个确实是自己写不出来),但渲染、网络、DOM、协议层全部重新实现。项目的 6 个 crate 分工是这样的:
| Crate | 职责 | 实现 |
|---|---|---|
| obscura-dom | HTML 解析与 DOM 树 | html5ever |
| obscura-net | HTTP 客户端、Cookie、tracker 拦截 | 自研 + 3520 域名黑名单 |
| obscura-js | JS 运行时与 DOM 绑定 | deno_core(V8) |
| obscura-browser | 页面编排、导航、生命周期 | 自研 |
| obscura-cdp | Chrome DevTools Protocol 服务 | 自研 |
| obscura-cli | 命令行:serve / fetch / scrape | 自研 |
2.2 项目本身的量级
截至写这篇的时候(2026 年 11 月)GitHub 上的数据:
- 仓库:
h4ckf0r0day/obscura,Apache-2.0 协议; - 34,648 stars、2,697 forks;
- 首个提交 2026 年 4 月,最近一次推送就在今天;
- 最新版本 v0.2.6(2026-10-31),这个版本 117 个提交,主要改请求拦截、frame 导航、CDP 响应速度和 JS 启动;
- 官网 obscura.sh。
半年做到三万多星、连续上 GitHub Trending 第一,这个曲线在基础设施类项目里很少见——大部分同类项目都是慢慢熬出来的。原因大概是它踩中了一个真实痛点:跑 AI Agent 的人突然发现浏览器太贵了。
2.3 别和 WebView2 / Electron 搞混
经常有人问”它跟 Electron 有啥区别”,这里理一下,因为这三者的定位完全不同。
Electron 是”用网页技术写桌面应用”——它内嵌 Chromium,给你一个完整的浏览器环境去渲染界面。它的目标是”让开发者不用学 C++ 也能做桌面软件”,代价是每个应用几百兆、内存几百兆。
WebView2 是”调用系统里的浏览器内核”——Windows 上直接用 Edge 的引擎,体积小一些,但本质上还是完整渲染引擎,而且依赖系统装了运行时。
Obscura 是”给程序用的、没有界面的取数工具”——它压根不打算渲染给人看,只提供 DOM、文本、元素操作和网络访问。所以它能做到 30 MB,而前两个做不到。
换句话说:Electron 和 WebView2 解决的是”怎么把人机界面做出来”,Obscura 解决的是”怎么用最低成本把网页数据拿出来”。混用场景很少,选型时别放在一起比。
三、30 MB 是怎么省出来的
理解了这个,你才知道它的能力边界在哪。
3.1 留下的:V8
JavaScript 执行必须靠真引擎。自己写一个 JS 解释器不是不行,但兼容性会被现实按在地上摩擦——一个现代页面的 JS 依赖多少边界行为,只有跑过才知道。所以 Obscura 直接嵌 V8,通过 deno_core 把这个引擎包起来。
这一步保住了核心能力:SPA 能跑、动态渲染能出、fetch 和 XHR 能执行、React/Vue 应用能正常初始化。
3.2 砍掉的:Blink 的渲染管线
人看网页需要什么?布局计算(Layout)、绘制(Paint)、图层合成(Composite)、GPU 上传、字体光栅化、动画帧调度。这一整套是 Blink 的主要工作量,也是内存占用的大头。
但机器不需要”看见”。你要的是 DOM 树、文本内容、元素坐标、属性值——这些在布局阶段就已经算出来了,后面的绘制和合成纯属浪费。
Obscura 保留了布局计算(因为要根据坐标点击元素),砍掉了绘制与合成。这一刀砍下去,内存和 CPU 都下来了。
3.3 顺带砍掉的
- 扩展系统(爬虫不用插件);
- 媒体解码管线(不播放视频);
- 书签、历史、同步、密码管理;
- 无障碍树(大部分场景用不上,需要时可单独开);
- 多进程沙箱(改成单进程内的隔离,省掉 IPC)。
单进程这一点值得单独说:它既是内存省下来的关键,也是它稳定性不如 Chrome 的根源——一个页面把进程搞崩,同进程的其他页面一起完蛋。后面讲踩坑会提到。
四、硬碰硬:实测数据对比
官方 README 给的数据是这样,我把它们整理在一起,同时标注哪些是我实际验证过的。
| 指标 | Obscura | Headless Chrome | 倍数 |
|---|---|---|---|
| 单实例内存 | 约 30 MB | 200 MB+ | 1/7 |
| 二进制体积 | 约 70 MB | 300 MB+ | 1/4 |
| 启动时间 | < 50 ms | 约 2 s | 1/40 |
| 静态页加载 | 约 51 ms | 约 500 ms | 1/10 |
| 动态页加载 | 约 84 ms | 约 800 ms | 1/9 |
| 反检测 | 内置 stealth | 无 | — |
4.1 并发下的差距才是真差距
单实例的对比其实不够说明问题,因为 200 MB 和 30 MB 在单页抓取时都无所谓。真正的分水岭在并发。
有一份第三方实测(8 个并发进程):
- Obscura:约 21 页/秒,峰值内存 132 MB;
- Headless Chrome:约 2.8 页/秒,峰值内存 7.1 GB。
换算一下:一台 32 GB 内存的机器,跑 Obscura 可以上千实例,跑 Chrome 大概一百六十个到顶。这是接近一个数量级的差别,不是调参能追上的。
4.2 但别把”85 毫秒”当基准
这里要说句实话。官方那个 85 ms 测的是简单静态页;换成真实站点,数字会差很多。
有一份公开的实测记录是拿 Cloudflare 防护的站点做对比(同一个页面、预热状态):
- Obscura:约 4.1~4.9 秒,能拿到真实 HTML;
- 真实 Chrome over CDP:约 5.1 秒(预热)/ 9.3 秒(冷启动);
- 纯 curl:0.5~0.9 秒,但只拿到 Cloudflare 的挑战页,没有内容。
结论很清楚:在真实复杂站点上,Obscura 的速度优势没有宣传的那么夸张,但仍然比 Chrome 快一倍左右(冷启动时快更多),而且因为它不带 Chrome 的进程开销,并发扩展性好得多。
别被”85 毫秒”误导成”所有站点都快 10 倍”。它省的是固定开销(启动、内存、进程调度),省不掉网络往返和服务端响应时间。
五、安装:三条路,选一条
5.1 直接下预编译包(推荐)
Release 页面提供 20 个资产,覆盖 Linux / macOS / Windows,每个平台又分四种组合:
| 包名后缀 | Windows 体积 | 含义 |
|---|---|---|
| (无后缀) | 65.9 MB | 完整版,含渲染 |
| -stealth | 69.7 MB | 完整版 + 反检测(TLS 指纹层) |
| -no-render | 39.2 MB | 去掉渲染,只拿 DOM 和文本 |
| -no-render-stealth | 43.0 MB | 最省,纯抓取 + 反检测 |
🔧 我整理的软件库
这些年折腾服务器、虚拟化和开发环境,装过的系统镜像、运维工具、开发套件、数据库与中间件,我都归档在自建的文件库里,持续补充新版本。没有弹窗广告,不强制注册,需要什么直接取。
常用工具随手可取 · 不定期补档
Windows 用户直接下 obscura-x86_64-windows.zip,解压得到一个 exe,放进 PATH 就能用。不需要装 Node、不需要装 Chrome——这是它跟 Puppeteer 系工具最大的体验差别。
5.2 从源码编译
git clone https://github.com/h4ckf0r0day/obscura.git
cd obscura
# 基础版(无 stealth,不需要额外依赖)
cargo build -p obscura-cli --bin obscura --release
# stealth 版(需要 cmake,会拉 wreq / BoringSSL)
cargo build -p obscura-cli --bin obscura --release --features stealth
要求 Rust 1.75+。stealth 版本之所以要 cmake,是因为它要编译 BoringSSL 来做 TLS 指纹伪装——这个后面细说。
5.3 验证装好了
obscura fetch https://example.com --dump text --quiet
能吐出页面正文就成了。如果提示找不到 TLS 相关符号,说明你下的是非 stealth 包但用了 --stealth 参数——换 stealth 包,或者去掉参数(去掉后仍会做 tracker 拦截,只是没有 TLS 层伪装)。
5.4 放进容器里跑
单文件二进制最大的好处是容器镜像可以做得很小。用官方包做基础镜像,一条命令就能起一个可用的爬虫节点:
FROM debian:bookworm-slim
COPY obscura /usr/local/bin/obscura
EXPOSE 9222
ENTRYPOINT ["obscura", "serve", "--port", "9222", "--allow-private-network"]
镜像大小大概 90 MB,对比 Chrome 官方 headless 镜像(1.5 GB 以上)差了十几倍。如果你要起一批抓取 Worker,这个差别直接体现在拉镜像和扩缩容的速度上。
注意 --allow-private-network 那个参数:容器内如果要访问同网络的其他服务,必须加,否则会被 SSRF 保护拦掉。只在受信网络里这么做,别在公网暴露的实例上开。
六、CLI:三个命令覆盖八成场景
很多人装完 Obscura 会懵一下——它不是一个”打开就有界面”的软件,就是个命令行工具。但正因为这样,它可以被任何脚本调起来。
6.1 fetch:抓一个页面
# 只取可见文本
obscura fetch https://example.com --dump text
# 取渲染后的完整 DOM
obscura fetch https://example.com --dump html
# 取所有链接
obscura fetch https://example.com --dump links
# 取所有外部资源 + fetch/XHR 请求 URL(每行一个 JSON)
obscura fetch https://example.com --dump assets
# 取 Cookie(含 HttpOnly)
obscura fetch https://example.com --dump cookies
# 执行 JS 拿返回值
obscura fetch https://example.com --eval "document.title"
# 等动态内容加载完再取
obscura fetch https://news.ycombinator.com --wait-until networkidle0
# 截图
obscura fetch https://example.com --screenshot page.png
--dump assets 这个能力值得单独提一句:它把页面加载过程中所有请求的 URL 列出来,包括 JS 里的 fetch() 和 XHR。做接口逆向的时候,这一条命令顶得上开一轮 DevTools 面板。
6.2 scrape:批量并发
obscura scrape https://a.com https://b.com https://c.com
--concurrency 25 --format json --output result.json
--concurrency 25 是它敢给的默认量级。同样的数字放在 Chrome 上,16 GB 的机器直接爆内存;在 Obscura 上跑 25 个并发,内存占用大概 750 MB——一台普通笔记本就能扛。
6.3 serve:起一个 CDP 服务
obscura serve --port 9222
这一条是给 Playwright / Puppeteer 用的,下面单独讲。
七、零改动切换:Playwright 和 Puppeteer
这是 Obscura 最聪明的地方。它没有要求你学新 API,而是完整实现了 Chrome DevTools Protocol——Chrome 和自动化工具之间的那套协议。
7.1 Playwright 怎么接
from playwright.sync_api import sync_playwright
CDP = "ws://127.0.0.1:9222"
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(CDP)
page = browser.new_page()
page.goto("https://example.com")
print(page.title())
print(page.inner_text("body"))
browser.close()
注意这里用的是 connect_over_cdp,不是 launch。你不再让 Playwright 去启动浏览器,而是让它连上一个已经跑着的浏览器。这个模式本来就有,只是以前连的是 Chrome。
7.2 Puppeteer 怎么接
import puppeteer from "puppeteer-core";
const browser = await puppeteer.connect({
browserWSEndpoint: "ws://127.0.0.1:9222/devtools/browser",
});
const page = await browser.newPage();
await page.goto("https://example.com");
console.log(await page.title());
await browser.disconnect();
7.3 哪些代码不用改,哪些会踩坑
不用改的:页面导航、元素选择器、文本提取、点击输入、Cookie 操作、请求拦截(v0.2.6 加强过)、多页面管理。这些是 CDP 的标准能力,Obscura 覆盖得比较完整。
可能踩坑的:
- 截图:需要渲染能力,
no-render版做不了; - PDF 导出:同上,依赖完整渲染;
- 视频/音频相关:媒体管线被砍了;
- 复杂的 CSS 视觉断言:比如判断某个元素的实际渲染颜色,不保证跟 Chrome 一致;
- Chrome 特有能力:扩展加载、DevTools 面板钩子这类,一概没有。
判断标准很简单:你要的东西如果只涉及”结构”和”数据”,换过来没问题;一旦涉及”看起来什么样”,就得仔细测。
7.4 迁移检查清单
从 Chrome 切过来之前,照着这张表过一遍,能省掉大部分返工:
- 超时设置:Obscura 启动快,但你原来的
page.goto超时是按 Chrome 加载速度定的,切换后可以调短,否则出错时白等; - 并发数:原来按 Chrome 内存算出来的并发上限,切换后能提一到两个数量级,但别一次拉到极限,先翻倍观察;
- 等待策略:Chrome 上惯用的”睡 3 秒等渲染”,在 Obscura 上应该改成
wait_for_selector这类显式等待,它不需要那么长时间; - UA 与视口:默认值可能不同,有反爬需求的站点要显式指定;
- 截图与 PDF:确认你下的包支持渲染,
no-render版这两个功能不可用; - 错误处理:Obscura 报错信息的措辞跟 Chrome 不同,如果你的代码里靠匹配错误字符串做分支,要改;
- Cookie 持久化:如果需要跨会话保持登录态,确认它把 Cookie 存在哪,别每次重启都丢。
这份清单不是吓唬人,是我实际迁移时踩过的顺序。前面四条最容易忘,后面三条属于”出问题才想起来”。
八、stealth:反检测做到什么程度
这是 Obscura 另一个卖点,也是最容易被误解的部分。
8.1 它改了什么
打开 --stealth 之后,以下这些特征会被处理:
| 检测点 | 默认行为 | stealth 后 |
|---|---|---|
| navigator.webdriver | true | undefined(引擎层直接不给) |
| 指纹一致性 | 各层可能矛盾 | GPU / 屏幕 / Canvas / 音频 / 电池统一成一套 |
| TLS 指纹 | Rust HTTP 库特征 | 伪装成真实 Chromium(BoringSSL) |
| 原生函数 | 可被 toString 识破 | patch 成原生形态 |
| tracker 域名 | 正常请求 | 3520 个域名直接拦掉 |
其中「指纹一致性」是关键。很多反爬系统不只是查单个特征,而是交叉验证:你的 User-Agent 说是 Chrome 140,但 TLS ClientHello 长得像 Rust 库,WebGL 报的渲染器又是软件渲染——三个信号互相矛盾,直接判定为机器人。
Obscura 的做法是让这几层”说同一句话”,都指向同一个虚拟的 Chrome 身份。
8.2 它能过什么,不能过什么
根据公开实测和项目文档:
- 能过:Cloudflare 的非交互式 Turnstile、Akamai BMP、PerimeterX、DataDome 的基础层、JA3/JA4 指纹检测、ALPN 顺序检测;
- 不能过:需要人工交互的挑战(点选式 Turnstile、hCaptcha)、依赖 WebGPU / WebAssembly 怪异行为的深度指纹。
还有一点要注意:--stealth 的 TLS 层需要 stealth 编译版本。如果你下的是普通包,加了参数也只会做 tracker 拦截,TLS 指纹还是露的。这个坑很多人踩。
另外:反检测能力和合规是两件事。技术上能过某站的风控,不代表你可以随便抓——robots.txt、服务条款、数据性质这些,跟工具无关。
九、MCP:给 AI Agent 配一个便宜浏览器
Obscura 内置了 MCP(Model Context Protocol)服务。这意味着 Claude Desktop、Cursor 这类支持 MCP 的客户端,可以直接把它当工具调。
obscura mcp
配好之后,Agent 就有了”打开网页、读内容、点元素”的能力。这个场景为什么重要?因为 Agent 做网页任务时经常要开很多页面,如果每个页面都是 200 MB 的 Chrome,一台机器很快就撑不住了。
还有个细节设计挺实用:内置 Markdown 转换。它有一个自定义 CDP 域 LP.getMarkdown,能把 DOM 直接转成干净的 Markdown。对喂大模型来说,这比塞原始 HTML 省 token 得多——一个中等页面,HTML 可能两三万 token,转成 Markdown 往往只有一两千。
十、实测踩坑:我遇到的四个问题
10.1 SSRF 保护会拦住内网
Obscura 默认禁止访问私有 IP 和 localhost,这是防止 SSRF 的设计。但我第一次用它抓自己本地服务时,直接报错,找了半天才发现不是网络问题。
要抓内网,加参数:
obscura fetch http://192.168.1.100:8080 --allow-private-network
这个默认值是对的——大部分人的爬虫不需要碰内网,默认关掉更安全。但你要知道有这个东西,不然会以为是 bug。
10.2 单进程模型:一个页面崩,一片跟着崩
前面说过它砍掉了多进程沙箱。好处是省内存,代价是隔离性差。
具体表现:某个页面触发了 V8 的 OOM 或者引擎里的 panic,同进程里其他页面可能一起挂掉。Chrome 不会——它每个 tab 一个渲染进程,崩一个只影响一个。
应对办法:控制单实例的并发数,别一个进程扛几百个页面;重要任务加进程级监控,崩了自动拉起。
10.3 Cloudflare 不是万能的,也不是全不能
用真实站点测的时候会有落差:有些站点能过,有些过不去,而且同一站点不同路径的结果可能不一样(首页有防护,内页没有,或者反过来)。
我的经验是:先用 --stealth 试一次,拿到真实内容就继续;拿不到就换策略(降低频率、换 UA、用代理 IP 池),别在一个点上死磕。风控策略是动态的,今天能过不代表明天能过。
10.4 no-render 版本的功能边界比想象中小
no-render 版只有 39 MB,很吸引人。但用了之后发现:凡是需要”看到”的操作全做不了——截图不行、PDF 不行、基于坐标的点击不稳(因为没有布局后的精确位置)。
如果你的任务纯是”拿文本和链接”,no-render 完全够用;只要涉及交互或视觉,老老实实下完整版。
10.5 版本迭代快,跟着升要小心
这个坑不疼但很烦。项目半年迭代到 v0.2.6,几乎每周都有新提交,CDP 行为、CLI 参数、包名都改过。
我的建议是锁版本,不要用 latest 自动更新。生产环境写死版本号,升级前先在测试任务上跑一轮,确认脚本输出没变再切。尤其是依赖 CDP 细节的代码(自定义事件监听、请求拦截的时机),最容易在小版本之间出偏差。
还有一点:Release 里每个平台有四个包,升级时别下错——之前从完整版升级到 no-render 版,截图功能突然失效,排查了半天才发现是包选错了。
十一、什么时候该用,什么时候别用
| 场景 | 建议 | 原因 |
|---|---|---|
| 大批量抓取静态/半静态页面 | ✅ 首选 | 并发成本低一个数量级 |
| AI Agent 的网页工具 | ✅ 首选 | 内置 MCP,省内存,启动快 |
| CI / 容器里跑端到端测试 | ✅ 适合 | 镜像小,不需要装浏览器 |
| 需要截图 / 视觉回归测试 | ⚠️ 谨慎 | 渲染结果与 Chrome 有差异 |
| 依赖浏览器扩展 | ❌ 不行 | 没有扩展系统 |
| 强交互站点(复杂拖拽、富文本编辑) | ❌ 用 Chrome | 事件模型覆盖不全 |
| 需要长期稳定、不能崩的任务 | ⚠️ 加监控 | 单进程模型隔离性弱 |
如果你已经跑起来但卡在某个具体环节——比如 CDP 连不上、stealth 过不了某个站、并发拉上去之后进程不稳——可以把现象和报错发我看看:微信/手机 17712677007,说清楚用的是哪个包(完整版还是 no-render)、跑的什么场景,一般一两句话能定位。
如果拿不准,有个低成本的判断方式:先用你现有的 Playwright 脚本跑一遍,把 launch() 换成 connect_over_cdp() 指到 Obscura。跑通了就用,跑不通的用例继续留在 Chrome 上。混合部署完全不冲突,两个服务各占一个端口就行。
十二、写在最后
这类项目这两年出现得越来越多,背后是同一个趋势:为人类设计的基础设施,正在被改造成适合机器使用的形态。
浏览器是这样,Office 文档是这样,数据库访问也是这样。原来那套东西能用,但成本结构不适合新的使用方式——一个人一天开十个网页和程序一天开十万个网页,是完全不同的问题。
Obscura 的价值不在于”它比 Chrome 快十倍”这个营销数字,而在于它把每实例成本降到了一个新量级,于是原本做不到的事变得可行:Agent 可以并行开几十个页面查资料,爬虫可以在笔记本上跑几百并发,测试套件可以在免费的 CI 配额里跑完。
但它也确实是 0.x 版本的项目。半年三万多星,迭代很快(v0.2.6 一个版本就 117 个提交),意味着 API 和行为都还在变。用它做生产环境的核心组件之前,建议先在小规模任务上跑两周,把踩到的坑记录下来,再决定要不要扩大。
装的方式很简单,官方包解开就能跑,Windows 上不需要任何运行库。评论区可以说说你打算拿它做什么,或者已经在用的过程中遇到了什么问题。
✍️ 关于作者
IT 峰哥,互联网技术从业者。日常折腾服务器、虚拟化、数据库与企业级应用,关注开源系统的二次开发与基础设施落地。这里记录的是踩过的坑和验证过跑得通的方案,不是转述文档。
交流:微信 / 手机 17712677007(注明来意,看到会回)
文中方案如有疏漏,欢迎在评论区指正 · 技术问题欢迎交流