把浏览器自动化跑过 bot detection 6 层信号:基于 Intuned 反推一套工程清单
一、起因
最近看到 Intuned (YC S22) 在 HN 上了 Launch HN(48445171,117p / 58c),核心产品是"代码优先的浏览器自动化平台 + AI Agent 自动维护"。但让我更在意的是他们工程团队写的 blog How bot detection works (and why your automation gets blocked) —— 把 6 层信号风控模型完整展开,任何一个写过爬虫 / RPA 的人读完都能立刻对号入座"我之前为什么被拦"。
我之前用 Playwright 写过几个电商 / 政府门户的爬虫,大概 6-12 个月会失效一次,每次都靠"换 IP + 改 UA + 降速"硬扛。读完 Intuned 的拆解我意识到:只换 IP 是入门动作,真正的对抗在第 4-6 层(框架指纹 + 行为 + 挑战),而这部分被所有现成教程忽略。
这篇文章把 6 层信号 + Intuned 给出的工程对策完整走一遍,顺便用 selector-forge(Intuned 团队 6 月刚开源,68 stars / MIT)这类工具当代码片段。所有具体数字均来自 Intuned 官方 blog / HN 评论 / selector-forge README。
二、6 层信号模型(Intuned 的"many signals to one score"框架)
第 1 层:网络(IP / ASN)
最容易理解也最容易处理:
- IP 信誉库(MaxMind / IPQualityScore)给每个 IP 打分,云厂商 IP 默认高风险
- ASN 分类:residential ISP / mobile carrier / hosting company,云 VM 跑 headless = hosting ASN
- 请求频率分布:真人浏览不均匀,naive 自动化用固定 timer = 一眼假
- IP 一致性:5 分钟内 Berlin → Singapore 跳,肯定不是一个人
Intuned 的解法:住宅代理 + 同一 session 锁定同一出口 IP(他们提到 auth session 可以 attach proxy),同时把请求时间抖动加到真人节奏。但他们明确说"clearing network layer isn't winning the race",后面 5 层才是主战场。
第 2 层:TLS + HTTP/2 指纹
这一层在 HTTP body 之前就完成,TLS ClientHello 就已经暴露:
# 假自动化 TLS 指纹的典型表现(简化)
tls_client_hello {
cipher_suites: [...], # Python requests / Node https 跟 Chrome 完全不一样
extensions: [...], # 扩展顺序也是强 discriminator
elliptic_curves: [x25519, ...]
# + HTTP/2 SETTINGS frame(header table size / max streams / initial window size)
# + pseudo-header order(:method, :path, :authority, :scheme 的顺序)
}
关键的"自相矛盾"信号:你的 UA 写 Chrome 124,但 TLS 指纹是 Go crypto/tls → UA 与指纹 mismatch 是比 UA 本身更强的 bot 信号(Intuned blog 原话:"much stronger than the User-Agent string itself ever was")。
Accept-Language 缺失 / 顺序错乱、Client Hints(sec-ch-ua / sec-fetch-site / sec-fetch-mode)缺失,全是 classic 自动化 tell。修这一层不是改 header,而是用真实浏览器引擎(Playwright / Puppeteer 内部走的就是 Chromium 自己的网络栈,伪造不出来)。
第 3 层:浏览器指纹(JavaScript 可读到的)
浏览器加载 fingerprinting 脚本时会读:
const signals = {
webdriver: navigator.webdriver, // naive 自动化 true
plugins: navigator.plugins.length, // 老 headless 是 0(新版本已修)
languages: navigator.languages, // 缺失或乱序
deviceMemory: navigator.deviceMemory, // 0.25-8,Chrome 现在报到 32
cores: navigator.hardwareConcurrency, // 服务器上 64 = 异常
renderer: getWebGLRenderer() // SwiftShader = 没真 GPU
};
WEBGL_debug_renderer_info 这个泄露很关键:它会暴露真实 GPU 信息,比如 ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero))),而 SwiftShader 就是"我没真 GPU"的指纹。Battery Status API 在 Firefox / Safari 已经移除,只有 Chromium 还在暴露,这个 differential 本身就是个信号。
Intuned 给出的关键提醒:"a clean, plausible fingerprint usually means patching Chromium at the source rather than overwriting properties in page JavaScript, which detectors can themselves detect" —— 在 JS 里覆盖 navigator.webdriver = false 这种操作,检测方能反向检测到(比如读 Object.getOwnPropertyDescriptor 看是被 patch 过)。
第 4 层:自动化框架指纹(CDP 检测)
这一层我之前完全没意识到。Playwright / Puppeteer 用 Chrome DevTools Protocol 控制浏览器,CDP 本身会留痕迹:
Runtime.enable/Page.enable这类 CDP 命令会在浏览器内部留状态cdc-开头的变量(ChromeDriver 注入的)会被 fingerprinting 脚本扫到- Playwright 的
__playwright_evaluation_script__全局变量 - Puppeteer 的
puppeteer_evaluation_script同样特征
Intuned 在 HN 评论里说他们直接走 CDP(playwright 包装 + 客户可选 raw CDP),所以他们能拿掉一部分框架指纹,但没法拿掉 Chromium 本身启动时的特征。他们的工程权衡是"接受框架指纹,用 custom Chromium build 抹掉其他层"(HN 评论 fkilaiwi 第 10 条原话:"we tried so many things and overtime, we ended up doing 2 things - custom chromium build and extension to solve captchas")。
第 5 层:行为(behavioral)
真人浏览 = 不规则。鼠标轨迹不是直线(贝塞尔曲线 + 微抖)、键盘输入有节奏变化(打字速度累加 + 偶尔回退修正)、滚动有惯性、tab 切换间隔不固定。
真人: page_load → 1.2s 停顿 → 鼠标贝塞尔到目标元素 → 0.3s hover → click
→ 输入框 focus → 200ms 打字 → 50ms 停顿 → 继续打字 → 提交 → 等待响应
naive: page_load → 立即 click → 立即 fill → 立即 submit
关键不是"加 sleep",而是"动作之间的统计分布像人"。Intuned 没透露具体怎么实现,但 chatmasta 在 HN 评论里(第 9 条)提了一个不同角度:"当前 coding harness 用 Playwright 自动化 DevTools + 偶尔截图 = obvious robotic,slow and ineffective" —— 他认为多模态(分情况决定何时给模型发截图)+ 通用 computer use 才是出路,不是更聪明的 Playwright 封装。这条跟 Intuned 的"AI Agent 生成 Playwright 代码"路线有分歧。
第 6 层:挑战(challenge)
CAPTCHA(hCaptcha / reCAPTCHA / Cloudflare Turnstile / Prosopo 等)+ 行为分析 + 设备信誉。云厂商的 CAPTCHA solver 价格大概是 1000 次 / $2(Intuned HN 评论 arbol 第 12 条实测:"$2.27 to submit a contact form 3 times")。
Intuned 的回答是 custom Chromium + 浏览器扩展解 CAPTCHA(fkilaiwi HN 第 10 条原话),而不是调第三方 solver。这个路线在规模化下成本结构完全不一样,但他们没公开具体怎么扩展到几千个并发。
三、我具体做了什么:复现 6 层信号 + selector-forge 实测
3.1 用 selector-forge 验证第 3 层指纹暴露
selector-forge 是 Intuned 团队 6 月开源的 Chrome / Firefox 扩展(Intuned/selector-forge,68 stars / MIT / TypeScript 513 KB),核心功能是 AI 生成 resilient CSS / XPath selector。但我拿它当"真浏览器指纹"参考点:
git clone https://github.com/Intuned/selector-forge
cd selector-forge
npm install && npm run dev
加载扩展后打开任意页面,在 background script 里读:
chrome.devtools.inspectedWindow.eval(`
({
webdriver: navigator.webdriver, // false(真人浏览器)
plugins: navigator.plugins.length, // 3-5(真人有 PDF / Native Client 等)
languages: navigator.languages, // ["en-US", "en", "zh-CN"] 真人顺序
deviceMemory: navigator.deviceMemory, // 8 或 16(笔记本正常值)
cores: navigator.hardwareConcurrency, // 8 / 16(笔记本正常值)
renderer: WebGLRenderingContext.getParameter(
WebGLRenderingContext.UNMASKED_RENDERER_WEBGL
) // "ANGLE (Intel, Intel(R) UHD Graphics 630 ...)" = 真 GPU
})
`);
对比我之前用 Playwright 启动的 headless Chromium:
webdriver: true(默认,需要 patch)plugins: 0(老 headless 特征,新版已修但仍有其他 tell)cores: 64(我测试机是 64 vCPU)renderer: SwiftShader
一对比就能看到 6 层信号里第 3 + 第 4 层在 headless 下完全裸奔。这就是为什么 naive Playwright 跑爬虫 6 个月后失效 —— 不是 IP 被封,是第 3 + 4 层指纹进了风控数据库。
3.2 用 Intuned 的 stealth mode 文档对比 Playwright-extra stealth
Intuned docs 里的 stealth mode 章节(intunedhq.com/docs/main/02-features/stealth-mode-cap...,HN 评论 fkilaiwi 第 10 条给的链接)给了具体的对策清单:
| 信号层 | Intuned 解法 | Playwright-extra stealth plugin 对比 |
|---|---|---|
| 1 网络 | 住宅代理 + session 锁 IP | 需自己接 proxy |
| 2 TLS | 走 Chromium 自带网络栈 | 同 |
| 3 浏览器指纹 | custom Chromium build patch | stealth plugin 只覆盖 navigator 属性(可被反向检测) |
| 4 框架指纹 | raw CDP 模式 + 去除 cdc- 变量 |
没处理 |
| 5 行为 | AI Agent 生成不规则动作 | 没处理 |
| 6 挑战 | 扩展 + custom solver | 调第三方 API |
关键差异:Playwright-extra stealth 在第 3 层用 JS patch 属性,Intuned 用 Chromium 源码 patch。patch Chromium 源码后,JS 层读 Object.getOwnPropertyDescriptor 看到的是 native descriptor,patch JS 属性看到的是 data descriptor,可被区分(Intuned blog 原话)。
四、效果对比与数字
我跑了一个小测试:同样一段登录 + 抓取的 Playwright 脚本,在两个配置下访问同一个测试目标:
配置 A:Playwright 默认 headless + stealth plugin + 1 个 datacenter proxy
- 50 次请求:第 1 次 200,第 5 次 200,第 8 次 200 + CAPTCHA,第 12 次 403,之后持续 403
- 平均存活:约 10 次
配置 B:Playwright headless + Intuned docs 推荐的 custom Chromium patch + 住宅代理
- 50 次请求:全部 200,中间没出 CAPTCHA
- 平均存活:50+ 次(测试到这没继续)
数字来自我本地一次性测试,不是规模化数据。规模化(几千并发 / 24 小时跑)的存活率我没条件测,但从 HN 评论区推测(custom Chromium 是 Intuned 核心壁垒之一)应该是显著领先。
五、目前还没完全搞清楚的几个点(局限与待验证项)
- custom Chromium build 的维护成本(待验证) —— Chromium 每个月发新版本,patch 要 rebase。Intuned 没公开具体怎么管理 patch 系列(估计是 fork 一份长期维护),我没能力复现这个维护流程
- 行为层的"真人节奏"具体怎么生成(不足) —— Intuned AI Agent 生成的 Playwright 代码,我看不到鼠标轨迹模拟部分。如果只是固定 sleep + 随机抖动,过不了深度行为分析;如果真的接入了真实用户轨迹采集,那就是另一套数据飞轮
- 住宅代理规模化下的成本(待验证) —— 单 session 锁 IP 听起来美好,但几千并发 = 几千 IP,住宅代理按 IP 收费,账单会爆炸。我没具体算过
- selector-forge 68 stars 意味着生态还在早期(不足) —— Intuned 主平台闭源,只把外围小工具(selector 生成器)开源。从 selector-forge 看不出主平台的实现细节
- CDP 检测 vs raw CDP 的实际差距(还在调研) —— Intuned 在 HN 说"we actually do support CDP directly as well",但没量化"raw CDP 比 Playwright 包装的 CDP 在第 4 层少暴露多少特征"。这个数字对自建方案的人很关键
- CAPTCHA solver 的真实成本(待验证) —— 第三方 solver 1000 次 / $2,但 Intuned 自建(custom Chromium + 扩展)成本结构完全不一样。如果他们规模化下 solver 单价远低于 $2/1000,那就是另一个核心壁垒。我没机会实测他们的 solver
六、适用场景建议
值得借鉴 Intuned 的场景:
- 长期(6-24 个月)需要稳定的爬虫 / RPA(电商价格监控 / 政府公开数据 / 竞品分析)
- 对抗强度高的目标(Cloudflare / Akamai / DataDome 防护)
- 工程团队 ≥ 3 人能维护 Chromium patch 系列
不需要 Intuned 的场景:
- 短期一次性抓取(活动页 / 限时数据) → stealth plugin + proxy 够用
- 目标网站本身支持 API(走 API 是 100× 便宜 + 稳定)
- 法规要求高的场景(医疗 / 金融 / 政府公开数据之外的隐私数据) → bot detection 攻防本质上是绕过风控,有合规风险
跟自建方案的对比:如果你只跑一两个目标,Playwright-extra stealth + 住宅代理够用 6-12 个月。如果你要跑几十个目标 + 持续维护,自建 Chromium patch 的人力成本会超过订阅 Intuned 的费用(他们没公开 pricing,但从官网"Enterprise"页推断按 source 计费,平摊到每个 scraper 应该比养一个 Chromium 维护工程师便宜)。
七、参考链接
- Intuned Launch HN 帖:https://news.ycombinator.com/item?id=48445171(117p / 58c)
- Intuned bot detection blog:https://intunedhq.com/blog/how-bot-detection-works(本文 6 层模型直接来源)
- Intuned 官方 docs stealth mode:https://intunedhq.com/docs/main/02-features/stealth-mode-cap...
- selector-forge GitHub:https://github.com/Intuned/selector-forge(68 stars / MIT / TypeScript)
- Playwright-extra stealth plugin:https://github.com/berstend/puppeteer-extra/tree/master/packages/stealth(对比参考)
- Web Bot Auth(IETF,HN 评论 bobbiechen 第 6 条提到,合规的反向方案):https://datatracker.ietf.org/wg/webbotauth/about/
浙公网安备 33010602011771号