公开页抓取改为 Chrome 136 自洽身份 + 每节点 SQLite 养罐,Trafilatura 走 curl_cffi;MCP/README/接手说明与 09-02 现网复测对齐,避免消费方继续抄过期的站点三分表。 Co-authored-by: Cursor <cursoragent@cursor.com>
127 lines
7 KiB
Markdown
127 lines
7 KiB
Markdown
# onesvm-browser-server
|
||
|
||
面向智能体的**自构建联网搜索服务**:消费者拿一把 `X-Service-Token`,用 MCP(主)或 HTTP(兜底)调用 `search` / `read`。国内直连,国外走自有代理池,query **不经过** Tavily / Jina 等境外 SaaS。
|
||
|
||
现网入口:`http://192.168.1.51:8640`(MCP `POST /mcp`,HTTP `POST /v1/search` `/v1/read`)。
|
||
|
||
| 你是谁 | 先读 |
|
||
|---|---|
|
||
| 消费方(Vlepontas / EAI) | [`docs/mcp-usage-20260901.md`](docs/mcp-usage-20260901.md) → [`docs/integration-vlepontas-20260901.md`](docs/integration-vlepontas-20260901.md) |
|
||
| 接手开发 | [`docs/dev-handoff-20260902.md`](docs/dev-handoff-20260902.md)(本文下面是设计与选型摘要) |
|
||
| 改架构 / 拍板 | [`docs/plan-final-20260901.md`](docs/plan-final-20260901.md)(决策权威)→ [`docs/design-arch-20260901.md`](docs/design-arch-20260901.md)(机制权威) |
|
||
|
||
---
|
||
|
||
## 1. 要解决什么问题
|
||
|
||
智能体需要「上网查公开页」。买境外 SaaS 会把 query 送出境,且按次计费;自建浏览器集群又容易把整机内存和出口 IP 打爆。本仓的约束是:
|
||
|
||
- **境内闭环**:搜索与精读默认不经境外托管 API。
|
||
- **内存纪律**:常驻业务峰 ≤1GB(L2);60 = 队列深度,不是 60 个浏览器。
|
||
- **零 Redis**:SQLite WAL 单写者排队。
|
||
- **诚实能力**:公开网页大约九成;登录墙 / 强 WAF / Google 搜索不承诺。住宅 IP 是另一条带成本声明的通道,本服务不做。
|
||
|
||
人交「事件怎么活、怎么死、多快死」;实现按 [`onesvm-dev-md/base/engineering-standards.md`](../onesvm-dev-md/base/engineering-standards.md) 事件表,缺格不补默认值开工。
|
||
|
||
---
|
||
|
||
## 2. 设计科学(为什么长这样)
|
||
|
||
### 2.1 统一出口,双形态同一内核
|
||
|
||
所有消费者注册主体、拿可吊销 key。MCP 与 HTTP 共用 **Auth → Policy → Queue → Engine**。错误码两面对齐。静态服务密钥只走 `X-Service-Token`,禁止塞进 `Authorization: Bearer`。
|
||
|
||
### 2.2 分层内核,而不是「一个大浏览器」
|
||
|
||
流量大约 90% 是搜索 + 纯 HTTP 精读,不该进 Chromium。
|
||
|
||
| 层 | 适配器 | 何时用 |
|
||
|---|---|---|
|
||
| A 无浏览器 | SearXNG-CN / SearXNG-Global / Trafilatura | 搜索发现、静态正文 |
|
||
| B 轻渲染 | Lightpanda | HTTP 抽空、需要一点 JS |
|
||
| C 保真 | chrome-headless-shell(按需槽,默认 0 副本) | 轻核不够时 |
|
||
| 预留 | Camoufox / 有头档 | 强对抗 + 住宅 IP,不在 1GB 预算内 |
|
||
|
||
降级链:C 满 → B → A → `blocked`/`upstream`。Cloudflare / WAF / 验证页**不拿渲染空转**,直接 `blocked`。
|
||
|
||
### 2.3 出口与身份分开记账
|
||
|
||
- **出口**:国内域直连;境外经 ProxyManager + mihomo vless 热池。决定「Google 过不过」的是 IP 信誉,不是 UA 字符串。
|
||
- **身份(P0/P1,2026-09-02 落地)**:每生产节点 8 套 Chrome 136 模版(与 Trafilatura `curl_cffi` `impersonate=chrome136` 自洽);一等 Cookie 养在本节点 SQLite。罐按 **模版 × http|cdp × 出口 × eTLD+1** 隔离,节点内共享、不按消费者拆。登录态 Cookie 名直接丢弃。403/验证页整域丢罐。Cookie **不进 MCP、不进 jobs.payload**。
|
||
|
||
Go 侧 `httpx` 仍是 Go TLS,UA 写诚实的 `onesvm-browser-server-httpx/1.0`,禁止再伪装 Chrome(TLS/UA 必须自洽)。
|
||
|
||
### 2.4 合规双向保险
|
||
|
||
请求侧在网关:SSRF、仅 80/443、域名策略、普通 key 遵守 robots。响应侧在 worker 模版层:体积/类型白名单、词表、PII 脱敏、注入包裹。命中即 `denied` 并审计,不假装成功。
|
||
|
||
---
|
||
|
||
## 3. 选用方案(实测后入选,不是目录堆砌)
|
||
|
||
2026-09-01 本机 Docker 评分(内存 30% / 质量 25% / 成功率 20% / 延迟 15% / 运维 10%)。全文:[`docs/decision-candidates-20260901.md`](docs/decision-candidates-20260901.md)。
|
||
|
||
| 方案 | 分 | 角色 | 为什么留 |
|
||
|---|---:|---|---|
|
||
| Trafilatura-HTTP | 96.8 | 默认精读 | 60/60、p50 ~60ms、正文干净;现网已加 curl_cffi |
|
||
| Lightpanda | 91.0 | 默认 JS | idle 3.6MB;CF/Amazon 仍过不了 |
|
||
| chrome-headless-shell | 85.5 | 保真按需 | 单槽 FIFO 零拒绝;重页 ~400MB |
|
||
| SearXNG-CN | 71.5 | 国内搜索 | 政策词准;突发时百度/搜狗 CAPTCHA,靠排队钳 4–8 |
|
||
| SearXNG-Global | 62.0 | 国外搜索 | 实例稳,但数据中心 IP 下 **仅 Bing**;产品不承诺多源 |
|
||
|
||
**明确排除**:playwright-distributed(Redis)、Browserless(4GB 档)、Jina 云(query 出境)、Firecrawl 自托管(与 shell+模版层重叠且更重)。
|
||
|
||
**用户已拍板**:D1 先 L0→L2(≤1GB);D2 接受 Bing-only 起步;D5 不做 Camoufox;Amazon 本站非本服务刚需。
|
||
|
||
现网能力以 [`docs/mcp-usage-20260901.md`](docs/mcp-usage-20260901.md) §4 为准(2026-09-02 mgr1 复测),不要把 09-01 bench 的「BBC 稳取 / Amazon 一律不行」抄进消费方文档。
|
||
|
||
---
|
||
|
||
## 4. 仓库地图
|
||
|
||
```
|
||
server/ Go 单二进制,-role=gateway|scheduler|proxymanager
|
||
cmd/browser-server/ 入口
|
||
internal/contract/ 信封与 Job(Session 字段 json:"-")
|
||
internal/gateway/ MCP + /v1 + Auth + 策略预检
|
||
internal/scheduler/ 队列、路由、模版层整合器、junk 过滤、Cookie 绑定
|
||
internal/dock/ 五适配器(SearXNG×2、Trafilatura、Lightpanda、shell)
|
||
internal/fingerprint/ 每节点 Chrome 136 模版
|
||
internal/session/ Cookie 罐(Sanitize / TTL / reap)
|
||
internal/store/ SQLite(jobs、keys、fp_*、session_cookies)
|
||
internal/proxymanager/ 订阅 / 探活 / 域名路由
|
||
internal/policy/ SSRF / robots / 域名
|
||
internal/safetyscan/ 响应侧词表与包裹
|
||
stacks/ Swarm stack + SearXNG 配置 + Trafilatura 镜像
|
||
scripts/ smoke-local.sh、deploy-mgr1.sh(默认 dry-run)
|
||
bench/ 选型期实测(无密钥)
|
||
docs/ 决策 / 机制 / MCP / 接手
|
||
```
|
||
|
||
源文件硬上限 **600 行**(`make wc`)。禁止万能 `util` 包。
|
||
|
||
---
|
||
|
||
## 5. 本机怎么跑
|
||
|
||
```bash
|
||
make test # go test(合入前加 -race:cd server && go test -race ./...)
|
||
make vet
|
||
make smoke # compose + stub 引擎,12 步断言
|
||
make image # onesvm/browser-server:dev(默认 linux/amd64)
|
||
make image-trafilatura # onesvm/trafilatura-http:dev
|
||
```
|
||
|
||
生产节点通常拉不到 Docker Hub。镜像必须在可联网机器构建/拉取,再 `docker save | ssh … docker load`,stack 用 `--resolve-image never`。**同 tag 覆盖后必须 `docker service update --force`**,否则任务还跑旧层。
|
||
|
||
mgr1 部署属 🟡:只在用户明确「确认执行」后跑 `bash scripts/deploy-mgr1.sh --apply`。密钥在 gitignore 的 `deploy.env`,不入 git。
|
||
|
||
---
|
||
|
||
## 6. 文档索引
|
||
|
||
完整表见 [`docs/README.md`](docs/README.md)。冲突时:
|
||
|
||
1. [`docs/plan-final-20260901.md`](docs/plan-final-20260901.md) — 决策
|
||
2. [`docs/design-arch-20260901.md`](docs/design-arch-20260901.md) — 机制
|
||
3. 代码 — 现网行为(文档会过期,以代码与 §4 现网复测为准)
|