remorses/playwriter

GitHub: remorses/playwriter

Playwriter 让 AI agent 通过 Chrome 扩展和 CLI/MCP 直接控制用户正在运行的浏览器,保留完整登录状态与扩展,实现低干扰的浏览器自动化。

Stars: 3715 | Forks: 164


Playwriter - For browser automation MCP

Let your agents control your own Chrome, via CLI or MCP. Your logins, extensions, cookies — already there.


其他浏览器 MCP 会启动一个全新的 Chrome —— 没有登录状态、没有扩展程序,瞬间被机器人检测器标记,且内存占用翻倍。而 Playwriter 会连接到**你正在运行的浏览器**。只需一个 Chrome 扩展程序,即可使用完整的 Playwright API,并能访问你已登录的所有内容。 ## 安装说明 1. 从 Chrome Web Store [**安装扩展程序**](https://chromewebstore.google.com/detail/playwriter-mcp/jfeammnjpkecdekppnclgkkffahnhfhe) 2. 在某个标签页上点击扩展程序图标 → 连接成功后会变为绿色 3. 安装 CLI 并开始自动化操作浏览器: npm i -g playwriter playwriter -s 1 -e 'await page.goto("https://example.com")' 4. 安装 skill,让你的 agent 知道如何使用 Playwriter: npx -y skills add remorses/playwriter ## 快速开始 ``` playwriter browser start # starts Chrome for Testing/Chromium with bundled Playwriter extension playwriter session new # creates stateful sandbox, outputs session id (e.g. 1) playwriter -s 1 -e 'await page.goto("https://example.com")' playwriter -s 1 -e 'console.log(await snapshot({ page }))' playwriter -s 1 -e 'await page.locator("aria-ref=e5").click()' ``` ## CLI 用法 每个会话都有**隔离的状态**。浏览器标签页在各会话之间是**共享**的。 ``` # 浏览器管理 playwriter browser start # auto-finds Chrome for Testing or Chromium, with recording flags enabled playwriter browser start /path/to/browser-binary # Session 管理 playwriter session new # creates stateful sandbox, outputs id (e.g. 1) playwriter session list # show sessions + state keys playwriter session reset # fix connection issues # 执行 (始终使用 -s) playwriter -s 1 -e 'await page.goto("https://example.com")' playwriter -s 1 -e 'await page.click("button")' playwriter -s 1 -e 'console.log(await page.title())' ``` 创建你自己的页面,以避免受到其他 agent 的干扰: ``` playwriter -s 1 -e 'state.myPage = await context.newPage(); await state.myPage.goto("https://example.com")' ``` 多行: ``` playwriter -s 1 -e $' const title = await page.title(); console.log({ title, url: page.url() }); ' ``` ## 示例 作用域内的变量:`page`、`context`、`state`(在调用之间持久化)、`require` 以及 Node.js 全局变量。 **在 state 中持久化数据:** ``` playwriter -e "state.users = await page.$$eval('.user', els => els.map(e => e.textContent))" playwriter -e "console.log(state.users)" ``` **拦截网络请求:** ``` playwriter -e "state.requests = []; page.on('response', r => { if (r.url().includes('/api/')) state.requests.push(r.url()) })" playwriter -e "await Promise.all([page.waitForResponse(r => r.url().includes('/api/')), page.click('button')])" playwriter -e "console.log(state.requests)" ``` **设置断点并调试:** ``` playwriter -e "state.cdp = await getCDPSession({ page }); state.dbg = createDebugger({ cdp: state.cdp }); await state.dbg.enable()" playwriter -e "state.scripts = await state.dbg.listScripts({ search: 'app' }); console.log(state.scripts.map(s => s.url))" playwriter -e "await state.dbg.setBreakpoint({ file: state.scripts[0].url, line: 42 })" ``` **实时编辑页面代码:** ``` playwriter -e "state.cdp = await getCDPSession({ page }); state.editor = createEditor({ cdp: state.cdp }); await state.editor.enable()" playwriter -e "await state.editor.edit({ url: 'https://example.com/app.js', oldString: 'const DEBUG = false', newString: 'const DEBUG = true' })" ``` **带标签的截图:** ``` playwriter -e "await screenshotWithAccessibilityLabels({ page })" ``` ## MCP 设置 推荐的做法是配合 skill 使用 CLI(即上述第 4 步)。如需直接配置 MCP 服务器,请参阅 [MCP.md](./MCP.md)。 ## 视觉标签 为 AI agent 提供类似 Vimium 风格的标签,以便识别元素: ``` await screenshotWithAccessibilityLabels({ page }) // Returns screenshot + accessibility snapshot with aria-ref selectors await page.locator('aria-ref=e5').click() ``` 颜色编码:黄色=链接,橙色=按钮,珊瑚色=输入框,粉色=复选框,桃色=滑块,鲑鱼红=菜单,琥珀色=标签页。 ## 对比 ### 对比 Playwright MCP | | Playwright MCP | Playwriter | | ------------- | ----------------- | --------------------------------- | | 浏览器 | 启动新 Chrome | **使用你的 Chrome** | | 扩展程序 | 无 | 保留你现有的扩展 | | 登录状态 | 全新 | 保留已有登录状态 | | 机器人检测 | 总是被检测到 | 可绕过(断开扩展程序连接) | | 协同工作 | 独立窗口 | 与用户使用相同的浏览器 | | | Playwright CLI | Playwriter | | --------------- | ------------------- | ----------------------------- | | 浏览器 | 启动新浏览器 | **使用你的 Chrome** | | 登录状态 | 全新 | 保留已有登录状态 | | 扩展程序 | 无 | 保留你现有的扩展 | | 验证码 | 总是被拦截 | 可绕过(断开扩展程序连接) | | 协同工作 | 独立窗口 | 与用户使用相同的浏览器 | | 功能 | 命令集受限 | Playwright 能做的一切 | | 原生 CDP 访问 | 否 | 是 | | 视频录制 | 基于文件的追踪 | 原生标签页捕获 (30–60fps) | ### 对比 BrowserMCP | | BrowserMCP | Playwriter | | ------------- | ------------------- | ------------------------ | | 工具 | 12+ 个专用工具 | 1 个 `execute` 工具 | | API | 操作受限 | 完整的 Playwright | | Context 占用 | 高(工具 schema) | 低 | | LLM 知识 | 必须学习工具 | 已经掌握 Playwright | ### 对比 Antigravity (Jetski) | | Jetski | Playwriter | | -------- | ---------------------------- | ---------------- | | 工具 | 17+ 个工具 | 1 个工具 | | 子 agent | 为每个浏览器任务生成 | 直接执行 | | 延迟 | 高(agent 开销) | 低 | ### 对比 Claude 浏览器扩展程序 | | Claude 扩展程序 | Playwriter | | -------------------- | -------------------- | ----------------------- | | Agent 支持 | 仅限 Claude | 任何 MCP client | | Windows WSL | 否 | 是 | | Context 方式 | 截图 (100KB+) | A11y 快照 (5-20KB) | | Playwright API | 否 | 完整 | | 调试器/断点 | 否 | 是 | | 实时代码编辑 | 否 | 是 | | 网络拦截 | 受限 | 完整 | | 原生 CDP 访问 | 否 | 是 | ### 对比内置 Chrome CDP (`--remote-debugging-port`) | | 内置 CDP | Playwriter | | --------------------- | ------------------------------------- | ---------------------------- | | 设置 | 需使用特殊标志重启 Chrome | 点击扩展程序图标 | | 确认对话框 | 显示 agent 无法关闭的自动化信息条 | 无阻塞性对话框 | | 自主 agent | 被调试横幅打断 | 完全自主 | | 用户干扰 | 横幅会在工作流中突然出现 | 静默 — 零干扰 | | 现有会话 | 必须重启 Chrome(丢失状态) | 使用你正在运行的浏览器 | ## 架构 ``` +---------------------+ +-------------------+ +-----------------+ | BROWSER | | LOCALHOST | | MCP CLIENT | | | | | | | | +---------------+ | | WebSocket Server | | +-----------+ | | | Extension |<---------> :19988 | | | AI Agent | | | +-------+-------+ | WS | | | +-----------+ | | | | | /extension | | | | | chrome.debugger | | | | | v | | v | | v | | +-----------+ | | +---------------+ | | /cdp/:id <--------------> | execute | | | | Tab 1 (green) | | +-------------------+ WS | +-----------+ | | | Tab 2 (green) | | | | | | | Tab 3 (gray) | | Tab 3 not controlled | Playwright API | +---------------------+ (no extension click) +-----------------+ ``` ## 远程访问 使用 [traforo](https://traforo.dev) 隧道通过互联网控制远程机器上的 Chrome: **在主机上:** ``` npx -y traforo -p 19988 -t my-machine -- npx -y playwriter serve --token ``` **从远程机器:** ``` export PLAYWRITER_HOST=https://my-machine-tunnel.traforo.dev export PLAYWRITER_TOKEN= playwriter -s 1 -e 'await page.goto("https://example.com")' ``` 它也可以在不使用 traforo 的情况下在局域网中工作(`PLAYWRITER_HOST=192.168.1.10`)。包含详细用例(远程 Mac mini、用户支持、多机器控制)的完整指南:[docs/remote-access.md](./docs/remote-access.md) ## 安全性 - **仅限本地**:WebSocket 服务器位于 `localhost:19988` - **Origin 验证**:只允许我们自己的扩展程序 ID(浏览器无法伪造 Origin) - **明确同意**:只有你点击了扩展程序图标的标签页才会被控制 - **可见的自动化**:Chrome 会在受控制的标签页上显示自动化横幅 - **无远程访问**:恶意网站无法连接 ## Playwright API 通过代码连接(无需 CLI): ``` import { chromium } from 'playwright-core' import { startPlayWriterCDPRelayServer, getCdpUrl } from 'playwriter' const server = await startPlayWriterCDPRelayServer() const browser = await chromium.connectOverCDP(getCdpUrl()) const page = browser.contexts()[0].pages()[0] await page.goto('https://example.com') await page.screenshot({ path: 'screenshot.png' }) // Don't call browser.close() - it closes the user's Chrome server.close() ``` 或者连接到正在运行的服务器: ``` npx -y playwriter serve --host 127.0.0.1 ``` ``` const browser = await chromium.connectOverCDP('http://127.0.0.1:19988') ``` ## 故障排除 查看中继服务器日志以调试问题: ``` playwriter logfile # prints the log file path # 通常为: ~/.playwriter/relay-server.log ``` 中继日志包含扩展程序、MCP 和 WebSocket 服务器日志。旁边还会创建一个单独的 CDP JSONL 日志(参见 `playwriter logfile`)。两者都会在每次服务器启动时重新创建。 示例:按方向和 method 汇总 CDP 流量计数: ``` jq -r '.direction + "\t" + (.message.method // "response")' ~/.playwriter/cdp.jsonl | uniq -c ``` ## 支持 如果 Playwriter 对你有帮助,请考虑[赞助本项目](https://github.com/sponsors/remorses)。 ## 已知问题 - 如果所有页面都返回 `about:blank`,请重启 Chrome(这是 `chrome.debugger` API 中的 Chrome bug) - 连接时浏览器可能会切换到浅色模式([Playwright issue](https://github.com/microsoft/playwright/issues/37627))
标签:AI智能体, MCP, MITM代理, Playwright, 后端开发, 浏览器自动化, 特征检测