playwright-cdp
直接通过 Chrome DevTools Protocol (CDP) 驱动 Chromium —— 一套 Playwright 风格的 Rust API,无需 Node.js driver。
playwright-cdp 通过单条 WebSocket 原生地讲 CDP 协议。它的 API 形状镜像 Playwright
(Playwright → BrowserType → Browser → BrowserContext → Page → Locator,
builder 选项结构体、async/Result<T>),但不去 spawn Playwright 的 Node driver 再
代理转发,而是直接拉起一个 Chromium 进程并原生驱动。
为什么做这个
playwright-rust(以及上游 Playwright)
会 shell 出一个 Node.js driver 二进制,通过自定义管道协议通信。能用,但代价是:
- 强依赖 Node.js 运行时 + Playwright 的
node_modules; - 多一个 IPC 跳板和需要管理的子进程;
- Rust crate 与已安装 driver 之间的版本耦合。
playwright-cdp 把这些都去掉了。系统里只要有 Chrome/Chromium 可执行文件,剩下全是纯
Rust 直接讲 CDP。
状态
当前为早期 0.1.x。核心 API 已实现,并对真实 Chrome 做了端到端验证(cargo test
全绿,见验证)。尚未覆盖 Playwright 的全部特性 —— 见
已实现与限制。
快速开始
[]
= "0.1"
= { = "1", = ["full"] }
use ;
async
如果你不需要 Playwright/BrowserType 这一层,直接 Browser::launch(opts) 也可以。
定位器与交互
# use AriaRole;
# // page: playwright_cdp::Page
# # let page: Page = unimplemented!;
page.locator.fill.await?;
page.get_by_role.click.await?;
let count: usize = page.locator.count.await?;
# Ok
网络拦截
# use RouteFulfillOptions;
# # let page: Page = unimplemented!;
page.route.await?;
# Ok
已实现
以下全部是基于 CDP 的真实实现(非桩函数):
| 领域 | 类型 / 能力 |
|---|---|
| 入口 | Playwright、BrowserType(chromium/firefox/webkit)、Browser::launch / connect_over_cdp |
| 上下文 | BrowserContext —— 页面、cookies、额外 headers、add_init_script、set_default_timeout / set_default_navigation_timeout、grant_permissions / clear_permissions、storage_state(cookies + localStorage)/ set_storage_state、上下文级 route |
| 页面 / 帧 | Page、Frame、FrameLocator —— goto/reload/go_back/go_forward/wait_for_url/wait_for_load_state、evaluate/eval_on_selector/wait_for_function、query_selector(_all)、screenshot、pdf、set_viewport_size、emulate_media、set_offline、set_cache_disabled、bring_to_front、set_geolocation、drag_and_drop、expose_function |
| 定位器 | Locator —— click/dblclick/fill/clear/check/uncheck/set_checked/press/hover/tap/drag_to/select_option/set_input_files/dispatch_event/scroll_into_view_if_needed,文本/属性/状态查询,nth/first/last/all/filter/and_/or_、evaluate(_all)、bounding_box、screenshot、wait_for、aria_snapshot |
| 元素与输入 | ElementHandle、Keyboard、Mouse、Touchscreen |
| 网络 | Request、Response(status/headers/body/text/json)、Route(continue_/fulfill/abort/fallback)、on_request/on_response/on_requestfinished/on_requestfailed、基于在途请求计数的 networkidle |
| 事件 | on_console、on_dialog(+ Dialog)、on_pageerror、on_download(+ Download)、on_filechooser(+ FileChooser)、on_worker(+ Worker)、on_page、on_close |
| 诊断 | Tracing(经 Tracing 域采集 Chrome trace)、aria_snapshot(无障碍树 → Playwright YAML)、ConsoleMessage |
| API 测试 | APIRequestContext / APIResponse —— 基于 reqwest 的独立 HTTP 客户端(page.request()、context.request()) |
| 断言 | expect(locator) / expect_page(page) —— to_be_visible/hidden/enabled/disabled/editable/checked、to_have_text/contain_text/inner_text、to_have_count/attribute/value、to_have_title/url,支持 .not() 与 .with_timeout(...) |
选择器引擎(text=、xpath=、role=、CSS、>> 链式)是一个按执行上下文注入的小脚本;
同源 <iframe> 遍历可通过 FrameLocator 完成。
示例
examples/ 下有十个可运行示例,每个都是针对真实浏览器的端到端演示:
| 示例 | 演示内容 |
|---|---|
demo |
启动、导航、求值、定位器点击、fill、截图 |
interactions |
click/fill/check/select/dblclick/hover/press + keyboard/mouse/touchscreen |
assertions |
expect / expect_page 断言 |
network |
请求/响应捕获、route fulfill/abort |
api_request |
独立的 page.request() HTTP 客户端 |
frames |
FrameLocator + 帧树 |
page_capture |
截图、PDF、aria_snapshot |
dialogs_downloads |
on_dialog、on_download |
contexts |
上下文隔离、cookies、storage_state 往返 |
bindings |
expose_function、wait_for_function |
验证
需要浏览器的测试在找不到 Chrome/Chromium 时会优雅跳过(可用 CHROME_PATH
或在 LaunchOptions 里指定 executable_path 来固定一个)。
工作原理
你的应用 ──► playwright-cdp (Rust)
│ 拉起并拥有 Chrome 进程(--remote-debugging-port)
│ 打开一条 ws:// 连接(flatten,多路复用)
└──► Chrome DevTools Protocol(Target / Page / Runtime / Network
/ DOM / Input / Fetch / Emulation / Accessibility / Tracing …)
BrowserProcess发现 Chrome 可执行文件(executable_path、CHROME_PATH、 常见安装路径、channel),以--remote-debugging-port=0启动,读取DevToolsActivePort,解析出浏览器 WebSocket 端点。CdpConnection在单条 socket 上多路复用请求/响应配对与事件分发;flatten 的 auto-attach 让弹窗/worker 复用同一条连接。- 页面级求值走默认(主世界)的
Runtime.evaluate,这样导航后不会因缓存的 执行上下文 id 失效而出错。
限制
- 仅支持 Chromium。 Firefox/WebKit 返回的是一个 Chromium 后端的
BrowserType并打印警告(CDP 是 Chromium 专有协议)。 FrameLocator仅支持同源(跨源 iframe 无法从父框架主世界访问)。- 对 headless Chrome 150 的怪行为做了防御式处理:例如
FileChooser走DOM.setFileInputFiles(该版本的Page.handleFileChooser不被支持);Download在收不到Completed进度事件时回退到文件系统轮询。 - 尚未实现:
Selectors.register(自定义选择器引擎)、popup-as-Page(opener/on_popup)、recordVideo、旧的page.accessibility.snapshot()JSON API。aria_snapshot力求贴近 Playwright 格式,但不保证边缘情况字节级一致。
许可证
Apache-2.0,见 LICENSE。