凌晨三点,屏幕右下角的日志还在滚。一个跑了六个小时的采集任务,在两千三百多个请求上停住了,返回的不是 403,也不是 429,而是一张 Cloudflare 的挑战页,那种让你”证明自己是人”的页面。脚本没崩,它只是安静地卡在那儿,像一条被闸门拦住的河。
你把截图丢进群里。三个人的回复几乎同时到。
第一个说,换内核,用 Camoufox,Firefox 的指纹是在 C++ 里写死的,页面上看不到任何 JS 补丁的痕迹。
第二个说,别换框架,装 Patchright,改一行 import 就替换掉你现在的 Playwright,Runtime.enable 那条泄漏它已经堵上了。
第三个说,你这不是浏览器的问题。你要的是一台机器:一台能自己开机、自己登录、自己记住上次干到哪儿的机器。
三个人都很笃定。三个人说的都不是同一件事。
那天晚上你三种都试了。换内核的那条路卡在装二进制上;补丁那条路改完 import 之后页面确实过了,第二天早上又不行了;至于那台机器,你连环境都还没装完,天就亮了。不是谁对谁错,是三个人站的位置不一样高。
这大概就是这类对比文章一直不好用的原因。把 star 数、许可证、编程语言排成一张表,参数是对的,读者看完还是不知道自己该选哪个。因为这三个东西压根不在一个高度上:一个在改浏览器内核,一个在改自动化库的协议行为,还有一个在造一整台给 AI 用的电脑。拿它们横向比”谁更隐身”,就像问锤子、螺丝刀和电钻哪个更好用,得先看你要干什么活。工具的名字会骗人,它所在的位置不会。
那台会自己睡觉的机器
invisible_dots 的仓库很直白,32,129 star,4,831 fork,MIT,TypeScript,2024 年 8 月 4 日建仓,最近一次提交就在昨天(2026-10-17)。README 里把自己定位成 OpenAI Dots 和 Grok Bot 的开源自托管替代品,同时老老实实挂了个 status: alpha。
关键在于它怎么组织运行环境。每一个 Dot 不是一段代码,也不是一个 browser context,而是一台硬件加速的虚拟机:Linux 桌面、独立的持久磁盘、空闲时休眠。你在里面装浏览器、登录账号、留 cookie,关掉再开还在。虚拟机里跑的那个浏览器叫 invisible_playwright_mcp,内核是打过补丁的 Firefox,指纹写在引擎内部,这一点和 Camoufox 的技术路线其实同源,区别是它被包进了一台机器里。每个身份有自己独立的 cookie 和登录态,互不串味。
为什么要做到这个程度?因为身份是会互相污染的。同一个浏览器配置里登过两个账号,cookie、localStorage、时区、甚至字体渲染的细微差异都会把它们连起来。一台 VM 一个身份,等于从操作系统这一层就把它们隔开,代价是每个身份都要吃一份完整的系统开销,省不掉。
再往上是记忆和 skill,可以挂 MCP server,权限分成 allow / ask / deny 三档,有任务队列和定时自动化,入口有 Web UI、CLI、HTTP API、Telegram、WhatsApp。README 里还有一句不起眼的话:kill -9 之后,已经接受的任务不会丢。这句是”整机”和”库”的分水岭:库被杀掉就是被杀掉了,机器被杀掉,重启接着干。
持久磁盘、权限分级、任务队列,单看都不稀奇,合起来才是”机器”的意思。它意味着你可以把一个任务丢进去,关掉笔记本,第二天回来看结果;也意味着它能被当成一个长期存在的同事,而不是一次性的脚本。README 把它和 OpenAI Dots、Grok Bot 放在同一个位置,说的就是这件事:卖的不是一个更难被识破的浏览器,是一个能自己干活的执行体。
代价很具体。Node 24+、Go 1.25+、Git、硬件虚拟化,x86-64,另外还要一个 OpenRouter key。x86-64 这一条就把不少人的 MacBook 挡在门外,Apple Silicon 上得另想办法,找一台 x86 的机器或者云主机。每开一个 Dot 就是一台 VM,内存和磁盘是实打实的开销,虽然空闲会休眠,但同时跑五个身份和跑一个身份是两种体感。
还有 alpha 这个标签。这个量级的 star、开放 issue 只有 4 个,这个比例不太像”没人用”,更像是维护者关得很勤,但从项目自己的标注看,它还没到可以放心托付生产环境的成熟度。上手也不是 pip install 那种事:你得先有一台愿意开虚拟化的机器,再接受”我在维护一套基础设施”这个身份。
实际用起来的曲线大概是这样:装环境那半天最痛苦,之后每加一个身份都要等它开机、等它登录、等它把上一次的状态捡回来;真跑起来反而省心,因为你不必再盯着进程有没有挂。前期重、后期轻,和装一个库的曲线正好相反。
一副从引擎里长出来的皮
Camoufox 是另一种思路:不碰你的运行环境,直接把浏览器内核改了。12,619 star,1,069 fork,MPL-2.0,Python,2024 年 7 月 26 日建仓,最近提交同样是昨天(2026-10-17),开放 issue 58 个。
它做的事说起来就一句:每次启动,生成一套内部自洽的设备身份。注意”自洽”两个字:不是随机编一个 UA、一个分辨率、一个时区,而是从真实设备的分布里采样一整套,让这些值彼此对得上。一个 Windows 11 的 UA 配一份 macOS 的字体列表,是最经典的翻车方式,Camoufox 想消灭的就是这种自相矛盾。
举个具体的例子。屏幕分辨率、devicePixelRatio、可用字体、WebGL 的 vendor 和 renderer、AudioContext 的微小偏差,这些值单独看都正常,凑在一起才构成一个”像真的”的设备。伪造其中一个很容易,难的是让二十个值同时说得通,还要在页面反复读取时保持稳定。Camoufox 把这件事放进了启动流程里。
更关键的是这些值从哪儿报出来。它在 C++ 层就把指纹写进去了,页面拿到的是原生值,不是 JS 在 navigator 上做的 defineProperty 覆盖。这个区别肉眼看不出来,用 CreepJS 这类工具就很容易看出来:JS 覆盖会留下 descriptor 的痕迹,原生值不会。Canvas 和 WebGL 的像素也来自真实的 OS、驱动和 GPU,而不是在 JS 里撒噪声。
这两种做法的差别,在对抗升级的时候会放大。JS 补丁是在跟检测方打补丁战:你覆盖一个属性,对面就查 descriptor、查 toString、查函数原型。C++ 层注入没有这层博弈,因为对页面来说那就是浏览器的原生行为。代价是你必须自己编译、自己跟版本,出了问题也只能读源码。
驱动方式是 Playwright,自动化层对页面不可见,这是它写在明面上的卖点。安装不算复杂:pip install -U "camoufox[geoip]",再 camoufox fetch 把二进制拉下来;Node 侧也有 npm 包,camoufox 加 playwright-core 两个就能用。那个 geoip 的 extra 不是装饰,它负责让时区、语言、经纬度跟出口 IP 对上。这一项对不上,前面所有努力基本白费。很多人在这儿翻车:指纹做得很漂亮,出口 IP 在法兰克福,时区却是洛杉矶,语言还是 en-US。这三条凑在一起,比一个朴素的默认浏览器更可疑。
代价藏在几个地方。它只有 Firefox,有些站点对 Firefox 的待遇和 Chrome 不一样,你的选择器、等待逻辑、上传行为都可能要重调。Firefox 在真实流量里占比不高,一个纯 Firefox 的指纹进到某些以 Chrome 用户为主的站点,本身就是个弱信号,这是判断不是数据,但从反爬的角度想,概率上是成立的。它还跟着 Firefox 的发布节奏走,上游一动,补丁要重新对一遍,这活儿不轻。还有一层它管不到:行为。指纹再真,页面上的鼠标是瞬移的、滚动是整屏跳的、每个请求间隔精确到毫秒,该被拦还是会被拦。Camoufox 解决的是”你看起来像什么设备”,不是”你看起来像不像人在操作”。这两件事经常被混为一谈。二进制包也不小,塞进容器镜像会明显胖一圈。
一把只对一种螺丝有效的螺丝刀
Patchright 是三个里最轻的:不改内核,只改 Playwright 自己。4,897 star,239 fork,Apache-2.0,TypeScript,2023 年 11 月 7 日建仓,最近提交在三天前(2026-10-15),开放 issue 3 个。Python、NodeJS、.NET 三个包都有。
它的定位是 drop-in replacement。原来 from playwright.sync_api import sync_playwright,改成 from patchright.sync_api import sync_playwright,剩下的代码基本不动。这一句话的吸引力,做过迁移的人都懂。但 drop-in 这三个字要打个折。API 层面确实基本兼容,行为层面不是:它关掉了 Console API,页面里的日志就没了;它调整了启动参数,某些依赖默认 flag 的调试工具会失灵;它在协议层做的隔离,也可能让少数依赖 CDP 全量事件的脚本收不到该收的消息。迁移前先跑一遍自己的回归用例,比事后查为什么某个等待超时划算。
它补的是协议层和启动参数层的洞。Runtime.enable 一开,某些检测手段就能顺着摸到自动化的痕迹,Patchright 的做法是把 JS 放到隔离的 ExecutionContext 里执行,绕开这条路径;它也会直接禁用 Console API,这条有效,副作用很直接,页面里的 console.log 不能用了,调试体验会变差;启动参数上,它加上 --disable-blink-features=AutomationControlled,去掉 --enable-automation 之类的默认痕迹;另外还支持 Closed Shadow Roots 里的元素和 XPath,这一条很实用,很多站点的关键按钮就藏在 closed shadow root 里,原生 Playwright 摸不到。
然后是那句要小心读的话。README 说它通过了 Brotector、Cloudflare、Kasada、Akamai、Shape/F5、Datadome、Fingerprint.com、CreepJS、Sannysoft 这些检测。这是项目自己的声称,不是第三方独立验证,而且检测这件事有时间性:今天过的,下个月未必过。把它当成”作者在这个方向上做得比较认真”的证据可以,当成 SLA 不行。这类清单还有个共同的陷阱:它测的是”当时那版浏览器的当时那些检测”,而检测方的规则是按周变的。一个项目能连续通过若干种检测,说明作者盯得紧,不说明你明天拿去跑生产一定没事。
天花板也很清楚。它只支持 Chromium,Firefox 和 WebKit 明确不支持。更根本的是,它改的是自动化痕迹,不是浏览器本身的指纹。Canvas 还是那个 Canvas,GPU 还是那块 GPU,字体还是那堆字体。如果对面查的是 TLS 指纹、是鼠标轨迹、是请求节奏,Patchright 一点忙都帮不上。它是一把很锋利的螺丝刀,但只对那一种螺丝有效。
所以它最适合的位置是”最后一公里”。你已经有了完整的 Playwright 工程,代理、重试、解析、存储都齐了,只差浏览器启动时那点自动化痕迹,这时候换 Patchright 是性价比最高的一步。反过来,如果你的脚本连页面都没打开就被挡了,或者对面根本不看 JS 层,那换它只是换个姿势撞墙。
为什么这张表只能有一张
三个东西讲完,会发现把它们放进同一张表本来就有点勉强,它们不是竞品,是三个不同高度的解法。但选型的时候人还是需要一张表,所以我把它压成一张,重点不在参数,在”层级”那一列。
| 项目 | 所处层级 | 技术路线 | 浏览器支持 | 语言生态 | 许可证 | 上手成本 | 适合谁 |
|---|---|---|---|---|---|---|---|
| invisible_dots | 整机 / 环境层 | 每个身份一台硬件加速 VM,内含打过补丁的 Firefox,外加记忆、权限与任务调度 | 自带 Firefox 内核 | TypeScript 为主,对外提供 Web UI / CLI / HTTP API / Telegram / WhatsApp | MIT | 高:Node 24+、Go 1.25+、x86-64 硬件虚拟化、OpenRouter key,且仍是 alpha | 要长期养多个身份、要 7×24 无人值守跑任务的团队 |
| Camoufox | 内核层 | 改 Firefox 源码,指纹在 C++ 层注入,启动时生成自洽的设备身份 | 仅 Firefox | Python 为主,另有 npm 包配 playwright-core | MPL-2.0 | 中:装包加 fetch 二进制,Firefox 下的自动化逻辑要重调 | 需要高强度指纹伪装、能接受 Firefox 生态的采集与 agent 项目 |
| Patchright | 自动化库层 | 补 Playwright 的协议泄漏与启动参数,不碰内核 | 仅 Chromium | Python / NodeJS / .NET | Apache-2.0 | 低:改一行 import,代价是 console 不可用 | 已有 Playwright 代码、只差最后一层自动化痕迹的团队 |
表里最该看的是第二列。层级决定了你能改什么、不能改什么。Patchright 改不到指纹,Camoufox 改不到调度,invisible_dots 也不负责让你的指纹更真,它只是把内核派的成果装进了一台会自己运转的机器。反过来看也一样:如果只是想让一段脚本多活两天,为它开一台 VM 是杀鸡用牛刀;如果要养二十个身份跑半年,只装一个 Patchright,你迟早得自己写那套调度、存储、权限和重启恢复,等你写完,你手里其实就是另一个 invisible_dots。
判断自己站在哪一层,有个笨办法:看失败发生在什么时候。请求发出去就被拒,多半是 IP 和 TLS 层的事,三个工具都帮不上;页面能打开但立刻跳挑战页,是浏览器指纹层,Camoufox 和 invisible_dots 里的那个内核在管这一段;页面正常渲染、操作到一半被踢,是自动化痕迹和行为层,Patchright 管这一段;任务跑两天断了、登录态丢了、进程挂了没人重启,那是调度层,只有 invisible_dots 管。这个对应关系不精确,但足够帮你排除掉两个错误答案。
真正要比的是三笔账
真到要做决定的时候,比的不是谁更隐身。把三份 README 摊开看,会发现它们各自在回答不同的问题:一个回答“怎么不被认出来”,一个回答“怎么让自动化看起来不像自动化”,还有一个回答“怎么让一个身份活过这个月”。
预算那一栏最容易被低估的不是许可证,三个都是开源许可,一分钱不花。钱花在别处。invisible_dots 要机器,一台能开硬件虚拟化的 x86 主机或者云实例,跑几个身份就是几份内存和磁盘;Camoufox 要人,Firefox 的兼容问题得有人啃,上游一升级就得有人跟;Patchright 要运气,它最便宜,但它的有效性依赖对面没升级检测。
维护成本更隐蔽。Patchright 的维护是”跟着 Playwright 和 Chrome 版本走”,节奏快但活儿碎;Camoufox 的维护是”跟着 Firefox 走”,周期长但每次都是硬仗;invisible_dots 的维护是”跟着一整套系统走”,你得会 VM、会容器、会它那套权限和队列,出问题时排查面比前两个宽得多。一个小团队同时维护三样东西不现实,能维护好一样就不错。
还有一条线不该被跨过去:目标站点的服务条款和 robots.txt。技术上能过 Cloudflare,不等于你有权过。抓公开数据、抓自己有权访问的账号、抓已经授权的内容,和绕过登录墙批量搬运别人的库,是两件事。前者可能只是工程问题,后者是法律问题。反检测工具本身是中性的,用它做什么不是。
所以回到凌晨三点那个卡住的脚本。如果它只是一次性的、几百个页面的活,装个 Patchright,改一行 import,去睡觉。如果它要长期跑、要养身份、要跨月保存登录态,那就别在浏览器上继续加补丁了,去准备一台机器,接受它的重量。Camoufox 站在中间。当你确实需要一副很难被认出来的皮,又还不想为此养一整套基础设施的时候,它是那个最合适的折中。
三样东西都能用,只是别指望其中一个能顺手把另外两个的问题也解决掉。



