\newpage
第21章:浏览器自动化与登录持久化(Camofox)¶
本章对应 Astra 生态组件
astra-camofox-browser— Camofox 封装- Camoufox/Camofox — 反检测浏览器
21.1 什么是 Camofox?¶
Camoufox(daijiang1987/Camoufox)是一个基于 Firefox 的 C++ 级指纹伪装浏览器——不是简单的 JS 层面的 navigator 修改,而是在底层 C++ 代码中修改浏览器指纹。
Camofox(jo-inc/camofox-browser)将前者封装为一个 REST API 服务器,为 AI Agent 提供无障碍树快照、稳定元素引用、会话隔离和代理支持。
21.2 典型应用场景¶
- 需要登录的网页:登录后保持 Session,Agent 无需每次手动认证
- 反爬严格的网站:模拟真实浏览器指纹
- 自动化表单填写:持久化 Cookie 省去重复登录
21.3 Hermes Agent 使用 Camofox 的架构¶
当 Hermes 的默认 Playwright/Chromium 被 Cloudflare、反爬严格的电商平台等拦截时,Camofox 是最佳替代方案。
21.4 容器化部署¶
Astra 生态 提供了预配置的容器脚本,位于
astra-camofox-browser仓库中。
21.4.1 使用容器脚本¶
git clone https://github.com/alrcatraz/astra-camofox-browser
cd astra-camofox-browser
# 下载 Camoufox 二进制
make fetch
# 构建镜像
make build
# 启动容器
make up
# 验证
curl -s http://localhost:9377/health
21.5 Hermes 配置¶
在 ~/.hermes/.env 中设置:
Hermes 的浏览器工具集自动检测此环境变量——无需在 config.yaml 中修改 browser.engine。
Camofox 选项:
| 环境变量 | 默认值 | 说明 |
|---|---|---|
CAMOFOX_PORT |
9377 |
监听端口 |
CAMOFOX_API_KEY |
(无) | 可选鉴权密钥 |
CAMOFOX_PROXY_URL |
(无) | 住宅代理 URL(增强反检测) |
21.6 登录凭据持久化与会话管理¶
21.6.1 核心挑战:跨轮次会话保持¶
关键限制: Hermes 在每个消息轮次之间清理浏览器会话。这意味着跨轮次的登录流程(输入手机号 → 等待验证码 → 输入验证码 → 登录)不能依赖 Hermes 的浏览器工具——会话在下一轮就消失了。
解决这个问题的关键是 持久化浏览器配置文件——将登录状态(Cookie、LocalStorage、Session)写入磁盘,使同一站点的后续访问能够复用已验证的会话。
21.6.2 配置文件持久化机制¶
Camofox 将浏览器状态保存到 ~/.camofox/profiles/<hash>/storage-state.json:
| Cookie 类型 | expires 值 |
容器重启后? |
|---|---|---|
Session Cookie(如 cookie2, _tb_token_) |
0 / -1 |
❌ 丢失 |
Persistent Cookie(如 t, tfstk) |
未来时间戳 | ✅ 有效直至过期 |
持久化策略:
- 首次登录 — 使用 Hermes 的 credential 系统(见第15章)获取网站凭据,通过 Camofox REST API 执行登录,浏览器 profile 自动持久化 Cookie
- 后续访问 — 指定相同的
userId/sessionKey,Camofox 自动从磁盘加载 profile,恢复已登录状态 - 定期刷新 — 对于 session-only Cookie 的站点,通过 cron 定期执行凭据登录刷新会话
21.6.3 通过 Camofox REST API 持久化会话¶
由于 Hermes 的浏览器工具在每轮后清理会话,需要直接调用 Camofox REST API(通过 execute_code() 或 terminal() 中的 curl)来维持跨轮次的登录状态:
| 操作 | 方法 | URL | 参数 |
|---|---|---|---|
| 创建标签页 | POST /tabs |
http://localhost:9377/tabs |
{"url":"...","userId":"X","sessionKey":"..."} |
| 获取页面快照 | GET /tabs/{tabId}/snapshot?userId=X |
— | — |
| 点击 | POST /tabs/{tabId}/click |
— | {"userId":"X","ref":"e5"} |
| 输入文本 | POST /tabs/{tabId}/type |
— | {"userId":"X","ref":"e2","text":"..."} |
| 导航 | POST /tabs/{tabId}/navigate |
— | {"userId":"X","url":"..."} |
| 截图 | GET /tabs/{tabId}/screenshot?userId=X |
— | — |
| 清理 | DELETE /sessions/{userId} |
— | — |
关键注意事项:
userId在 GET 端点中放 query params,在 POST 端点中放 JSON body- 为每个站点/账号创建固定的
userId和sessionKey,确保登录状态持续有效 - 标签页持续存在直到显式删除或 Camofox 服务重启
21.6.4 从凭据管理系统读取登录信息¶
Camofox 的登录凭据应通过第15章描述的凭据管理系统获取:
21.6.5 登录状态验证¶
import requests
CAMOFOX = "http://localhost:9377"
USER_ID = "site_monitor_prod"
# 创建标签页并检查是否已登录
resp = requests.post(f"{CAMOFOX}/tabs", json={
"url": "https://example.com/account",
"userId": USER_ID,
"sessionKey": "persistent_session"
})
tab_id = resp.json()["tabId"]
# 获取页面 snapshot 验证登录状态
snap = requests.get(f"{CAMOFOX}/tabs/{tab_id}/snapshot",
params={"userId": USER_ID}).json()
# 检查 snapshot 中是否出现"登录"按钮(→ 未登录)或"我的账户"(→ 已登录)
is_logged_in = "my account" in str(snap).lower()
21.6.6 定期刷新策略¶
对于 Session Cookie 有效期较短的站点,通过 cron 定期执行凭据登录:
| 调度 | 操作 | 凭据来源 |
|---|---|---|
| 每日 06:00 | 刷新所有网站登录 | KeePassXC → Camofox |
| 容器重启后 | 自动恢复 profile 登录 | profile 磁盘文件 |
| Session 过期时 | 自动检测 → 重新登录 | KeePassXC 凭据查询 |
21.7 反检测浏览器策略全景¶
| 方法 | 可靠性 | 安装成本 | 状态 |
|---|---|---|---|
| Camofox 浏览器 | ✅ 高 | 中等(容器部署) | 推荐 |
| 无头浏览器直连 | ❌ 被封锁 | 低 | 不可行 |
| 代理 + 普通浏览器 | ⚠️ 中等 | 中等 | 与用户使用同一个浏览器进程 |
对于反爬严格的平台,Camofox 配合持久化凭据管理是当前 Astra 生态的推荐方案。