remorses/playwriter
GitHub: remorses/playwriter
Playwriter 让 AI agent 通过 Chrome 扩展和 CLI/MCP 直接控制用户正在运行的浏览器,保留完整登录状态与扩展,实现低干扰的浏览器自动化。
Stars: 3715 | Forks: 164
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, 后端开发, 浏览器自动化, 特征检测