深入理解浏览器自动化协议:从 CDP 到 BiDi,框架对比与反检测分析

3 阅读10分钟

本文从浏览器自动化的底层原理出发,梳理 WebDriver Classic、CDP、WebDriver BiDi 三代协议的演进脉络,对比主流自动化框架的技术差异,并深入分析各方案的反检测特征与局限性。


一、浏览器自动化的底层基础

在聊协议之前,先搞清楚浏览器到底是什么。

每个浏览器内核由两个核心引擎组成:

浏览器JS 引擎渲染引擎
Chromium (Chrome/Edge)V8Blink
FirefoxSpiderMonkeyGecko
WebKit (Safari)JavaScriptCoreWebCore

所有浏览器自动化框架的本质,就是把外部指令传递给这两个引擎去执行。 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 ClassicCDPWebDriver 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 支持度被检测风险
RuyiPageFirefoxWebDriver BiDi高,主路线就是 Firefox + BiDi低(当前阶段)
PlaywrightChromium / Firefox / WebKitCDP 为主中到高中,支持但不以 BiDi 为核心中到高
Selenium多浏览器WebDriver Classic + 部分 BiDi低到中中,兼容广但 BiDi 能力不强
PuppeteerChromiumCDP
DrissionPageChromium混合驱动,核心偏 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 月的现状。