16.3 Playwright 层实现

生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~180k tokens,输出 ~6k tokens(本节)


上一节我们解析了 CDP 低级层——直接通过 WebSocket 控制浏览器。本节上升到 Playwright 层,这是 Agent 与网页交互的主要接口:智能元素定位、页面快照、交互操作、状态管理。


16.3.1 Playwright 会话管理

连接复用

Playwright 通过 CDP 连接到 Chrome,但与 withCdpSocket() 的一次性连接不同,Playwright 需要持久连接来维护页面状态:

// src/browser/pw-session.ts — 连接缓存
let cached: ConnectedBrowser | null = null;
let connecting: Promise<ConnectedBrowser> | null = null;

通过 cachedconnecting 实现连接复用——同一时刻只维护一个 Playwright 到 Chrome 的连接,所有操作共享这个连接。

页面状态追踪

每个 Page 对象关联一个 PageState,用 WeakMap 管理:

// src/browser/pw-session.ts — 页面状态
type PageState = {
  console: BrowserConsoleMessage[];  // 控制台消息(最多 500 条)
  errors: BrowserPageError[];        // 页面错误(最多 200 条)
  requests: BrowserNetworkRequest[]; // 网络请求(最多 500 条)
  requestIds: WeakMap<Request, string>;
  
  // 角色引用(Role Refs)——页面快照中元素的标识
  roleRefs?: Record<string, { role: string; name?: string; nth?: number }>;
  roleRefsMode?: "role" | "aria";
  roleRefsFrameSelector?: string;
};

const pageStates = new WeakMap<Page, PageState>();

衍生解释WeakMap 是 JavaScript 的一种特殊 Map,其键是弱引用——当键对象(这里是 Page)被垃圾回收时,对应的 entry 自动消失。这正好适合管理页面状态:当 Playwright 销毁 Page 对象后,相关的状态数据不会造成内存泄漏。

Role Refs 缓存

页面快照会生成角色引用(如 e1e2),Agent 通过这些引用来操作元素。为了保持引用稳定性(即使 Playwright 返回了不同的 Page 对象),还有一个 target 级别的缓存:

缓存键是 ${cdpUrl}::${targetId},最多存储 50 个 target 的引用,FIFO 淘汰。


16.3.2 角色快照(Role Snapshot)

角色快照是 OpenClaw 浏览器控制的核心创新——它将网页的可访问性树转换为 Agent 可读的文本表示,并为每个交互元素分配一个短引用 ID。

三类 ARIA 角色

衍生解释:ARIA(Accessible Rich Internet Applications)是 W3C 制定的标准,定义了 Web 元素的语义角色(Role)。例如一个 <div> 可以有 role="button" 表示它是按钮,<input type="text"> 自动获得 role="textbox"。屏幕阅读器(如 VoiceOver、NVDA)依赖这些角色来向视障用户描述页面结构。OpenClaw 复用了这个标准——Agent 通过角色来"看"页面,就像屏幕阅读器一样。

快照格式

角色快照的输出类似这样:

方括号中的 [e1][e2] 等就是角色引用——Agent 在后续操作中使用 e3 来点击 "Cart" 按钮。

引用分配与去重

当页面上有多个同名按钮(如两个 "Add to Cart"),追踪器会为它们分配不同的 nth 索引,确保引用不歧义。

快照统计


16.3.3 三种快照模式

OpenClaw 提供三种页面快照方式,各有侧重:

1. AI Snapshot(推荐)

_snapshotForAI 是 Playwright 内部的一个方法(前缀下划线表示非公开 API),它返回一个为 AI 优化的页面文本表示。

2. ARIA Snapshot

直接获取 Chrome 的可访问性树——信息最完整但体积较大。

3. Role Snapshot

Role Snapshot 支持过滤选项——可以只显示交互元素、限制深度、压缩结构性节点——适合 Agent 快速了解页面可操作元素。


16.3.4 Playwright 工具核心

pw-tools-core.ts 是一个桶文件,聚合了八个子模块:

interactions — 交互操作

核心交互操作都通过角色引用定位元素:

refLocator(page, ref) 是关键桥梁——它在 PageState.roleRefs 中查找引用 e3 对应的 { role: "button", name: "Cart (3)" },然后构造 Playwright 的 page.getByRole("button", { name: "Cart (3)" }) 定位器。

完整的交互操作集:

函数
用途

clickViaPlaywright

点击/双击元素

hoverViaPlaywright

悬停

typeViaPlaywright

在输入框中打字

fillFormViaPlaywright

批量填写表单

selectOptionViaPlaywright

选择下拉选项

pressKeyViaPlaywright

按键(如 Enter、Tab)

dragViaPlaywright

拖拽

scrollIntoViewViaPlaywright

滚动到元素可见

highlightViaPlaywright

高亮元素(调试用)

setInputFilesViaPlaywright

文件上传

armFileUploadViaPlaywright

预备文件选择器

armDialogViaPlaywright

预备对话框处理

downloads — 下载管理

state — 页面状态

storage — 存储管理

trace — 性能追踪


16.3.5 AI 辅助模块聚合

pw-ai.ts 将所有 Playwright 操作重新导出为统一的 API 表面:


本节小结

  1. Playwright 连接复用——全局缓存一个到 Chrome 的持久连接,所有操作共享

  2. 页面状态用 WeakMap 管理——控制台消息、网络请求、页面错误各有容量上限(500/500/200)

  3. 角色快照是 Agent "看"网页的方式——将可访问性树转为缩进文本,为每个交互元素分配短引用 ID(如 e1

  4. 三种快照模式:AI Snapshot(Playwright 内建优化)、ARIA Snapshot(完整可访问性树)、Role Snapshot(可过滤/压缩)

  5. 所有交互操作通过角色引用定位——Agent 看到 [e3] 就用 ref: "e3" 来点击,底层通过 getByRole() 解析

  6. 工具核心分为八大模块:交互、快照、下载、响应、活动、状态、存储、追踪

  7. pw-ai.ts 聚合了 60+ 个 Playwright 操作函数,为浏览器服务器提供统一的 API 表面

Last updated