mcpField
D
dev-browser

dev-browser

github.com/code-yeongyu开发70.5k45 次安装今天更新
代码仓库

关于 dev-browser

dev-browser 是面向 Agent 的浏览器自动化技能,通过小型脚本逐步执行任务,并在运行之间保留页面状态。它支持独立 Chromium 或连接用户的 Chrome 会话,并以 Playwright 控制页面、通过无障碍快照发现元素。

主要功能

  1. 01脚本运行间保留页面状态
  2. 02使用独立 Chromium 或 Chrome 扩展模式
  3. 03通过 Playwright 控制页面
  4. 04借助 ARIA 快照和引用查找元素
  5. 05截图并检查页面状态

适用场景

  1. 01通过多个脚本逐步自动化任务
  2. 02操作现有浏览器中的已登录网站
  3. 03先检查陌生页面布局再定位元素
  4. 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。这表示客户端已连接,浏览器已准备好接受控制。 工作流:

  1. 脚本调用 client.page("name"),与常规模式一样创建新页面/连接到现有页面。
  2. 自动化操作在用户实际的浏览器会话中运行

如果扩展程序尚未连接,请告知用户启动并激活扩展程序。下载链接: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/ 文件。

核心原则
  1. 编写小脚本:每个脚本只做一件事(导航、点击、填充、检查)
  2. 评估状态:在末尾记录/返回状态,以决定下一步
  3. 使用描述性页面名称:使用 "checkout"、"login",而不是 "main"
  4. 断开连接以退出:await client.disconnect()——页面会保留在服务器上
  5. 在 evaluate 中使用纯 JS:page.evaluate() 在浏览器中运行,不支持 TypeScript 语法

工作流循环

对于复杂任务,请遵循以下模式:

  1. 编写脚本,执行一个操作
  2. 运行脚本并观察输出
  3. 评估结果——操作成功了吗?当前状态如何?
  4. 决定下一步——任务已完成,还是需要再写一个脚本?
  5. 重复以上步骤,直到任务完成
浏览器上下文中不使用 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

评论

支持 Markdown