关于 dev-browser
dev-browser 是面向 Agent 的浏览器自动化技能,通过小型脚本逐步执行任务,并在运行之间保留页面状态。它支持独立 Chromium 或连接用户的 Chrome 会话,并以 Playwright 控制页面、通过无障碍快照发现元素。
主要功能
- 01脚本运行间保留页面状态
- 02使用独立 Chromium 或 Chrome 扩展模式
- 03通过 Playwright 控制页面
- 04借助 ARIA 快照和引用查找元素
- 05截图并检查页面状态
适用场景
- 01通过多个脚本逐步自动化任务
- 02操作现有浏览器中的已登录网站
- 03先检查陌生页面布局再定位元素
- 04通过重放网络请求抓取大型数据集
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ code-yeongyu/ oh-my-openagent --skill dev-browser安装后在 Claude Code 中输入/dev-browser确认已加载。
详细介绍
Dev Browser Skill
浏览器自动化,可在多次脚本执行之间保留页面状态。编写小巧、专注的脚本,逐步完成任务。验证工作流中的某个环节后,如果有重复工作要做,可以编写脚本,在一次执行中完成这些重复工作。
选择方法
- 本地/可查看源代码的网站:先阅读源代码,直接编写选择器
- 布局未知的页面:使用
getAISnapshot()发现元素,并使用selectSnapshotRef()与之交互 - 视觉反馈:截取屏幕截图,查看用户所见内容
设置
安装:请参阅 references/installation.md,了解详细的设置说明,包括 Windows 支持。
有两种模式可供选择。如果不确定使用哪种模式,请询问用户。
独立模式(默认)
启动新的 Chromium 浏览器,用于全新的自动化会话。
./skills/dev-browser/server.sh &
如果用户提出要求,请添加 --headless 标志。运行脚本前,请等待 Ready 消息。
扩展模式
连接到用户现有的 Chrome 浏览器。在以下情况使用:
- 用户已登录网站,并希望你在非本地开发环境的已认证体验中执行操作。
- 用户要求你使用扩展程序
重要:核心流程仍然相同。你需要在用户的浏览器中创建命名页面。
启动中继服务器:
cd skills/dev-browser && npm i && npm run start-extension &
等待控制台中出现 Waiting for extension to connect...,随后出现 Extension connected。这表示客户端已连接,浏览器已准备好接受控制。
工作流:
- 脚本调用
client.page("name"),与常规模式一样创建新页面/连接到现有页面。 - 自动化操作在用户实际的浏览器会话中运行
如果扩展程序尚未连接,请告知用户启动并激活扩展程序。下载链接:https://github.com/SawyerHood/dev-browser/releases
编写脚本
请从
skills/dev-browser/目录运行所有脚本。@/导入别名需要此目录的配置。
使用 heredoc 内联执行脚本:
cd skills/dev-browser && npx tsx <<'EOF'
import { connect, waitForPageLoad } from "@/client.js";
const client = await connect();
// Create page with custom viewport size (optional)
const page = await client.page("example", { viewport: { width: 1920, height: 1080 } });
await page.goto("https://example.com");
await waitForPageLoad(page);
console.log({ title: await page.title(), url: page.url() });
await client.disconnect();
EOF
仅在需要重复使用脚本、脚本较复杂或用户明确要求时,才写入 tmp/ 文件。
核心原则
- 编写小脚本:每个脚本只做一件事(导航、点击、填充、检查)
- 评估状态:在末尾记录/返回状态,以决定下一步
- 使用描述性页面名称:使用
"checkout"、"login",而不是"main" - 断开连接以退出:
await client.disconnect()——页面会保留在服务器上 - 在 evaluate 中使用纯 JS:
page.evaluate()在浏览器中运行,不支持 TypeScript 语法
工作流循环
对于复杂任务,请遵循以下模式:
- 编写脚本,执行一个操作
- 运行脚本并观察输出
- 评估结果——操作成功了吗?当前状态如何?
- 决定下一步——任务已完成,还是需要再写一个脚本?
- 重复以上步骤,直到任务完成
浏览器上下文中不使用 TypeScript
传递给 page.evaluate() 的代码会在浏览器中运行,而浏览器不支持 TypeScript:
// ✅ Correct: plain JavaScript
const text = await page.evaluate(() => {
return document.body.innerText;
});
// ❌ Wrong: TypeScript syntax will fail at runtime
const text = await page.evaluate(() => {
const el: HTMLElement = document.body; // Type annotation breaks in browser!
return el.innerText;
});
抓取数据
抓取大型数据集时,应拦截并重放网络请求,而不是滚动 DOM。请参阅 references/scraping.md,获取涵盖请求捕获、架构发现和分页 API 重放的完整指南。
客户端 API
const client = await connect();
// Get or create named page (viewport only applies to new pages)
const page = await client.page("name");
const pageWithSize = await client.page("name", { viewport: { width: 1920, height: 1080 } });
const pages = await client.list(); // List all page names
await client.close("name"); // Close a page
await client.disconnect(); // Disconnect (pages persist)
// ARIA Snapshot methods
const snapshot = await client.getAISnapshot("name"); // Get accessibility tree
const element = await client.selectSnapshotRef("name", "e5"); // Get element by ref
page 对象是标准的 Playwright Page。
等待
import { waitForPageLoad } from "@/client.js";
await waitForPageLoad(page); // After navigation
await page.waitForSelector(".results"); // For specific elements
await page.waitForURL("**/success"); // For specific URL
检查页面状态
屏幕截图
await page.screenshot({ path: "tmp/screenshot.png" });
await page.screenshot({ path: "tmp/full.png", fullPage: true });
ARIA 快照(元素发现)
使用 getAISnapshot() 发现页面元素。返回 YAML 格式的无障碍树:
- banner:
- link "Hacker News" [ref=e1]
- navigation:
- link "new" [ref=e2]
- main:
- list:
- listitem:
- link "Article Title" [ref=e8]
- link "328 comments" [ref=e9]
- contentinfo:
- textbox [ref=e10]
- /placeholder: "Search"
理解 refs:
[ref=eN]——用于交互的元素引用(仅包含可见、可点击的元素)[checked]、[disabled]、[expanded]——元素状态[level=N]——标题级别/url:、/placeholder:——元素属性
使用 refs 交互:
const snapshot = await client.getAISnapshot("hackernews");
console.log(snapshot); // Find the ref you need
const element = await client.selectSnapshotRef("hackernews", "e2");
await element.click();
错误恢复
失败后页面状态仍会保留。使用以下方式调试:
cd skills/dev-browser && npx tsx <<'EOF'
import { connect } from "@/client.js";
const client = await connect();
const page = await client.page("hackernews");
await page.screenshot({ path: "tmp/debug.png" });
console.log({
url: page.url(),
title: await page.title(),
bodyText: await page.textContent("body").then((t) => t?.slice(0, 200)),
});
await client.disconnect();
EOF