
在 Web 自动化与反爬虫的对抗中很多开发者会遇到一个困惑明明已经改了 User-Agent、隐藏了无头模式Playwright 刚启动访问目标网站还是会被立刻识别拦截。其中最核心、也最容易被忽略的原因就是CDP 检测—— 一种直接命中自动化工具底层通信协议的检测技术。一、什么是 CDP 检测1. CDP 是什么CDP 全称Chrome DevTools ProtocolChrome 开发者工具协议是 Chromium 内核浏览器原生提供的一套调试与控制协议。它原本的设计目的是让开发者工具F12能够通过 WebSocket 连接实现对浏览器的底层控制比如操作 DOM、执行 JavaScript、捕获网络请求、分析性能等。Playwright、Puppeteer、Selenium 4 等主流自动化工具本质上都是通过 CDP 协议向浏览器发送指令完成页面导航、元素点击、数据抓取等操作。2. CDP 检测的定义CDP 检测是反爬虫与反欺诈系统使用的一类技术手段通过探测浏览器运行环境中是否存在 CDP 连接留下的特征与痕迹判断当前浏览器是否被自动化程序远程控制而非真人操作。和传统的 Canvas 指纹、WebGL 指纹不同CDP 检测不关心 “你用的是什么设备”而是直接回答 “有没有脚本在背后操纵浏览器” 这个核心问题因此检测权重更高也更难绕过。二、为什么 Playwright 一启动就会被识别Playwright 对 Chromium 的控制完全建立在 CDP 之上浏览器启动的瞬间CDP 会话就已经建立并在 JavaScript 运行时中留下了多处可被探测的痕迹。这就是为什么很多时候页面刚加载甚至还没执行任何操作就已经被识别。1.navigator.webdriver属性标记这是最基础也最广为人知的检测点。当浏览器通过 CDP 被自动化工具控制时navigator.webdriver属性会被自动设置为true而正常用户的浏览器中该值为false。网站只需要一行 JavaScript 代码就能完成检测if (navigator.webdriver) { // 判定为自动化工具 }虽然 Playwright 后续版本尝试隐藏这个属性但修改属性描述符本身也会产生新的特征依然可以被高级检测脚本识别。2.Runtime.enable运行时痕迹这是 CDP 检测最核心、最隐蔽的检测点也是 “一启动就被识别” 的主要原因。Playwright 在建立 CDP 连接后会默认调用Runtime.enable命令来接收执行上下文通知。这个调用会在 V8 引擎内部设置一个调试标志产生一个副作用当页面向控制台输出一个带有 getter 的对象时这个 getter 会被自动触发执行。正常浏览器中控制台不会主动读取对象的 getter而 CDP 开启后为了展示对象属性会自动调用所有 getter。反爬脚本正是利用这个差异通过构造一个带 getter 的对象并输出到控制台观察 getter 是否被自动触发就能精准判断 CDP 是否处于激活状态。3. CDP 专属全局属性泄露CDP 连接和自动化工具会在 window 对象上注入一些正常浏览器不存在的属性ChromeDriver 遗留的window.cdc_adoQpoasnfa76pfcZLmcfl_*系列属性Playwright 注入的__playwright_binding__等内部绑定对象window.__cdp相关的内部状态属性这些属性名通常是随机或特征化的字符串真人浏览器环境中绝不会出现扫描到即可直接判定为自动化。4. 执行上下文隔离特征通过 CDP 的Runtime.evaluate执行的 JavaScript 代码会运行在一个独立的隔离世界Isolated World中和页面自身的 JavaScript 不在同一个上下文。反爬脚本可以通过 Symbol 属性、函数调用栈、定时器执行顺序等方式探测到是否存在外来的隔离执行上下文从而识别 CDP 控制的存在。5. 其他 CDP 侧信道特征控制台 API 行为差异CDP 连接后console.debug、console.dir等方法的内部行为与正常浏览器存在细微差别事件可信标志缺失CDP 模拟的点击、键盘事件缺少真人输入事件特有的isTrusted true标志WebSocket 连接状态浏览器本地会开放调试端口并维持 WebSocket 连接高级检测可以通过网络侧特征识别三、CDP 检测 vs 普通浏览器指纹检测很多开发者容易把 CDP 检测和普通的浏览器指纹检测混为一谈实际上两者是完全不同的检测维度表格检测类型检测目标检测层面绕过难度浏览器指纹检测设备型号、显卡、字体、插件等环境特征应用层中等可通过伪装参数绕过CDP 检测浏览器是否被远程调试 / 控制运行时底层高触及协议本身的设计简单来说指纹检测回答 “你是谁”CDP 检测回答 “你是不是真人在操作”。即使你把所有指纹都伪装得和真人一模一样只要 CDP 连接存在依然会被精准识别。四、常见的 CDP 检测绕过思路1. Stealth 插件补丁社区最常用的方案是使用playwright-stealthPython或playwright-extrapuppeteer-extra-plugin-stealthNode.js。这类插件会在页面加载前注入 JavaScript 补丁覆盖navigator.webdriver、伪造window.chrome对象、修复控制台行为差异隐藏大部分表层 CDP 特征。但这类方案属于JavaScript 层面的修补无法从根本上消除Runtime.enable带来的底层特征面对 DataDome、Cloudflare Turnstile 等高级反爬系统时效果有限。2. 改造 CDP 调用的增强版本以 Patchright、rebrowser-patches 为代表的方案直接修改了 Playwright 内部的 CDP 调用逻辑避免不必要的Runtime.enable调用移除 CDP 绑定注入模式优化脚本执行上下文的隔离方式这类方案从协议层面减少了 CDP 痕迹绕过能力比普通 stealth 插件更强但依然无法完全消除 CDP 连接本身的存在。3. 附着到真实浏览器不使用 Playwright 自带的 Chromium而是启动一个普通用户安装的 Chrome 浏览器开启远程调试端口再让 Playwright 通过 CDP 附着上去。这种方式使用真实的浏览器二进制文件TLS 指纹、启动参数、内置插件都和真人浏览器一致能大幅降低被识别概率。4. 注意事项CDP 检测只是反爬体系的一环即使绕过了 CDP 检测TLS 指纹JA3/JA4、IP 信誉、行为模式等依然可能导致被拦截尽量使用headlessfalse有头模式无头模式会叠加更多可疑特征绕过 CDP 检测是一个持续对抗的过程没有一劳永逸的方案总结CDP 检测之所以能精准识别 Playwright本质上是因为 “控制浏览器” 这个行为本身就会留下痕迹 —— 只要你通过 CDP 协议去操纵浏览器就必然会在运行时中产生特征。理解 CDP 检测的原理能帮助我们跳出 “改 UA、换指纹” 的表层对抗思路从协议层面去理解自动化工具的暴露面。在实际场景中往往需要结合协议层补丁、真实浏览器、住宅 IP、行为模拟等多种手段才能达到较好的绕过效果。