Browser-Use 公司决定放弃 Playwright 浏览器自动化框架,转而直接使用 Chrome DevTools Protocol (CDP) , 文章为此的学习笔记.
1. 为什么 Browser-Use 决定从 Playwright 转向原生的 Chrome DevTools Protocol (CDP)?
Browser-Use 决定放弃 Playwright 转向原生 CDP,主要原因是为了解决抽象层带来的问题,并获得更深层次的控制和性能提升。Playwright 和 Puppeteer 这样的适配器库虽然便于 QA 测试和自动化脚本的编写,但在 AI 浏览器公司过去一年的经验中发现,它们可能会掩盖底层浏览器的重要细节。通过直接使用 CDP,Browser-Use 大幅提高了元素提取、截图和所有默认操作的速度,并增加了异步反应能力和对跨域 iframe 的原生支持。Playwright 引入了一个额外的网络跳跃(通过 Node.js Playwright 服务器 websocket),这在进行数千次 CDP 调用时会产生明显的延迟。最终,他们发现适配器库不再能节省时间,反而成为了实现更专业化逻辑的障碍,尤其是在处理 AI 浏览器代理更窄的需求时。
2. Playwright 是如何工作的,以及它有哪些“尖锐的边缘”或痛点?
Playwright 通过客户端-服务器模型实现多语言支持,其中不同语言的客户端与一个运行 Node.js websocket 服务器的核心实现进行通信。这个 Playwright Node.js 中继服务器接收标准化的“Playwright 协议”RPC 调用,然后将其转换为 CDP 或 BIDI 调用发送给浏览器执行。虽然这种设计在某些方面很优雅,提供了类型化的 RPC 接口并标准化了跨语言的行为,但它引入了双重 RPC 机制,导致状态在浏览器、Playwright Node.js 中继进程和 Python 客户端进程这三者之间不可避免地发生漂移,这三者还涉及不同的语言和运行时。
Playwright 的“尖锐边缘”或痛点包括:
- 稳定性问题:例如,截取超过 16,000 像素高的全页截图会可靠地导致 Playwright 崩溃。
- 边缘情况处理不佳:在特定慢速网络条件下,Node.js 进程可能无限期地等待浏览器回复,导致 Python 客户端挂起。
- 特殊页面处理:alert() / confirm() / onbeforeunload 弹出窗口处理、文件上传和下载处理、以及 about:*、chrome://* 等特殊页面类型和崩溃的标签页处理存在问题。
- 自定义和控制受限:对于需要彻底利用适配器层并进行高度自定义和控制的场景,Playwright 的抽象反而成为障碍。
3. Chrome DevTools Protocol (CDP) 在浏览器自动化历史中扮演了怎样的角色?
CDP 在浏览器自动化历史中扮演了核心且不断演进的角色。它的起源可以追溯到 2011 年 Chrome 发布的远程调试功能和 WebKit Remote Debugging Protocol v1.0。随着 2013-2014 年 Blink 从 WebKit 分叉,该协议在 Chromium 侧固化并正式成为 Chrome DevTools Protocol (CDP)。它定义了浏览器使用的域/事件模型。
CDP 的重要里程碑包括:
- 2017 年 4 月:无头 Chrome 发布,Puppeteer 作为 Chrome 团队的 Node 库,通过 CDP 驱动 Chrome(无头或完整模式)被引入。
- 2018 年 1 月:Puppeteer 1.0 发布,标志着 CDP 驱动的自动化工具进入成熟阶段。
尽管后来出现了 WebDriver 这样的 W3C 跨浏览器标准和 Playwright 这样的多浏览器框架,但 CDP 一直是 Chromium 浏览器自动化核心的底层协议。许多高级驱动库和 AI 助手扩展本质上都是通过 CDP 来实现与浏览器的通信和 RPC 调用。
4. 除了 CDP,Chromium 还暴露了哪些其他的自动化 API?
除了 CDP,Chromium 还暴露了以下几种自动化 API:
- Chrome 扩展 API:这些 API 看起来功能强大,因为它们通过 chrome.debugger 包含了 CDP。然而,原生的 CDP 允许访问一些 chrome.debugger 不可用的调用,并支持并行连接到多个目标。
- OS 级别的辅助功能和屏幕阅读器 API:例如 NVDA、Voice Over、AppleScript 和 Appium 等,这些 API 允许获取屏幕阅读器可见的元素树(链接、按钮、输入等),并脚本化复制/粘贴、鼠标、键盘输入以及基于元素旋转器/标签页的导航。
- 内部 Chromium C++ API:这是 Chromium 源代码内部的 API,允许更深层次的定制,甚至可以编辑 CDP 规范以添加自定义 C++ API 调用,这在“呼叫来自屋内”时提供了几乎无限的可能性。
值得注意的是,W3C WebDriver / ChromeDriver REST API 并不是浏览器直接暴露的,而是 W3C 推荐的驱动程序(如 ChromeDriver、GeckoDriver、WebKitDriver)提供给客户端的标准化 REST API 形式,它们构建在底层的 CDP/BIDI 调用之上。WebDriver BiDi 是一种正在开发中的协议,旨在将旧的基于 REST API 的 WebDriver 系统与 CDP 合并到一个 WebSocket 中。
5. 为什么说构建 AI 浏览器自动化是“构建在复杂性的叠叠乐塔上”?
构建 AI 浏览器自动化被比喻为“构建在复杂性的叠叠乐塔上”,因为每一层都引入了其自身的“有漏洞的抽象”、细微的崩溃和资源限制。这意味着开发者不仅需要理解他们正在使用的适配器库(如 Playwright),还需要理解这些库所依赖的底层浏览器协议(如 CDP),以及操作系统级别的交互。每一层都可能隐藏重要的细节,导致难以追踪的错误和性能瓶颈。当一个大型代码库围绕一个适配器库构建时,最终会发现该库不再通过“隐藏真实复杂性”来节省时间,反而成为了实现可靠、高性能解决方案的障碍。特别是对于 AI 浏览器代理,它们需要对浏览器行为有更精细的控制和更快的响应速度,使得这些抽象层的代价变得更加明显。
6. Browser-Use 迁移到原生 CDP 后,在架构上引入了哪些关键变化?
Browser-Use 迁移到原生 CDP 后,引入了以下关键的架构变化:
- 新的 cdp-use 库提供 Python 类型绑定:这是一个为 Chrome DevTools Protocol (CDP) 生成类型安全的 Python 客户端的库。它自动从官方 CDP 协议规范生成带有完整 TypeScript 风格类型安全的 Python 绑定,提供 100% 直接访问,而没有复杂的会话管理、页面或元素逻辑。
- 新的事件驱动架构:过去,他们只在操作之间更新对世界的视图,这在假设页面内容只因操作而改变时是合理的。然而,许多页面内容会自发改变(如缓慢加载的结果列表、动画轮播等)。现在他们引入了事件驱动架构,以更好地适应 CDP 的底层事件驱动架构。这使得他们能够订阅和响应 CDP 事件,并设置“watch dog”服务来监控各种情况,例如文件下载或页面崩溃,从而集中处理事件和错误恢复逻辑。
- 新的跨 OOPIF 工作的提取元素句柄:一个标签页实际上是“目标”(根目标 + 跨域 iframe + worker)的集合,每个目标都包含“帧”,每个帧都包含“节点”。抽象掉这些细节会导致无法正确路由输入、关联事件以及在 DOM 更改后重新找到元素。现在,他们使用包含 targetId、frameId、backendNodeId、x/y 位置和备用选择器的“超级选择器”来表示节点,并提供了最小的路由辅助函数,以确保即使在嵌套的跨域 iframe 和 DOM 元素移动的情况下,也能准确知道节点所有者和输入应该落在何处。
7. 浏览器标签页崩溃有哪些不同的方式?解决这些问题为什么是一个巨大的工程挑战?
Chrome 中至少有 10 种不同的方式可能导致标签页崩溃,这使得交付可靠的体验成为一个巨大的工程挑战,因为底层组件本身就不可靠,甚至具有对抗性。这些崩溃方式包括:
- 所有目标在初始请求正在进行时都会短暂地处于“崩溃”/无响应状态。
- Chrome 核心进程(zygote/root process)可能因文件系统 I/O 慢、内存不足 (OOM) 或 CPU 延迟而崩溃。
- GPU 进程可能崩溃,甚至有专门的 CDP 调用 Browser.crashGpuProcess。
- 页面渲染器可能因 Chrome 源代码中的异常(如 SIGSEV、OOM)而崩溃。
- 页面渲染器可能因页面超出允许的资源(通过 Page.crash() 方法)而崩溃。
- 页面可能因 JavaScript 主线程中的无限循环或加密挖矿而自旋锁/内存溢出。
- 在 activateTarget 焦点之前进行滚动/输入/截图可能导致目标崩溃(5 秒延迟)。
- 在 activateTarget 之前处理 JavaScript 弹出窗口,或在关闭后尝试处理。
- 父框架在子 onbeforeunload 期间进行导航。
- 上述任何一种崩溃发生在嵌套的跨源进程外 iframe (OOPIF) 中,导致父目标出现微妙问题。
Playwright 能够处理其中大约一半的问题,但在解决另一半问题上设置了不可逾越的障碍。因此,Browser-Use 决定转向原生 CDP,并承担解决所有这些崩溃情况的挑战,以确保其用户能够在其之上构建可靠的应用程序。
8. “时间是一个扁平的圆圈”这句话在浏览器自动化领域意味着什么?
“时间是一个扁平的圆圈”这句话指的是,尽管技术不断进步,但在浏览器自动化领域,许多核心问题和挑战自十年前就一直存在并循环出现。作者提到,早在 2014 年,他刚开始创业时使用 PhantomJS 和 Python 与 JS 之间的 RPC,而到 2025 年,他仍然在处理相同的问题:标签页崩溃处理、页面加载重试、JS+Python RPC 翻译问题、Python asyncio 的头痛问题、鼠标移动模糊等等。
这句话强调了浏览器自动化固有的复杂性,以及开发者在不同时期使用不同工具时,往往会遇到类似的基本障碍。虽然工具和协议有所改进(如 CDP、WebDriver BiDi 的发展),但底层浏览器的行为模式和自动化过程中可能出现的问题(如各种崩溃、页面状态同步)具有持久性。不过,作者也乐观地指出,尽管挑战依然存在,但现在有了 AI 这个“隧道尽头的一大束光”,有望帮助解决手动 QA 自动化中的许多复杂性。