Files
docs/browser-harness-guide.md
T

512 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Browser Harness 使用指南:连接 AI 与真实浏览器
> 官方仓库:[browser-use/browser-harness](https://github.com/browser-use/browser-harness)
>
> 组织:Browser Use
>
> 设计哲学:最薄、最小、最强的 Agent 浏览器控制层
---
## 一、项目背景
Browser Harness 是一个极薄的 CDPChrome DevTools Protocol)桥接层,让 AI 编程助手(Claude Code、Codex、Hermes Agent 等)**直接操控你的真实浏览器**。它不做任何高层抽象 — 就是一条 WebSocket 连到 Chrome,中间什么都没有。
核心理念来自 [The Bitter Lesson of Agent Harnesses](https://browser-use.com/posts/bitter-lesson-agent-harnesses)
> "Agent 需要的不是一个全功能的浏览器自动化框架,而是一根足够细的管道 — 能传递点击和截图就够了。"
### 与传统工具的区别
| 特性 | Browser Harness | Playwright / Puppeteer | Selenium |
|------|-----------------|------------------------|----------|
| 代码量 | ~1000 行(4 个文件) | 数十万行 | 数十万行 |
| 浏览器 | 连接你的真实 Chrome | 启动独立浏览器 | 启动独立浏览器 |
| 登录态 | 直接用你的 Cookie / Session | 需要手动注入或重新登录 | 需要手动注入或重新登录 |
| 扩展/书签 | 全部可用 | 无 | 无 |
| AI Agent 编辑 | Agent 可直接改 helper 代码 | 不能 | 不能 |
| 跨 iframe / Shadow DOM | 坐标点击天然穿透 | 需要切换 context | 需要切换 context |
### 架构(~1000 行代码)
```
Chrome / Browser Use Cloud → CDP WebSocket → daemon(长驻进程)→ IPC → browser-harness CLI
```
四个核心文件:
| 文件 | 作用 |
|------|------|
| `run.py` | CLI 入口,负责解析命令、启动 daemon、执行 Python 片段 |
| `daemon.py` | 长驻中间层进程,管理 CDP 连接生命周期 |
| `helpers.py` | CDP 封装 + 核心浏览器原语(截图、点击、导航、JS 执行) |
| `admin.py` | daemon 生命周期管理、诊断、更新、云浏览器管理 |
Agent 只能编辑 `agent-workspace/` 下的内容:
- `agent_helpers.py` — 任务特定的辅助函数
- `domain-skills/` — 可复用的站点技能(社区贡献)
---
## 二、安装
### 前置要求
- Python >= 3.11
- `uv`(推荐,Python 包管理器)或 `pip`
- Chrome / Chromium 浏览器
- Git
### 推荐安装方式(uv tool,全局可用)
```bash
# 1. 克隆到持久目录(推荐 ~/Developer/,不要放 /tmp
git clone https://github.com/browser-use/browser-harness
cd browser-harness
# 2. 用 uv tool 安装为可编辑的全局命令
uv tool install -e .
# 3. 验证
command -v browser-harness
# 输出: /home/user/.local/bin/browser-harness
```
> **为什么用 `-e`editable)?** Agent 在运行时会往 `agent-workspace/agent_helpers.py` 中写自定义 helpereditable 安装保证下次调用 `browser-harness` 立即使用新代码,无需重新安装。
### 备选安装方式(pip
```bash
git clone https://github.com/browser-use/browser-harness
cd browser-harness
pip install -e .
```
### 平台支持
| 平台 | 状态 | 备注 |
|------|------|------|
| Linux | ✅ 完全支持 | Socket: `/tmp/bu-<NAME>.sock` |
| macOS | ✅ 完全支持 | Socket: `/tmp/bu-<NAME>.sock` |
| Windows | ✅ 支持 | IPC 使用 TCP loopback + port file |
### 各平台安装注意事项
**macOS**
```bash
# Chrome 路径
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome
# 一键打开 chrome://inspect 页面
osascript -e 'tell application "Google Chrome" to activate' \
-e 'tell application "Google Chrome" to open location "chrome://inspect/#remote-debugging"'
```
**Windows**
```bash
# Chrome 路径
"C:\Program Files\Google\Chrome\Application\chrome.exe"
# 安装后确保 %USERPROFILE%\.local\bin 在 PATH 中
```
**Linux**
```bash
# Chrome 通常已通过包管理器安装
google-chrome
# 非标准安装路径
/usr/bin/google-chrome
/opt/google/chrome/chrome
```
### 注册为 Agent 的全局 Skill(可选)
安装后,让 AI Agent 在任何项目中都能使用 Browser Harness
**Claude Code** — 在 `~/.claude/CLAUDE.md` 中添加:
```markdown
@~/Developer/browser-harness/SKILL.md
```
**Codex** — 创建符号链接:
```bash
mkdir -p ~/.codex/skills/browser-harness
ln -sf ~/Developer/browser-harness/SKILL.md ~/.codex/skills/browser-harness/SKILL.md
```
---
## 三、浏览器连接
Browser Harness 连接浏览器有两种方式:
### Way 1chrome://inspect 复选框(推荐日常使用)
**连接到你的真实 Chrome,继承所有登录态、扩展、书签。**
1. 在 Chrome 地址栏输入 `chrome://inspect/#remote-debugging`
2. 勾选 "Allow remote debugging for this browser instance"
3. 此设置是**每个 Profile 一次性的**,勾选后该 Profile 的每次启动都默认开启
Chrome 144+ 首次连接时会弹出 "Allow remote debugging?" 确认框,点击 Allow 即可。
**优点**:直接用你的真实浏览器,Cookie、Session、扩展全部生效。
**缺点**:偶尔需要手动点击 Allow 弹窗。
### Way 2:命令行启动(推荐自动化/无头场景)
**启动独立的 Chrome 实例,无弹窗,适合无人值守。**
```bash
# Linux / macOS
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-bh
# macOS(完整路径)
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
--remote-debugging-port=9222 \
--user-data-dir=/tmp/chrome-bh
# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" ^
--remote-debugging-port=9222 ^
--user-data-dir=%TEMP%\chrome-bh
```
> **重要**`--user-data-dir` 必须指向**非默认 Profile 目录**。指向默认目录(如 `~/.config/google-chrome`)时,Chrome 136+ 会**静默忽略** `--remote-debugging-port` 参数。
告诉 Harness 连接哪个端口:
```bash
# 环境变量方式
export BU_CDP_URL=http://127.0.0.1:9222
browser-harness <<'PY'
print(page_info())
PY
# 或者内联
BU_CDP_URL=http://127.0.0.1:9222 browser-harness <<'PY'
print(page_info())
PY
```
### Headless 模式(E10 等企业系统自动化专用)
启动独立 headless Chrome
```bash
google-chrome --headless=new \
--remote-debugging-port=9223 \
--user-data-dir=/tmp/bh-e10 \
--no-first-run --no-default-browser-check \
--window-size=1920,1080
```
然后所有 browser-harness 命令加上端口前缀:
```bash
export BU_CDP_URL=http://127.0.0.1:9223 && browser-harness <<'PY'
new_tab("https://example.com/login")
wait_for_load()
PY
```
> ⚠️ **关键**`export` 和 `browser-harness` 必须在**同一行**。daemon 是独立进程,不会继承后续 shell 的环境变量。
---
## 四、基本使用
### 第一个命令
```bash
browser-harness <<'PY'
print(page_info())
PY
```
输出当前标签页的 URL 和标题。
### 导航
```bash
browser-harness <<'PY'
# 打开新标签页(首选方式,不会覆盖用户当前标签)
new_tab("https://github.com")
wait_for_load()
# 获取页面信息
print(page_info())
PY
```
> **new_tab() vs goto_url()**:第一次导航总是用 `new_tab()`。`goto_url()` 会在用户当前活跃标签页中导航,可能覆盖用户正在看的内容。
### 截图(最核心的反馈方式)
```bash
browser-harness <<'PY'
capture_screenshot("/tmp/page.png")
PY
```
截图是验证操作结果的首选方式 — 比 DOM 检查更快、更直观。
### 坐标点击(穿透 iframe / Shadow DOM
```bash
browser-harness <<'PY'
# 用截图找到目标坐标后直接点击
click_at_xy(500, 300)
wait_for_load()
capture_screenshot("/tmp/after_click.png")
PY
```
坐标点击经由 Chrome 浏览器的合成器层(compositor level)派发 `Input.dispatchMouseEvent`,天然穿透 iframe、Shadow DOM 和跨域边界。**不需要切换 context。**
> **工作流**`capture_screenshot()` → 看图找坐标 → `click_at_xy(x, y)` → `capture_screenshot()` 验证。这是 Browser Harness 推荐的操作模式,而非 Playwright 风格的 "先定位再点击"。
### JS 执行(DOM 读取和复杂逻辑)
```bash
browser-harness <<'PY'
# 读取页面内容
content = js("document.body.innerText")
print(content[:500])
# 提取结构化数据
import json
links = json.loads(js('''
var all = document.querySelectorAll("a");
var result = [];
for (var i = 0; i < all.length; i++) {
if (all[i].href) result.push({text: all[i].textContent.trim(), href: all[i].href});
}
return JSON.stringify(result);
'''))
for l in links:
print(l["text"], "->", l["href"])
PY
```
### 表单填充(native setter 方式)
React/Vue 等框架的受控组件不接受直接的 `.value = "..."` 赋值。需要使用原生 setter + 事件派发:
```bash
browser-harness <<'PY'
# 注入通用 fillInput 函数
js('''
var ns = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
window.__fi = function(selector, value) {
var el = document.querySelector(selector);
el.focus();
ns.call(el, value);
el.dispatchEvent(new Event("input", { bubbles: true }));
el.dispatchEvent(new Event("change", { bubbles: true }));
el.dispatchEvent(new Event("blur", { bubbles: true }));
};
''')
js('window.__fi("#username", "myuser")')
js('window.__fi("#password", "mypass")')
PY
```
### 原始 CDP 调用
需要 helpers.py 没有封装的功能时,直接调 CDP 协议:
```bash
browser-harness <<'PY'
# 清空浏览器缓存
cdp("Network.clearBrowserCache")
# 设置 Cookie
cdp("Network.setCookie", {"name": "token", "value": "abc123", "domain": "example.com"})
PY
```
---
## 五、核心 Helpers 速查
浏览器启动时自动导入的 helpers:
| Helper | 功能 |
|--------|------|
| `new_tab(url)` | 打开新标签页并导航 |
| `goto_url(url)` | 在当前标签页导航(谨慎使用) |
| `wait_for_load()` | 等待页面加载完成 |
| `capture_screenshot(path)` | 截图保存为 PNG**需要传 path 参数** |
| `click_at_xy(x, y)` | 坐标点击(穿透所有层级) |
| `js(code)` | 在页面中执行 JavaScript 并返回结果 |
| `page_info()` | 返回当前 URL 和标题 |
| `switch_tab(target)` | 切换到指定标签页 |
| `cdp(method, params)` | 直接调用 CDP 协议方法 |
| `http_get(url)` | 并发 HTTP GET(适合批量请求静态页面) |
| `ensure_real_tab()` | 确保当前连接的是真实标签页(排除 Chrome 内部页) |
---
## 六、Interaction Skills(交互技能)
`interaction-skills/` 目录下包含可复用的交互模式文档:
| 技能 | 内容 |
|------|------|
| `screenshots.md` | 截图策略 |
| `tabs.md` | 标签页管理 |
| `dialogs.md` | 弹窗处理(alert/confirm/prompt |
| `dropdowns.md` | 下拉框交互 |
| `iframes.md` | iframe 内操作 |
| `cross-origin-iframes.md` | 跨域 iframe 处理 |
| `shadow-dom.md` | Shadow DOM 穿透 |
| `uploads.md` | 文件上传 |
| `downloads.md` | 文件下载 |
| `drag-and-drop.md` | 拖拽操作 |
| `scrolling.md` | 页面滚动 |
| `cookies.md` | Cookie 管理 |
| `network-requests.md` | 网络请求拦截 |
| `print-as-pdf.md` | 网页转 PDF |
| `viewport.md` | 视口调整 |
---
## 七、Cloud 浏览器(Browser Use Cloud
Browser Use 提供免费云浏览器(3 个并发浏览器,无需绑卡):
```bash
# 设置 API Key
export BROWSER_USE_API_KEY="your-key"
# 启动远程 daemon
browser-harness <<'PY'
start_remote_daemon("work")
PY
# 使用
BU_NAME=work browser-harness <<'PY'
new_tab("https://example.com")
print(page_info())
PY
```
**云浏览器特性**
- Stealth 模式(绕过反爬检测)
- 代理支持(`proxyCountryCode="de"`
- Profile 持久化(`profileName="my-work"` — 登录态保持)
- 本地 Profile 同步(`sync_local_profile("MyChromeProfile")` 上传 Cookie
---
## 八、Agent 自进化:写好 Helper,下次直接用
Browser Harness 的设计允许 Agent 在执行过程中**自我改进**。当遇到 `helpers.py` 没有的功能时:
```python
# 在 agent-workspace/agent_helpers.py 中添加
def fill_form_selectors(fields: dict):
"""填表:fields = {'#username': 'john', '#password': '***'}"""
ns = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value").set
for selector, value in fields.items():
el = document.querySelector(selector)
el.focus()
ns.call(el, value)
el.dispatchEvent(new Event("input", {"bubbles": true}))
```
下次调用 `browser-harness` 时(因为是 `-e` editable 安装),新 helper 自动可用。
---
## 九、日常维护
```bash
# 诊断当前状态
browser-harness --doctor
# 更新到最新版(每天检查一次,有更新时自动提示)
browser-harness --update -y
# 重启 daemon
browser-harness <<'PY'
restart_daemon()
PY
```
---
## 十、故障排查
### Daemon 不响应
```bash
# 清理残留的 daemon
pkill -f browser_harness.daemon
rm -f /tmp/bu-*.sock /tmp/bu-*.pid
# 重新启动
browser-harness <<'PY'
restart_daemon()
PY
```
### Chrome 远程调试未开启
```bash
browser-harness --doctor
# 看 "chrome running" 和 "daemon alive" 两行
```
- **chrome FAIL**Chrome 没运行。Way 1 让用户打开 ChromeWay 2 自己启动。
- **chrome ok, daemon FAIL**Chrome 运行了但远程调试没开。去 `chrome://inspect/#remote-debugging` 勾选复选框。
### macOS:一键打开 chrome://inspect
```bash
osascript -e 'tell application "Google Chrome" to activate' \
-e 'tell application "Google Chrome" to open location "chrome://inspect/#remote-debugging"'
```
### Windows:环境变量设置
```powershell
# PowerShell
$env:BU_CDP_URL = "http://127.0.0.1:9222"
# CMD
set BU_CDP_URL=http://127.0.0.1:9222
```
### 环境变量陷阱
`export BU_CDP_URL=...` 然后下一行 `browser-harness` **不会生效**。daemon 是独立进程,不继承后续 shell 环境变量。必须:
```bash
# ✓ 正确
export BU_CDP_URL=http://127.0.0.1:9222 && browser-harness <<'PY'
...
PY
# ✗ 错误
export BU_CDP_URL=http://127.0.0.1:9222
browser-harness <<'PY' # daemon 拿不到 BU_CDP_URL
...
PY
```
---
## 十一、相关资源
- 官方仓库:[github.com/browser-use/browser-harness](https://github.com/browser-use/browser-harness)
- 设计哲学:[The Bitter Lesson of Agent Harnesses](https://browser-use.com/posts/bitter-lesson-agent-harnesses)
- Cloud 浏览器:[cloud.browser-use.com](https://cloud.browser-use.com)
- 官方文档:[docs.browser-use.com](https://docs.browser-use.com)
---
> 最后更新:2026-06-01
> 基于 Browser Harness v0.1.0