browser-harness 浏览器自动化工具手册
目标与边界
做:
- 用 browser-harness 连接本机 Chrome,完成:打开网页、抓取页面、整站抓取、登录、点击输入、截图、执行 JS
- 配合 agent_helpers.py 的封装工具(grab_page / crawl_site / login_form)高效抓站
- 工作流:agent 判断 + browser-harness 执行 + 豆包看截图
不做:
- ❌ 不依赖外部 LLM API(browser-harness 本身不需要任何模型 key)
- ❌ 不直接抄网站源码(复刻 = 观察设计重新实现,注意版权)
- ❌ 不替代 DSH 插件开发(那是 dsh-plugin-development 的职责)
环境速查
| 项 |
值 |
| 项目目录 |
<你的目录>\browser-harness-main(克隆自 github.com/browser-use/browser-harness) |
| 命令 |
~/.local/bin/browser-harness(uv tool install 后) |
| 调试 Chrome |
端口 9222,profile <你的目录>\bh-chrome-profile |
| 连接环境变量 |
BU_CDP_URL=http://127.0.0.1:9222 |
| agent 扩展 |
agent-workspace\agent_helpers.py(每次运行自动加载) |
工作流程
1. 启动调试 Chrome(如果 9222 未运行)
# 先探测:curl http://127.0.0.1:9222/json/version 返回 200 = 已运行
# 未运行则启动(后台):
$chrome = "$env:ProgramFiles\Google\Chrome\Application\chrome.exe"
$profile = "$env:USERPROFILE\bh-chrome-profile"
Start-Process -FilePath $chrome -ArgumentList "--remote-debugging-port=9222","--user-data-dir=$profile","--no-first-run","about:blank" -WindowStyle Minimized
Start-Sleep -Seconds 4
2. 调用 browser-harness(stdin 传 Python 代码)
$env:BU_CDP_URL = "http://127.0.0.1:9222"
$code = @'
new_tab("https://example.com")
wait_for_load()
print(page_info())
'@
$code | & "$env:USERPROFILE\.local\bin\browser-harness"
输出编码铁律:任何脚本开头必须执行,否则遇到特殊字符会崩溃:
import sys
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
3. 基础函数(helpers.py 预置)
| 函数 |
作用 |
new_tab(url) / goto_url(url) |
开新标签 / 当前标签导航(goto 用完整 URL,相对路径会报错) |
page_info() |
返回 {url, title, w, h, sx, sy, pw, ph} |
js(expression) |
在页面执行 JS 并返回结果(最强大的函数) |
fill_input(selector, text) |
填输入框(对 React 受控组件无效,见坑 2) |
click_at_xy(x, y) / type_text(text) / press_key(key) |
鼠标/键盘 |
capture_screenshot(path) |
截图 |
wait(sec) / wait_for_load() / wait_for_element(sel) |
等待 |
list_tabs() / switch_tab(target) |
标签页管理 |
upload_file(selector, path) / http_get(url) |
上传 / HTTP 请求 |
cdp(method, **params) |
底层 CDP 原语 |
4. agent_helpers.py 封装工具(整站抓取)
| 工具 |
调用 |
返回/落盘 |
grab_page(url) |
d = grab_page("https://...") |
dict:url/title/text/inputs/buttons/links/selects/tables/scripts |
crawl_site(urls, out_dir) |
crawl_site(["https://a.com","https://a.com/b"], r"D:\out") |
逐页落盘 JSON(ensure_ascii=True) |
login_form(url, user, pwd) |
login_form("https://a.com/auth", "u", "p") |
填前两个 input + 点"登录"按钮,返回登录后 URL |
标准抓站流程:
import sys
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
login_form("https://site.com/auth?mode=login", "user", "pass")
crawl_site(["https://site.com/", "https://site.com/pricing"], r"D:\out")
5. 复刻网页的标准做法
- 用
js("document.body.innerText") 抓文本、js("[...document.querySelectorAll('a')]...") 抓链接
- 用
getComputedStyle 抓 2-3 个关键颜色/字体/侧边栏宽度(不要抄源码)
- 观察设计 → 重新手写 HTML/CSS/JS(类名、结构、样式全自己写,内容/数据可以来自页面)
- Chrome headless 截图验证 + 豆包识图检查渲染
常见坑(必须遵守)
- goto_url 必须完整 URL:
goto_url("/pricing") 报 "Cannot navigate to invalid URL",要 goto_url("https://site.com/pricing")
- React 受控表单:
fill_input 找不到元素或填不进去 → 用原生 setter:const setVal=(el,v)=>{const s=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set;s.call(el,v);el.dispatchEvent(new Event('input',{bubbles:true}));el.dispatchEvent(new Event('change',{bubbles:true}));};
- JS 返回 surrogate 字符(emoji 等)会让 stdout/stderr 崩溃 → 开头 reconfigure 两个流;数据量大时用
json.dump(..., ensure_ascii=True) 落盘而非 print
- agent_helpers.py 是独立模块:内部函数引用基础函数必须显式
from browser_harness.helpers import goto_url, wait_for_load, wait, js, page_info(helpers 的注入是单向的)
- browser-harness 输出缓冲:PowerShell 里不要用
Select-Object -Last N 管道包住耗时命令(会缓冲到结束才显示,像卡死)
- spa 页面:
wait_for_load() 后加 wait(2-3) 等渲染,必要时抓 document.body.innerText 二次确认
输出模板(整站分析报告)
# {站点名} 全面解析({页面名})
- URL / 标题 / 访问要求
- 页面结构(布局图)
- 核心数据(表格化)
- 功能模块解析
- 技术特征(框架/脚本/第三方)
- 业务逻辑要点
- 安全与隐私提醒(敏感信息脱敏)
- 备注
维护
- 修改
agent-workspace\agent_helpers.py 后下次运行自动生效(editable 安装),无需重装
- 更新 browser-harness:
browser-harness --update -y
- 诊断:
browser-harness --doctor(chrome/daemon/连接状态)
1---2name: browser-harness3description: 用 browser-harness(CDP 直连 Chrome)控制浏览器完成网页自动化任务的完整手册。当用户要求打开网页、抓取网站内容、登录网站、分析页面、浏览器自动化、复刻网页、爬数据时使用。 The complete manual for driving a real browser with browser-harness (CDP straight to Chrome) to finish web automation tasks. Use when the user asks to open pages, scrape site content, log in to a site, analyze a page, automate the browser, clone a web page, or crawl data.4---56# browser-harness 浏览器自动化工具手册78## 目标与边界910**做**:11- 用 browser-harness 连接本机 Chrome,完成:打开网页、抓取页面、整站抓取、登录、点击输入、截图、执行 JS12- 配合 agent_helpers.py 的封装工具(grab_page / crawl_site / login_form)高效抓站13- 工作流:**agent 判断 + browser-harness 执行 + 豆包看截图**1415**不做**:16- ❌ 不依赖外部 LLM API(browser-harness 本身不需要任何模型 key)17- ❌ 不直接抄网站源码(复刻 = 观察设计重新实现,注意版权)18- ❌ 不替代 DSH 插件开发(那是 dsh-plugin-development 的职责)1920## 环境速查2122| 项 | 值 |23|---|---|24| 项目目录 | `<你的目录>\browser-harness-main`(克隆自 github.com/browser-use/browser-harness) |25| 命令 | `~/.local/bin/browser-harness`(uv tool install 后) |26| 调试 Chrome | 端口 **9222**,profile `<你的目录>\bh-chrome-profile` |27| 连接环境变量 | `BU_CDP_URL=http://127.0.0.1:9222` |28| agent 扩展 | `agent-workspace\agent_helpers.py`(每次运行自动加载) |2930## 工作流程3132### 1. 启动调试 Chrome(如果 9222 未运行)3334```powershell35# 先探测:curl http://127.0.0.1:9222/json/version 返回 200 = 已运行36# 未运行则启动(后台):37$chrome = "$env:ProgramFiles\Google\Chrome\Application\chrome.exe"38$profile = "$env:USERPROFILE\bh-chrome-profile"39Start-Process -FilePath $chrome -ArgumentList "--remote-debugging-port=9222","--user-data-dir=$profile","--no-first-run","about:blank" -WindowStyle Minimized40Start-Sleep -Seconds 441```4243### 2. 调用 browser-harness(stdin 传 Python 代码)4445```powershell46$env:BU_CDP_URL = "http://127.0.0.1:9222"47$code = @'48new_tab("https://example.com")49wait_for_load()50print(page_info())51'@52$code | & "$env:USERPROFILE\.local\bin\browser-harness"53```5455**输出编码铁律**:任何脚本开头必须执行,否则遇到特殊字符会崩溃:56```python57import sys58sys.stdout.reconfigure(encoding="utf-8", errors="replace")59sys.stderr.reconfigure(encoding="utf-8", errors="replace")60```6162### 3. 基础函数(helpers.py 预置)6364| 函数 | 作用 |65|---|---|66| `new_tab(url)` / `goto_url(url)` | 开新标签 / 当前标签导航(goto 用完整 URL,相对路径会报错) |67| `page_info()` | 返回 {url, title, w, h, sx, sy, pw, ph} |68| `js(expression)` | 在页面执行 JS 并返回结果(最强大的函数) |69| `fill_input(selector, text)` | 填输入框(**对 React 受控组件无效**,见坑 2) |70| `click_at_xy(x, y)` / `type_text(text)` / `press_key(key)` | 鼠标/键盘 |71| `capture_screenshot(path)` | 截图 |72| `wait(sec)` / `wait_for_load()` / `wait_for_element(sel)` | 等待 |73| `list_tabs()` / `switch_tab(target)` | 标签页管理 |74| `upload_file(selector, path)` / `http_get(url)` | 上传 / HTTP 请求 |75| `cdp(method, **params)` | 底层 CDP 原语 |7677### 4. agent_helpers.py 封装工具(整站抓取)7879| 工具 | 调用 | 返回/落盘 |80|---|---|---|81| `grab_page(url)` | `d = grab_page("https://...")` | dict:url/title/text/inputs/buttons/links/selects/tables/scripts |82| `crawl_site(urls, out_dir)` | `crawl_site(["https://a.com","https://a.com/b"], r"D:\out")` | 逐页落盘 JSON(`ensure_ascii=True`) |83| `login_form(url, user, pwd)` | `login_form("https://a.com/auth", "u", "p")` | 填前两个 input + 点"登录"按钮,返回登录后 URL |8485**标准抓站流程**:86```python87import sys88sys.stdout.reconfigure(encoding="utf-8", errors="replace")89sys.stderr.reconfigure(encoding="utf-8", errors="replace")90login_form("https://site.com/auth?mode=login", "user", "pass")91crawl_site(["https://site.com/", "https://site.com/pricing"], r"D:\out")92```9394### 5. 复刻网页的标准做法95961. 用 `js("document.body.innerText")` 抓文本、`js("[...document.querySelectorAll('a')]...")` 抓链接972. 用 `getComputedStyle` 抓 2-3 个关键颜色/字体/侧边栏宽度(**不要抄源码**)983. **观察设计 → 重新手写 HTML/CSS/JS**(类名、结构、样式全自己写,内容/数据可以来自页面)994. Chrome headless 截图验证 + 豆包识图检查渲染100101## 常见坑(必须遵守)1021031. **goto_url 必须完整 URL**:`goto_url("/pricing")` 报 "Cannot navigate to invalid URL",要 `goto_url("https://site.com/pricing")`1042. **React 受控表单**:`fill_input` 找不到元素或填不进去 → 用原生 setter:105 ```js106 const setVal=(el,v)=>{const s=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set;s.call(el,v);el.dispatchEvent(new Event('input',{bubbles:true}));el.dispatchEvent(new Event('change',{bubbles:true}));};107 ```1083. **JS 返回 surrogate 字符**(emoji 等)会让 stdout/stderr 崩溃 → 开头 reconfigure 两个流;数据量大时用 `json.dump(..., ensure_ascii=True)` 落盘而非 print1094. **agent_helpers.py 是独立模块**:内部函数引用基础函数必须显式 `from browser_harness.helpers import goto_url, wait_for_load, wait, js, page_info`(helpers 的注入是单向的)1105. **browser-harness 输出缓冲**:PowerShell 里不要用 `Select-Object -Last N` 管道包住耗时命令(会缓冲到结束才显示,像卡死)1116. **spa 页面**:`wait_for_load()` 后加 `wait(2-3)` 等渲染,必要时抓 `document.body.innerText` 二次确认112113## 输出模板(整站分析报告)114115```markdown116# {站点名} 全面解析({页面名})117- URL / 标题 / 访问要求118- 页面结构(布局图)119- 核心数据(表格化)120- 功能模块解析121- 技术特征(框架/脚本/第三方)122- 业务逻辑要点123- 安全与隐私提醒(敏感信息脱敏)124- 备注125```126127## 维护128129- 修改 `agent-workspace\agent_helpers.py` 后**下次运行自动生效**(editable 安装),无需重装130- 更新 browser-harness:`browser-harness --update -y`131- 诊断:`browser-harness --doctor`(chrome/daemon/连接状态)