本文从浏览器自动化的底层原理出发,梳理 WebDriver Classic、CDP、WebDriver BiDi 三代协议的演进脉络,对比主流自动化框架的技术差异,并深入分析各方案的反检测特征与局限性。
一、浏览器自动化的底层基础
在聊协议之前,先搞清楚浏览器到底是什么。
每个浏览器内核由两个核心引擎组成:
| 浏览器 | JS 引擎 | 渲染引擎 |
|---|---|---|
| Chromium (Chrome/Edge) | V8 | Blink |
| Firefox | SpiderMonkey | Gecko |
| WebKit (Safari) | JavaScriptCore | WebCore |
所有浏览器自动化框架的本质,就是把外部指令传递给这两个引擎去执行。 JS 引擎负责执行脚本逻辑,渲染引擎负责页面布局、样式计算、DOM 操作等。
区别只在于:指令怎么传进去?
二、三代通信协议的演进
2.1 第一代:WebDriver Classic — HTTP 单向通信
这是 Selenium 采用的方式,也是最早被 W3C 标准化的浏览器自动化协议。
通信链路:
你的代码 → HTTP 请求 → WebDriver 进程(chromedriver/geckodriver) → 浏览器内部接口 → 引擎
每个浏览器厂商都需要开发一个独立的 WebDriver 进程作为中间适配层:
- chromedriver — Google 开发,适配 Chromium
- geckodriver — Mozilla 开发,适配 Firefox
- safaridriver — Apple 开发,适配 Safari
这些 driver 的作用就是:接收标准化的 HTTP 指令,翻译成各自浏览器能理解的内部调用。
优点: 跨浏览器通用,W3C 标准。
缺点:
- HTTP 是请求-响应模式,只能单向通信——你发指令,浏览器回结果,浏览器不能主动通知你
- 需要额外下载和管理 driver 进程
- 速度相对慢(每个操作都是一次完整的 HTTP 请求-响应)
2.2 第二代:CDP — WebSocket 双向通信
CDP(Chrome DevTools Protocol)是 Google 为 Chromium 设计的私有调试协议。你按 F12 打开的 DevTools 面板,底层就是通过 CDP 和浏览器通信的。
Playwright 和 Puppeteer 都直接使用 CDP 协议。
通信链路:
你的代码 → WebSocket → CDP 协议 → Chromium → V8 + Blink
这里要澄清一个常见的混淆:WebSocket 和 CDP 不是二选一的关系,而是两个层面的东西。
- WebSocket — 传输通道(怎么传),类比 TCP
- CDP — 协议内容(传什么),类比 HTTP
CDP 跑在 WebSocket 上,就像 HTTP 跑在 TCP 上一样。所以"Playwright 通过 WebSocket 通信"和"Playwright 用 CDP 协议"说的是同一件事的两个层面。
优点:
- 双向实时通信——浏览器可以主动推送事件给你(比如页面加载完成、网络请求发生)
- 没有中间 driver 进程,直连浏览器
- 速度快
缺点:
- CDP 是 Google 的私有协议,只有 Chromium 系浏览器原生支持
- Firefox 和 WebKit 不原生支持 CDP
- Playwright 为了支持 Firefox 做了大量 hack 适配
2.3 第三代:WebDriver BiDi — 统一的双向标准
这就是本文的重点。
核心矛盾:
WebDriver Classic (HTTP) → 跨浏览器通用,但只能单向通信
CDP (WebSocket) → 双向实时,但只有 Chromium 支持
既要双向实时,又要跨浏览器通用——这就是 WebDriver BiDi 要解决的问题。
BiDi 不是某个人或某家公司发明的,而是 Google、Mozilla、Apple 等浏览器厂商在 W3C 框架下共同推进的新标准。官方全名叫 WebDriver BiDi,本质上是 W3C WebDriver 标准的 2.0 演进版本。
通信链路:
你的代码 → WebSocket → BiDi 协议 → 浏览器内置的 BiDi 模块 → 翻译成内部私有协议 → 引擎
关键架构变化:BiDi 的适配层是内置在浏览器里的,不是一个外部独立进程。
Selenium 方式:
代码 → HTTP → chromedriver(独立进程) → 浏览器
需要下载和管理 driver 进程
BiDi 方式:
代码 → WebSocket → 直连浏览器(内置 BiDi 实现) → 引擎
不需要额外的 driver 进程
2.4 三代协议总结
| 特性 | WebDriver Classic | CDP | WebDriver BiDi |
|---|---|---|---|
| 归属 | W3C 标准 | Google 私有 | W3C 标准 |
| 通信方式 | HTTP 单向 | WebSocket 双向 | WebSocket 双向 |
| 中间进程 | 需要外部 driver | 不需要 | 不需要 |
| 浏览器支持 | 所有浏览器 | 仅 Chromium | 所有浏览器(逐步实现中) |
| 速度 | 慢 | 快 | 快 |
三、各浏览器的私有调试协议
一个容易被忽略的事实是:每个浏览器都有自己的调试协议,不只是 Chromium 有。
Chromium → CDP (Chrome DevTools Protocol) → 公开、文档完善、生态庞大
Firefox → RDP (Remote Debug Protocol) → 存在,但文档少、生态小
WebKit → Web Inspector Protocol → 基本只给 Safari 自己用
所以不是"其他浏览器没有双向通信能力",而是各搞各的,协议格式完全不兼容。CDP 因为 Chrome 的市场份额和完善的文档,成了事实标准,但其他厂商并不愿意实现 Google 的私有协议——这既是政治问题(不想把控制权交给 Google),也是技术问题(CDP 是为 Chromium 架构设计的,和 Firefox/WebKit 架构不匹配)。
BiDi 的本质就是:各家都有双向通信能力,但协议不统一,谁也不服谁,所以在 W3C 框架下重新制定了一套大家都认可的标准。
BiDi 内置在浏览器中,充当一个统一的转化器,把标准化的外部指令翻译成各家的私有协议:
BiDi(内置于 Chromium)→ 转成 CDP 调用 → V8 + Blink
BiDi(内置于 Firefox) → 转成 RDP 调用 → SpiderMonkey + Gecko
BiDi(内置于 WebKit) → 转成 Inspector 调用 → JavaScriptCore + WebCore
各家原有的私有协议(CDP、RDP 等)不会消失,它们依然是浏览器内部的核心调试机制。BiDi 只是在上面加了一层统一的接口。
四、Chromium vs Chrome:一个常被忽略的区别
聊 Playwright 的时候经常有人问:Playwright 安装时下载的 Chromium 和我们日常用的 Chrome 有什么区别?
Chromium(开源项目)
├── 纯开源代码
├── 没有 Google 服务(账号同步、自动更新等)
├── 没有专有编解码器(部分视频格式不支持)
└── 任何人都可以编译、修改
Chrome(Google 的产品)
├── 基于 Chromium 源码
├── + Google 账号体系
├── + 自动更新机制
├── + 专有媒体编解码器(H.264 等)
└── + 一些闭源商业组件
简单说:Chromium 是毛坯房,Chrome 是 Google 精装修后的成品房。 核心引擎(V8 + Blink)完全一样。
Playwright 为什么不直接用你电脑上的 Chrome?因为 CDP 协议的接口会随版本变化,Playwright 需要精确控制 Chromium 版本来确保兼容性。
同理,支持 BiDi 的浏览器需要较新版本——Chromium 大约 114+,Firefox 也需要较新版本才完整支持 BiDi。这也是为什么 RuyiPage 推荐使用它指定的 Firefox 版本。
五、主流自动化框架对比
| 框架 | 主要浏览器方向 | 底层协议 | CDP 暴露面 | Firefox / BiDi 支持度 | 被检测风险 |
|---|---|---|---|---|---|
| RuyiPage | Firefox | WebDriver BiDi | 无 | 高,主路线就是 Firefox + BiDi | 低(当前阶段) |
| Playwright | Chromium / Firefox / WebKit | CDP 为主 | 中到高 | 中,支持但不以 BiDi 为核心 | 中到高 |
| Selenium | 多浏览器 | WebDriver Classic + 部分 BiDi | 低到中 | 中,兼容广但 BiDi 能力不强 | 中 |
| Puppeteer | Chromium | CDP | 高 | 低 | 高 |
| DrissionPage | Chromium | 混合驱动,核心偏 Chromium | 中到高 | 低 | 中到高 |
选型建议:
- 主做 Firefox 自动化,关注反检测 → RuyiPage
- 多浏览器统一自动化 → Playwright / Selenium
- 主做 Chromium/CDP → Puppeteer / Playwright
- Firefox + BiDi 高层封装 → RuyiPage
六、反检测深度分析
6.1 CDP 方案(Playwright/Puppeteer)的主要检测点
调试端口开放
Playwright 启动 Chromium 时需要开放 CDP 调试端口(如 9222),反爬系统可以探测到这个端口的存在。这是一个从外部建立的 WebSocket 连接,网站能够感知到"有人从外面在控制我"。
浏览器启动参数特征
# Playwright 启动 Chromium 时典型的参数:
--disable-blink-features=AutomationControlled
--enable-features=NetworkService
--disable-background-networking
--disable-default-apps
--no-first-run
这些参数组合本身就是特征——正常用户不会这样启动浏览器。
navigator / window 属性异常
navigator.webdriver // 可能为 true
navigator.plugins.length // 自动化浏览器通常为 0
navigator.languages // 可能与系统语言不匹配
navigator.permissions.query({name: "notifications"})
// 真实浏览器返回 "prompt",自动化浏览器可能返回 "denied"
JS 执行堆栈差异(核心 CDP 暴露面)
通过 CDP 的 Runtime.evaluate 执行的 JS,和页面自身的 JS 相比,Error.stack 堆栈信息不同。网站可以通过分析堆栈帧来识别 CDP 注入的脚本。
const err = new Error();
console.log(err.stack);
// CDP 调用的堆栈里会出现特殊的帧信息
// 正常页面 JS 不会有这些
事件可信度
CDP 发送的点击事件,event.isTrusted 可以伪造为 true,但事件的其他属性(时间戳精度、坐标分布、事件序列)可能不自然。
WebGL / Canvas 指纹
WebGLRenderingContext.getParameter(renderer)
// 返回 "Google SwiftShader" → 大概率是自动化环境
自动化浏览器通常运行在无 GPU 环境,WebGL 渲染器字符串会暴露虚拟 GPU 特征。
6.2 BiDi 方案(RuyiPage)为什么当前检测少
无外部 CDP 连接痕迹: BiDi 是浏览器内置模块,不需要从外部建立 CDP 连接,没有调试端口暴露。
事件原生触发: BiDi 通过浏览器原生事件系统触发操作,event.isTrusted 天然为 true,不是伪造的。
不需要开放调试端口: 没有 9222 这样的端口特征。
启动参数更干净: 相比 Playwright 启动 Chromium 时的大量非常规参数,BiDi 方式更接近正常浏览器启动状态。
打个比方:
Playwright + CDP:像有人从窗户外面伸手进来操作你的电脑 → 窗户开着,屋里的人能看到
BiDi 内置:像电脑自己装了个定时任务在执行 → 没有开窗户,屋里的人看不出区别
6.3 BiDi 并非不可检测——清醒认知
BiDi 模块被激活本身就是特征。 正常用户浏览网页时,浏览器内置的 BiDi 模块不会被启用。只要风控厂商去逆向研究浏览器,就能找到 BiDi 启用后的内部状态差异。
启用 BiDi 需要特定的启动参数。 和 CDP 一样,这些参数就是检测特征。
浏览器内部状态差异。 BiDi 模块激活后,浏览器内部某些标志位、运行状态可能和正常使用不同,这些都是潜在的检测点。
行为层面的通病。 这是所有自动化方案都逃不掉的——鼠标轨迹、点击间隔、滚动模式、页面停留时间、请求时序等,机器操作和真人操作在统计特征上总有差异。
当前 BiDi 检测少的真实原因:
CDP 被检测 → 因为用了十几年,风控厂商研究透了,检测规则成熟
BiDi 暂时安全 → 因为太新,风控厂商还没投入精力去研究
这不是技术优势,是时间差优势。
等 BiDi 普及了、用的人多了,风控厂商一定会逆向浏览器找到 BiDi 启用后的特征,建立指纹库,覆盖检测规则。
七、结论:没有银弹
回顾整个演进路线:
WebDriver Classic(HTTP 单向)
↓ 解决双向通信问题
CDP(WebSocket 双向,但 Chromium 专属)
↓ 解决跨浏览器问题
WebDriver BiDi(WebSocket 双向 + 跨浏览器标准)
每一代协议都在解决上一代的核心痛点,但没有任何一代能从根本上解决"被检测"的问题。因为自动化操控浏览器本身就不是正常用户行为,程序控制和真人操作之间的差异,不会因为换一个协议就消失。
所有自动化方案——无论是 CDP、BiDi 还是未来可能出现的新协议——都只是在拉长被风控追上的时间窗口。选择框架时,应该根据实际场景(目标浏览器、性能需求、维护成本)来决定,而不是追求"绝对不被检测"。
务实的选型思路:
- 需要 Firefox + 当前反检测窗口期 → RuyiPage
- 需要多浏览器通用 + 生态成熟 → Playwright / Selenium
- 需要 Chromium 深度控制 → Puppeteer / Playwright
- 需要长期稳定 → 关注行为层面的拟人化,而不是押注某个协议
本文基于对 WebDriver、CDP、WebDriver BiDi 协议的技术分析,以及对 RuyiPage、Playwright、Selenium 等框架的对比研究整理而成。协议标准仍在演进中,文中观点基于 2026 年 4 月的现状。