mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-10-31 14:27:30 +00:00
用户报告截图不对(此前已改为落盘返回路径)。查下去发现**两个叠加的问题**,
其中一个是既有的、与上次改动无关的严重缺陷。
## ① 协议解析失败:chromedp v0.9.5 不认 Chrome 154
```
ERROR: could not unmarshal event: parse error: expected string near offset 411 of 'cookiePart...'
```
cdproto 把 `partitionKey` 定义为 `string`,而 Chrome 154 已改成对象
(`cookiePartitionKey`)。新版 cdproto 定义了 `CookiePartitionKey` 结构体,
且 `UnmarshalJSON` **双向兼容**(字符串 → 结构体,旧浏览器也不坏)。
副作用:`Navigate` 从 2.5s 降到 85ms(解析错误消失,不再反复重试)。
## ② 视口截图在 headless 下**永远挂住**(既有缺陷,不是升级引入)
`Screenshot(sel)` 内部是 `QueryAfter` + `NodeVisible`,而 NodeVisible 在
headless Chromium 上永远不满足 —— 两步单独看都成功,但它一直等下去:
```
Do(Query body) ✓ Do(WaitReady body) ✓
Do(WaitVisible body) ✗挂住 Do(WaitVisible html) ✗挂住
Run(Screenshot html) ✗挂住 Run(FullScreenshot) ✓
Run(CaptureScreenshot) ✓(70KB)
```
**决定性对照:旧版 chromedp v0.9.5 在同一个后端上同样挂。**
所以这不是升级引入的。生产日志也佐证:
- 成功的 8 次 —— agent 都传了 `full:true`(走 FullScreenshot)
- 超时的 5 次 —— 都是默认分支(走 Screenshot("body"))
且 `NodeVisible` 的两步实测都正常(`dom.GetBoxModel` 300µs 成功、
`visibleJS` 返回 true / offsetWidth=480),就是等待机制本身不返回。
没有深挖到 chromedp 内部的根因,但**换用 `CaptureScreenshot` 完全绕开这条链**,
且语义更对:「不传 full 就只截当前视口」本来就是 API 文档的含义。
## 迁移方式:兼容层收敛,业务代码最小改动
v0.20 是**泛型重写**(`Action[T]` 返回值而不填指针),25 处调用点受影响。
新增 `chromedp_compat.go` 把新 API 收敛成几个小助手
(`chromedpDo` / `newRemoteAllocator` / `chromedpCaptureScreenshot` …),
业务代码保持旧写法。
为何不逐处改:20+ 处机械改写会把 diff 淹没,真正要审的
「行为变了没有」反而看不清。
`NewRemoteAllocator` 在 v0.20 移到了独立子模块 `remote`(核心模块现在
只用标准库 + cdproto,需要 websocket 的东西全部搬出去)。
## 顺带修掉 go.mod 的重复 replace
`go mod tidy` 清掉了 4 条重复的 `replace ... => ../../`(hmapdev 往已有
go.mod 追加却不去重导致的)。Go 容忍它,但 `go mod tidy` 会报错。
## 判据(可杀变异,实测)
`chromedp_compat_test.go`:
- 视口截图必须走 `CaptureScreenshot`,不得退回 `Screenshot(sel)`
(改回挂住的写法 → FAIL ×2)
- 兼容层关键助手都在(去掉 CaptureScreenshot → build FAIL)
- 无旧式「传指针接收截图」残留
全部 20 个 example `go vet` 通过;SDK 根 module build/test 通过。
生产实测:agent 做视口截图返回
`/home/newqqagent/browser_screenshots/shot-20261011-104225.610-browser_1.png`
(1280×713 PNG / 70518 字节),不再超时。
Co-authored-by: JianFeeeee <JianFeeeee@users.noreply.gitcode.com>
browser · 统一浏览器
一个插件覆盖三种"访问网页"的能力,从最轻到最重。按需选层是这个插件的重点 —— 绝大多数抓取用 HTTP 就够,不该为了一句话启动 Chromium。
三种能力层
| 层 | 工具 | 何时用 |
|---|---|---|
| 搜索 | browser_search |
要的是"找到哪些页面",不是页面本身 |
| quick(纯 HTTP) | browser_fetch(mode=quick) |
静态页、API、能直接拿到 HTML |
| normal(无头渲染) | browser_render / browser_fetch(mode=render) |
JS 渲染的页面,HTTP 拿不到内容 |
| interactive(CDP) | browser_start + navigate/click/type/scroll/html/screenshot |
需要交互:登录、点按、翻页 |
browser_fetch 的 mode:
auto(默认):先试 HTTP,遇 403/429 才降级用 Chromium 渲染render:强制 Chromiumquick:纯 HTTP,不降级
工具
| 工具 | 说明 |
|---|---|
browser_search |
网页搜索 |
browser_fetch |
抓取 URL 内容,三种 mode 见上 |
browser_render |
无头 Chromium 渲染并提取文本(normal) |
browser_start |
启动交互式浏览器会话(CDP) |
browser_navigate |
导航到指定 URL |
browser_click |
点击元素 |
browser_type |
输入文本 |
browser_scroll |
滚动页面 |
browser_html |
取当前页 HTML |
browser_screenshot |
截图,保存为 PNG 并返回路径(拿 path 调 describe_image / ocr_image) |
browser_install |
安装 systemd 托管的共享浏览器后端 |
browser_close |
关闭会话 |
共享浏览器后端
browser_install 安装 homeagent-browser.service(systemd 托管)。
装上之后所有 agent 共享同一个 Chromium 实例与登录态,各自占独立标签页互不干扰
(同 source 复用自己的标签页)。
前提:本机已有 chromium 二进制,没有会提示先装(apt install chromium 或等价)。
实现要点
- 搜索用
cn.bing.com而不是www.bing.com:后者对程序化请求常回 302(同意/重定向页), 根本拿不到结果块。 - 标题取
<h2>里的<a>:直接抓结果块里第一个<a>会拿到来源行而非标题。 - 摘要认
b_lineclamp:旧版 Bing 用b_caption,新版已迁走,两套都匹配。 - 有 SSRF 防护:见源码
SSRF段,抓取前校验目标地址,避免被诱导访问内网。
测试
go test -count=1 ./...
testdata/bing_cn.html 是搜索解析的固定样本,用它做离线断言,避免测试依赖真实网络。
构建
hmapdev build