从 Playwright 到 agent-browser:基于 Accessibility Tree 的浏览器自动化与 AI Agent 实践
这篇文章整理了一次从『传统浏览器自动化测试』一路深入到『AI Agent 驱动浏览器操作』的完整思考路径,核心关键词包括 Playwright、Rust、playwright-rs、agent-browser、Accessibility Tree、LLM。如果你正在思考如何让浏览器自动化更稳、更智能,或者如何把 LLM 接进真实网页操作,这篇总结可以作为一份系统性参考。
一、浏览器自动化的三条路线
在讨论具体工具前,先明确三种常见路线:
官方 Playwright(Node.js / Python / Java / .NET)
工程能力最强,生态最成熟,适合严肃的 E2E 测试。Rust + Playwright
通过 Rust bindings 调用 Playwright(如playwright-rs),在 Rust 工程内完成浏览器自动化。Rust WebDriver / Selenium 生态
标准化强,但对现代浏览器能力(自动等待、可访问性、trace)支持有限。
本文重点集中在 路线 2 以及由此延伸出的 agent-browser + LLM 思路。
二、playwright-rs:在 Rust 中写浏览器自动化测试
playwright-rs 是目前最有前途的 Rust Playwright 绑定:
- 基于 官方 Playwright Server(Node.js)
- Rust 侧通过 JSON-RPC 调用
- 支持 Chromium / Firefox / WebKit
- 支持 Linux / macOS / Windows
- 已在 GitHub Actions 跨平台跑通
一个最小的 Rust 测试用例
1 |
|
关键点在于:推荐使用 role / name 等基于可访问性语义的 locator,而不是 CSS selector。
三、Accessibility Tree 是什么?为什么它更稳?
它不是 DOM
Accessibility Tree 是浏览器内部为屏幕阅读器和辅助技术维护的一棵语义树:
- 节点是 button / textbox / heading / link
- 而不是 div / span
- 包含 role、accessible name、state(disabled/checked/expanded)
它由浏览器从 DOM + CSS + ARIA 自动计算生成。
为什么适合自动化与 AI ?
- 更贴近『人类理解的页面结构』
- 对 class、布局、嵌套不敏感
- 天然支持『这个按钮叫什么』『这个输入框是干嘛的』
Playwright 原生支持基于 accessibility 的定位,这也是它明显强于 Selenium 的地方。
ARIA(Accessible Rich Internet Applications)是一套给 Web 元素补充『语义、名称和状态』的规范,
浏览器据此计算 Accessibility Tree,供辅助技术、测试工具和 AI 使用。
ARIA 不是 Accessibility Tree 的『开关』,而是『校准器』;没有 ARIA,浏览器也能计算出树,只是精度可能不同。
四、Selenium 为什么很难支持 Accessibility Tree ?
结论先行:
Selenium 短期内几乎不可能完整支持 accessibility tree。
原因包括:
- WebDriver 标准主要围绕 DOM
- Accessibility Tree 属于浏览器内部语义模型
- AOM(Accessibility Object Model)仍处于实验/讨论阶段
- 不同浏览器、不同操作系统的无障碍实现差异巨大
因此,Selenium 通常只能:
- 结合 axe-core 等工具做无障碍检测
- 而不是『读取并操作 accessibility tree』
五、agent-browser:为 AI Agent 设计的浏览器控制层
- agent-browser 是什么
- Vercel Labs 出品
- 一个 Rust CLI + Playwright 后端 的工具
- 不是测试框架,而是『浏览器操作协议的 CLI 实现』
它的核心创新是:
snapshot + ref-id 的交互模型
- snapshot 的工作原理
- 从 Playwright 读取页面的 accessibility tree
- 语义裁剪(去掉无关节点)
- 为每个节点分配稳定的引用 ID(如 @e2)
- 输出一份『当前页面可操作状态』
示例:
1 | @e1 heading "Log in to Miro" |
- 用 ref-id 操作页面
1 | agent-browser fill @e2 "test@example.com" |
完全不需要 CSS selector。
source ~/.bashrc
第一步:确认你的环境前提
agent-browser 的现实前提有三点,缺一不可。
第一,macOS 本身没有问题,Intel 或 Apple Silicon 都可以。 第二,需要 Node.js(用于 Playwright)。 第三,需要 Rust(用于 agent-browser CLI)。
你可以先快速确认一下:
node -v
npm -v
rustc --version
cargo --version
如果 Node 没装,建议直接用:
brew install node
pnpm setup
pnpm config get global-dir
mkdir -p ~/.pnpm-global
pnpm config set global-dir ~/.pnpm-global
source ~/.zshrc
如果 Rust 没装:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup update stable
或者:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
rustup update stable
装完记得重新开一个 shell,确保 cargo 在 PATH 里。
第二步:安装 Playwright(这是最容易被忽略的一步)
agent-browser 不是直接控制浏览器,它底层仍然依赖 Playwright 的 browser binaries。
在一个干净目录里执行一次即可:
npx playwright install
或者:
npm install -g playwright@latest
playwright --version
playwright install
这一步会下载 Chromium / Firefox / WebKit。 macOS 上第一次运行浏览器时,系统可能会弹出『安全性与隐私』提示,允许即可。
如果这一步没做,后面 agent-browser 会『能启动,但打不开页面』。
第三步:安装 agent-browser CLI
现在开始真正的 agent-browser。
官方仓库是:
https://github.com/vercel-labs/agent-browser
最直接、最稳妥的方式是 从源码安装:
git clone https://github.com/vercel-labs/agent-browser.git
cd agent-browser
pnpm install
pnpm build
pnpm build:native # Requires Rust (https://rustup.rs)
pnpm link --global # Makes agent-browser available globally
agent-browser install
安装成功后,你应该能看到:
agent-browser --help
如果提示 command not found,检查 $HOME/.cargo/bin 是否在 PATH 中。
第四步:做一次最小可行测试(不接 LLM)
不要一上来就连 LLM,先验证三件事:
- Playwright 能起浏览器
- agent-browser 能读 accessibility tree
- snapshot 能正常输出
按顺序来:
agent-browser open https://miro.com/login/ --headed
你应该能看到浏览器窗口被打开。
接着:
agent-browser snapshot
正常情况下,会输出类似:
@e1 heading "Example Domain"
@e2 paragraph "This domain is for use in illustrative examples..."
@e3 link "More information..."
只要这一步成功,说明你的 macOS + Playwright + agent-browser 环境是健康的。
第五步:实际操作页面(验证 ref-id 模型)
继续在 example.com 上试:
agent-browser click @e22
agent-browser snapshot
你会看到页面发生变化,ref-id 全部重新分配。 这一步非常关键,它验证了你对 agent-browser 核心原则的理解:
ref-id 只在当前 snapshot 有意义
agent-browser click @e4
agent-browser fill @e6 "andy@dtype.info"
第六步:测试一个真实复杂页面(推荐)
不要立刻上 Miro、Google 这种登录页,先选一个『复杂但不反爬』的页面,比如:
agent-browser open https://news.ycombinator.com
agent-browser snapshot
你会看到大量:
@e1 link "Hacker News"
@e2 link "new"
@e3 link "past"
...
试着:
agent-browser click @e2
agent-browser snapshot
如果这一步稳定,说明 accessibility tree + ref-id 在真实页面上是可用的。
第七步:macOS 上几个非常常见的坑
这里是我强烈建议你提前注意的:
中文输入法干扰 在 fill textbox 时,尽量用英文输入法,否则某些页面会出现奇怪的 key event。
系统权限 第一次运行 Playwright 控制的浏览器时,macOS 可能阻止『自动化控制』。 去: 系统设置 → 隐私与安全性 → 辅助功能 / 自动化 放行你的终端(iTerm / Terminal)。
页面一变就 snapshot 不 snapshot 就继续 click / fill,是 agent-browser 使用中最常见的逻辑错误。
第八步:准备接 LLM(但暂时别急)
在 macOS 上,推荐的下一步架构是:
- agent-browser 作为 纯执行层
- 你自己写一个 controller(Rust / Python / Node 都行)
- LLM 只负责:
- 读 snapshot 文本
- 输出下一条命令(严格受限)
现在这个阶段,先不要上 MCP、不要上多 agent,先把『单步 → snapshot → 单步』这条链跑顺。
六、用 agent-browser 操作 Miro 登录页(示例)
1 | agent-browser open https://miro.com/login/ |
核心原则只有一句话:
页面一变,就重新 snapshot。
ref-id 是『当前页面状态下的逻辑锚点』,不是全局 ID。
七、agent-browser vs playwright-mcp
| 维度 | agent-browser | playwright-mcp |
|---|---|---|
| 形态 | CLI 工具 | MCP Server |
| 面向对象 | 脚本 / AI Agent | MCP 客户端(IDE / 桌面) |
| 交互方式 | 命令 + snapshot | 工具调用 |
| 状态管理 | 外部控制器 | MCP 会话 |
| 适合场景 | 自建 agent loop、 CI、脚本 |
IDE 内 AI 助手 |
一句话区分:
- agent-browser:浏览器能力 = 一组命令
- playwright-mcp:浏览器能力 = MCP 工具集
八、如何把 LLM 和 agent-browser 结合?
典型的 ReAct / Tool Loop:
- open 页面
- snapshot 获取页面状态
- 把 snapshot + 目标发给 LLM
- LLM 输出下一条命令(受限 DSL)
- 执行命令
- 重复直到完成或失败
关键工程要点:
- 命令白名单
- 域名限制
- 步数 / 时间上限
- 失败自动截图
本质分工是:
LLM 负责决策,agent-browser 负责执行。
使用 agent-browser 搭配 Claude Code 的方法也一并介绍。
通过在 AGENTS.md / CLAUDE.md 中像下面这样写明 agent-browser 的操作方式,就可以让 Claude Code 具备浏览器操作能力。
1 | ## Browser Automation |
安装 Ubuntu Server for ARM / macOS
1 | [FAILED] Failed unmounting cdrom.mount - /cdrom |
在 UTM 里操作方法如下。
- 在 UTM 窗口顶部菜单点击虚拟机的设置按钮
- 找到 CD/DVD 或 Drives
- 把挂载的 Ubuntu ISO 文件移除(Eject / Clear / 删除 ISO)
做完后,再回到虚拟机窗口按 ENTER。
1 | IFACE=$(ip -o link show | awk -F': ' '{print $2}' | grep -v lo | head -n1) |
1 | ip a |
1 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" |
1 | echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/$(whoami) > /dev/null |
1 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash |
1 | nvm install 22 && nvm alias default 22 && nvm use 22 |
安装并配置 OpenClaw
1 | npm install -g openclaw@latest |
配置局域网终端访问 OpenClaw Dashboard
- 配置 Tailscale
- 配置 Nginx
1. 配置 Nginx HTTPS 反向代理
2. 修改 OpenClaw 配置 - 添加 controlUi.dangerouslyDisableDeviceAuth: true(Device pairing)
3. 重启 Gateway - 尝试让新配置生效
配置 OpenClaw
禁用 web_search
如果不想使用 Brave API(需要绑定信用卡),可以在配置中禁用 web_search:
1 | openclaw config set 'tools.web.search.enabled' false |
重启后 web_search 工具将被禁用,web_fetch 仍然可用。如需禁用 web_fetch:
1 | openclaw config set 'tools.web.fetch.enabled' false |
新增 Skill 时添加环境变量
当创建的 Skill 需要环境变量(如 API 密钥、路径)时,有三种方式配置:
1. 每次调用时传递(推荐自定义变量)
1 | { |
2. 配置 PATH 预置目录
1 | openclaw config set tools.exec.pathPrepend '["/home/hijirii/.cargo/bin", "/opt/bin"]' |
⚠️ 注意:exec 工具不会读取
~/.bashrc或~/.profile,需要使用上述方式配置。对于host=gateway,env.PATH会被拒绝(安全限制),请使用pathPrepend代替。
九、整体对照总结
- playwright-rs:适合『Rust 工程内的自动化测试』
- Accessibility Tree:是稳定自动化与 AI 操作的语义基础
- agent-browser:把可访问性语义变成可执行协议
- LLM + agent-browser:让浏览器自动化从『写 selector』升级为『做决策』
十、一句话收尾
DOM 是给浏览器画页面用的,
Accessibility Tree 是给『人』理解页面用的,
而 agent-browser,是给 AI 操作页面用的。
这正是现代浏览器自动化正在发生的范式转移。