AI Agent 专属浏览器 CLI — 通过 CDP 协议操控真实 Chrome,为 LLM 提供网页感知与操作能力。
面向个人使用的浏览器自动化效率工具候选版本,具备闭环 Agent、实时反馈、失败报告、成本透明、本地历史、任务 Profile 和轻量安全护栏。
- 接管已登录的 Chrome —
--connect模式直连人类已开启的浏览器,100% 保留登录态 - 扩展模式(无感) — 通过 Chrome 扩展 +
chrome.debuggerAPI 操控浏览器,无需--remote-debugging-port - 自动检测 — 50ms 探测 9222 端口,有 Chrome 就接管,没有就自动拉起强化无头实例
- 跨 iframe 滚动 — 自动穿透多层 iframe,跨域时降级为 CDP 父页面滚动
- LoaderId 隔离空闲检测 — 每次导航独立计数器,旧页面事件不会污染新页面
- 多维分析过滤 — 50+ 广告/追踪域名 + 路径关键词 + 资源类型 + beacon 文件,确保秒级空闲判定
- 反检测 — 禁用
navigator.webdriver、真实 User-Agent、1280×720 视口 - 指纹浏览器级反检测 — Canvas 噪声、WebGL 伪造、plugins 填充、WebRTC 保护等 8 大防护
- 拟人化输入 — CJK 用
InputEvent,ASCII 用KeyboardEvent,逐键随机延迟 - 正文提取 — Readability 风格算法,自动识别页面正文,去除导航/广告噪声
- 等待元素 — 按文本/选择器/ID 轮询等待动态元素出现
- 内容断言 — 验证元素是否包含预期文本,支持 UI 自动化测试
- 文件下载 — 端口模式用 CDP 下载管理,扩展模式用
chrome.downloadsAPI - Windows Job Object — 进程异常退出时 Chrome 自动被内核级机制终止
- 内置 Agent Prompt —
prompt子命令直接输出 LLM 系统提示词 - Agent 自主规划 —
run_task让 Agent 自主观察→决策→执行→观察,完成多步浏览器任务 - 不抢标签页 — 扩展模式
active: false后台创建标签页,兜底恢复焦点,全程无感 - 失败报告 — 任务结束时自动生成 JSON/Markdown 报告,包含操作时间线和失败分析
- 实时进度 — 每步 observe/action/recovery 输出到 stderr,不污染 MCP stdout
- 成本透明 — LLM usage 和费用估算,按 provider/model 区分,配置化价格
- 本地历史 — SQLite 持久化,支持 history/search/compare/cleanup/db-status
- 任务 Profile — 从成功任务保存为可复用模板,变量替换,顺序执行,失败即停
- 安全护栏 — guarded 模式敏感操作要求确认,同域操作自动频率限制
# 构建
cargo build --release
# 方式 1: 扩展模式(推荐,无感)
# 需要在 Chrome 中加载 extension/ 目录(unpacked)
.\target\release\agent-browser-cli.exe view --url "https://www.baidu.com" --extension
# 方式 2: 自动检测
# 如果 9222 端口有 Chrome → 自动接管(保留登录态)
# 如果没有 → 拉起新的无头 Chrome
.\target\release\agent-browser-cli.exe view --url "https://www.baidu.com"
# 方式 3: 显式连接已登录的 Chrome
# 先启动: chrome.exe --remote-debugging-port=9222
.\target\release\agent-browser-cli.exe view --connect http://127.0.0.1:9222 --url "https://github.com"
# 方式 4: 管道监听模式(SDK 集成用)
.\target\release\agent-browser-cli.exe listen --extension
# 方式 5: 独立 Agent Chrome(自动启动,不打扰用户主浏览器)
# AGENT_BROWSER_MODE=connect 时自动拉起一个带调试端口的独立 Profile Chrome。
# 用户日常 Chrome 不受影响;首次需在 Agent Chrome 中手动登录一次,之后复用。
$env:AGENT_BROWSER_MODE = "connect"
.\target\release\agent-browser-cli.exe view --url "https://www.baidu.com"当用户需要完整渲染(如钉钉文档,会检测 chrome.debugger 而降级)时,用独立 Agent Chrome 替代扩展模式:
- 自动检测
AGENT_CONNECT_PORT(默认 9222)是否已有 Chrome,有则直连,无则自动启动 - 使用独立 profile 目录(
%LOCALAPPDATA%\AgentBrowser\chrome-profile),绝不复用/干扰用户主 Chrome - 用户日常 Chrome 与 Agent Chrome 可同时运行
- 首次使用需在 Agent Chrome 中手动登录一次(钉钉/站点),之后登录态持久复用
| 环境变量 | 默认值 | 说明 |
|---|---|---|
AGENT_BROWSER_MODE |
空 | 设为 connect 启用自动启动 |
AGENT_CONNECT_HOST |
127.0.0.1 |
CDP 主机 |
AGENT_CONNECT_PORT |
9222 |
CDP 端口 |
AGENT_CONNECT_USER_DATA_DIR |
%LOCALAPPDATA%\AgentBrowser\chrome-profile |
独立 profile 目录 |
AGENT_CHROME_PATH |
自动探测 | Chrome 可执行文件路径 |
针对 alidocs.dingtalk.com/i/nodes/... 钉钉文档,下载必须保持后台运行,不得抢占用户正在使用的窗口或标签页。
推荐流程:
- 使用扩展模式通过
AGENT_ATTACH_EXISTING=1和AGENT_ATTACH_URL=<完整 URL>精确查找并附着已有标签页;不要新建文档标签页,也不要调用Page.navigate。 - 用
tree获取当前 frame 快照,在文档 frame 内点击三点菜单(本次文档为f1-e5)。 - 对“下载到本地”执行
hover_text。钉钉菜单位于 iframe,不能把 iframe 局部坐标直接发给顶层 CDP;hover_text必须先加上 iframe 的页面偏移,再发送Input.dispatchMouseEvent(mouseMoved)。 - 在点击格式前先执行
arm_download_watch,然后点击精确文本Markdown(.md)。最后执行await_download_watch,必须收到state=complete且filename以.md结尾。
仅提供链接、没有现成标签页时,已验证的流程是:扩展以 createTab(active:false) 新建临时标签页,导航并等待工具栏完整渲染,再按同一菜单和下载监听流程执行。临时页的元素 ID 每次渲染都会变化,不能复用例如 f1-e5 的编号;应从工具栏语义/几何定位三点详情按钮。本次页面右侧控制顺序为“新建、搜索、三点详情”,应选择从右数第三个空标签按钮。当前路由器的 Target.closeTarget 只解绑调试器,尚未实现所有权校验后的关闭;在补齐该能力前,任务应保留临时标签,绝不关闭用户已有标签。
验证脚本:verify_dingtalk_markdown_download.py。成功标准是扩展下载事件和本地文件同时确认;仅看到菜单、Page.downloadWillBegin 或旧的 Downloads 文件都不能算完成。
重要约束:
- 禁止
activate_tab、chrome.tabs.update({active:true})、chrome.windows.update({focused:true})、系统鼠标/API、屏幕坐标点击。 - 禁止使用“当前活动标签”兜底;活动标签可能是用户的其他工作页面。
document.readyState=interactive在钉钉 SPA 中不是失败依据;新页面导航应等待带匹配loaderId的Page.lifecycleEvent(name="load")。- “下载到本地”可能同时存在多个 DOM 镜像节点;悬停允许同一可见控件的重复命中,但格式点击仍必须唯一命中。
- 格式点击必须只执行一次。若等待逻辑重试点击,可能创建同名的多份下载;重试只能用于观察菜单是否出现。
- 扩展模式下
Browser.setDownloadBehavior和Page.setDownloadBehavior可能被拒绝,优先使用chrome.downloads.onCreated/onChanged监听实际文件。
agent-browser-cli view --url <URL> [--connect <URL>] [--profile <PATH>] [--show]agent-browser-cli listen [--connect <URL>] [--profile <PATH>] [--resources block|allow|smart] [--show] [--extension]资源策略:
block— 阻断图片/CSS/字体/广告(最快,默认)allow— 允许所有资源(完整渲染)smart— 只阻断广告/追踪,允许图片和 CSS
listen 启动后需要完成浏览器连接/附着,就绪后才会在 stdout 打印一行:
{"status":"ready","message":"agent-browser-cli is listening ...","media_enabled":false}驱动方必须轮询 stdout、直到读到 "status":"ready" 再发送任何命令,不能用固定 sleep。原因是两种模式的初始化耗时差异极大:
- 自启动模式(headless /
--show):通常数秒内 ready。 - 扩展模式(
--extension):需经本地 bridge 连接已加载的扩展、由扩展创建后台about:blank临时标签并逐 target 附着。实测典型约 15 秒 ready,Chrome 负载较重时可达 ~30 秒(视机器和 Chrome 负载而定)。
若在 ready 之前就写 stdin,命令会在初始化窗口内丢失或不被处理,表现为 stdout 长时间无响应。请给扩展模式预留 至少 60–90 秒 的就绪超时(mcp_server.py 已按模式区分:自启动 30s、扩展 90s)。
必须持续排空 stderr(扩展模式尤其致命):扩展模式下二进制会向 stderr 输出大量
[cdp]调试日志。若驱动方重定向了 stderr 却不读取,Windows/OS 管道缓冲(约 4 KiB)一旦填满,子进程写 stderr 即被阻塞、初始化假死,约 31 秒后以退出码 1 退出——看起来像"握手超时",实为 stderr 未排空。务必用独立线程/任务持续读取 stderr(或直接2>NUL/2>/dev/null丢弃)。mcp_server.py已在等待 ready 之前启动_drain_stderr后台任务处理此问题。
Windows/PowerShell 注意:首次向 stdin 写入若带 UTF-8 BOM,会让第一条 JSON 报
Invalid JSON;用WriteLine/无 BOM 编码,或先发一条空行 priming。
agent-browser-cli prompt直接将内置的 LLM 系统提示词输出到 stdout,可管道传给 AI 框架。
Agent 采用 闭环控制(ReAct 循环 + 验证 + 恢复),自主完成多步浏览器任务。
观察 → 结构化快照 → LLM 决策 → 执行 → 验证 → 更新状态 → 恢复/重规划 → 循环
# 在 Claude Code 或其他 MCP 客户端中调用
run_task("打开 https://example.com 并告诉我页面标题")
run_task("在百度搜索 Rust 并点击第一条结果")
run_task("下载这个钉钉文档到桌面")cd /d/agent_browser_cli/ai_browser_cli_repo
python agent_runner.py "打开 https://example.com 并读取标题"| 能力 | 说明 |
|---|---|
| 结构化动作结果 | 每次动作返回 transport_ok / page_responded / effects 三层语义 |
| 页面变化验证 | before/after 快照对比(URL、标题、DOM 指纹、表单状态、新标签页) |
| 目标状态管理 | current_goal / next_goal / completed_goals 滚动式目标分解 |
| 有限错误恢复 | STALE_TARGET → reobserve;ELEMENT_NOT_FOUND → reobserve;NAVIGATION_TIMEOUT → check URL/retry once |
| Pause / Resume | 同进程内 checkpoint 暂停/恢复,恢复后重新观察页面 |
| 上下文模式 | `AGENT_CONTEXT_MODE=legacy |
| 变量 | 默认值 | 说明 |
|---|---|---|
AGENT_CONTEXT_MODE |
dual |
上下文模式:legacy(旧 history)/ dual(双写)/ structured(仅结构化) |
AGENT_VERIFY_MODE |
shadow |
验证模式:off / shadow(只记录)/ active |
AGENT_RECOVERY_MODE |
off |
恢复模式:off / shadow / active |
AGENT_GOAL_ASSESSMENT |
off |
目标评估模式:off / shadow(只记录)/ active |
AGENT_OBSERVABILITY |
stderr |
可观测性输出:off / stderr(文本)/ jsonl(结构化 JSON) |
AGENT_OBSERVABILITY_PATH |
"" |
JSONL 输出文件路径(为空时 jsonl 输出到 stderr) |
AGENT_MAX_STEPS |
15 |
最大步数 |
AGENT_LLM_DELAY |
0 |
LLM 调用间延迟(秒),用于低配额 API |
AGENT_ACTION_GUARD |
off |
动作前 target 验证:off / shadow / active |
AGENT_LOOP_GUARD |
off |
循环防护(重复 no_effect 检测):off / shadow / active |
AGENT_RAW_EVALUATE |
off |
原始 JavaScript 执行:off / shadow / active(默认拒绝 LLM 生成任意 JS) |
从 v0.9.1 起,Agent 提供完整的个人效率闭环:失败报告、实时进度、成本透明、本地历史、任务 Profile、安全护栏。
运行任务 → 实时进度 → 记录成本 → 失败报告 → 保存历史 → 对比历史
→ 成功任务存为 Profile → 变量化重复执行 → 敏感动作确认 → 同域限速
任务结束时自动生成用户可读报告(尤其失败时),保存到 reports/:
| 变量 | 默认值 | 说明 |
|---|---|---|
AGENT_REPORT_MODE |
failure |
报告模式:off / failure(仅失败/暂停)/ always |
AGENT_REPORT_FORMAT |
both |
格式:md / json / both |
AGENT_REPORT_DIR |
reports |
报告目录 |
AGENT_REPORT_SCREENSHOT |
off |
截图(未实现,默认关闭) |
报告包含:task_id、状态、耗时、步数、最终 URL、failure_code、操作时间线、失败分析、建议、成本摘要。
AGENT_PROGRESS_MODE=stderr # 实时进度输出到 stderr(不污染 MCP stdout)
AGENT_LLM_INPUT_PRICE_PER_MILLION=0.15 # 每百万输入 token 价格(美元)
AGENT_LLM_OUTPUT_PRICE_PER_MILLION=0.60 # 每百万输出 token 价格(美元)进度输出示例:
[step 1/12] observe page ... ok
[step 2/12] navigate → bing.com ... success 0.81s
[task] completed: done
python -m cli init # 创建 data/reports/config/profiles 目录 + 配置模板
python -m cli init --yes # 自动确认安全操作
python -m cli doctor # 只读诊断(不弹 Chrome、不调用 API)
python -m cli doctor --check-api # 额外检查 API 可达性
python -m cli doctor --json # JSON 输出doctor 检查:Chrome 路径/版本、CDP 端口、扩展、Rust CLI、Python 依赖、LLM 环境、磁盘、目录可写、baseline 漂移。
python -m cli history # 最近 20 条任务
python -m cli history --status failed # 按状态筛选
python -m cli history --limit 50 --json # 更多 + JSON
python -m cli search-history "Rust" # 模糊搜索
python -m cli compare <id1> <id2> # 比较两次任务
python -m cli cleanup # 清理旧数据(按保留天数)
python -m cli db-status # 数据库状态| 变量 | 默认值 | 说明 |
|---|---|---|
AGENT_DATA_DIR |
data |
数据目录 |
AGENT_DB_PATH |
data/agent.db |
SQLite 路径 |
AGENT_RETENTION_DAYS |
30 |
保留天数 |
AGENT_DB_ENABLED |
on |
是否启用 SQLite(off 时零访问) |
数据库表:tasks、actions、events、checkpoints、reports、profiles、profile_steps。所有 JSON 字段经过敏感信息过滤。
python -m cli save-as-profile --task-id <id> --name <name> # 从成功任务保存
python -m cli save-as-profile --last-run --name <name> # 从最近任务保存
python -m cli list-profiles # 列出所有
python -m cli show-profile <name> # 查看详情
python -m cli delete-profile <name> # 删除
python -m cli run-profile <name> --var key=value # 运行
python -m cli run-profile <name> --vars-json '{...}' # 变量 JSON- 只从
status=success的任务创建 Profile {{variable}}模板替换,缺失变量在执行前失败(MISSING_PROFILE_VARIABLE)- 每次
run-profile生成新的 task_id,不修改原任务 - 顺序执行,失败即停止
- 步骤会重新 observe、重新定位 target(不盲目重放旧 target_id)
AGENT_SAFETY_MODE=personal|guarded # personal 不确认,guarded 敏感操作确认
AGENT_CONFIRMATION_MODE=terminal|disabled
AGENT_RATE_LIMIT_MODE=off|auto # 同域操作频率限制
AGENT_MIN_ACTION_INTERVAL_MS=1000
AGENT_RATE_JITTER_MIN_MS=200
AGENT_RATE_JITTER_MAX_MS=800- guarded 模式:支付/转账/删除/发送/上传/密码/验证码等敏感操作要求确认
- 无终端:返回
confirmation_required,不伪装成功 - 用户拒绝:停止动作,不重放
- 同域限速:auto 模式下同一 origin 连续动作间隔不足时插入随机等待
- 不限制 LLM API:只限制浏览器动作
⚠️ 安全检测属于便利型护栏,不是企业级安全边界。URL 关键词/动作类型匹配可能存在误报或漏报,个人使用场景可接受。
当 DOM/accessibility tree 无法可靠定位目标元素时,按需截图并调用视觉 LLM 返回候选,再映射回真实 DOM target_id 执行标准动作。
AGENT_VISION_MODE=fallback # off | fallback | always
AGENT_VISION_PROVIDERS=glm # 声明支持视觉的 provider(用逗号分隔)
AGENT_VISION_REDACTION=basic # off | basic | strict
AGENT_SCREENSHOT_SCOPE=auto # auto | target | viewport | full
AGENT_VISION_STABILITY_TIMEOUT_MS=1500 # 页面稳定等待超时
AGENT_VISION_UNAVAILABLE=dom # dom | error(provider 不可用时)
AGENT_VISION_MAX_CALLS=3 # 每任务最多视觉调用次数
AGENT_VISION_MAX_CALLS_PER_PAGE=1 # 每页最多视觉调用次数
AGENT_VISUAL_COORDINATE_CLICK=off # off | active(默认关闭坐标点击)
AGENT_VISION_MAX_COST_USD= # 视觉预算上限(留空不启用)
AGENT_VISION_JPEG_QUALITY=70
AGENT_VISION_MAX_IMAGE_BYTES=1000000视觉 provider 需配置 API key(如 GLM 用 GLM_API_KEY),只通过环境变量提供,不写入配置文件、报告、SQLite 或日志。
- 触发条件:
element_not_found/target_invalid/no_effect/ 用户明确描述颜色/位置/图标 - 截图范围:
auto(有 target → target crop;否则 viewport crop)、target、viewport、full(仅显式开启) - 页面稳定 gate:截图前判断页面稳定(无进行中导航、URL 未变化、可交互元素>0),超时返回
VISION_PAGE_NOT_STABLE - provider 降级:
AGENT_VISION_UNAVAILABLE=dom(回 DOM-only recovery)/error(返回VISION_PROVIDER_UNAVAILABLE) - 安全:basic/strict 脱敏敏感区域;PIL 不可用时 fail-closed(返回
VISION_REDACTION_UNAVAILABLE,不上传未脱敏截图) - 映射:视觉 bbox → DPR/scroll 修正 → elementFromPoint → 真实 DOM target_id → 标准动作
- 坐标点击默认关闭:坐标只用于 DOM 映射,不直接点击
- 预算/次数:
AGENT_VISION_MAX_COST_USD/AGENT_VISION_MAX_CALLS控制 - 原始截图不持久化:不进报告/SQLite/JSONL/Profile
⚠️ 当前已验证 GLM-4V-Flash 视觉定位链路。复杂 iframe、Shadow DOM、遮挡和多候选场景仍需单独验证。视觉 provider 需显式配置。
所有持久化(报告、SQLite、Profile、日志)均过滤:
- 密码、Cookie、Authorization、API key、完整表单值不写入
- secret 变量在
show-profile、进度、报告、普通输出中脱敏 - 不保存原始 LLM 思考过程和完整页面文本
Agent 支持三种暂停原因:
waiting_for_user— 验证码、登录授权、人工确认waiting_for_page— 页面仍在加载、下载尚未完成waiting_for_external_event— 等待邮件、支付回调、第三方状态
MCP 接口:
{"action": "agent_resume", "checkpoint_id": "cp_xxx"}限制(当前版本):
- 仅支持同一进程、同一 MCP 实例内恢复
- 进程重启后 checkpoint 和 session 丢失,旧 checkpoint_id 返回
CHECKPOINT_NOT_FOUND - 不支持跨进程持久化(Redis/SQLite/PostgreSQL 暂未实现)
- 不支持多调用方权限隔离(单实例本地使用场景)
| 动作 | 说明 |
|---|---|
navigate |
打开 URL |
click |
点击元素(target_id) |
type |
输入文本 |
evaluate |
执行任意 JavaScript(绕过 50 字符截断) |
debug_events |
读取有界缓存中的 console、未捕获异常、HTTP/网络错误;支持 cursor 增量读取 |
debug_clear |
清空当前调试事件缓存 |
debug_status |
查看 Runtime/Log/Network 监听是否就绪和具体错误 |
debug_start / debug_stop |
开始或暂停事件缓存,不断开浏览器 |
debug_inject |
向当前页面或指定 frame_index 的 iframe 注入异步 JavaScript;iframe 使用隔离世界,仅可操作 DOM,无法读取页面主世界的 JS 闭包或框架内部状态 |
download_setup |
设置下载目录 |
pause |
暂停任务,生成 checkpoint |
stop |
任务完成或遇到障碍时终止 |
| 错误类型 | shadow 建议 | active 行为 |
|---|---|---|
STALE_TARGET |
reobserve | 强制重新观察,回到 LLM 重新决策(不重放旧动作) |
ELEMENT_NOT_FOUND |
reobserve | 强制重新观察,回到 LLM 重新决策 |
NAVIGATION_TIMEOUT |
check URL → retry once | URL 已到达目标则不重试;未变化最多重试一次 |
| 其他 | 旧逻辑 | 3 次重试 + 黑名单 |
# 环境变量
export AGENT_BROWSER_EXTENSION=1 # 必须
export LLM_PROVIDER=anthropic # 或 openai
export ANTHROPIC_API_KEY=sk-xxx # 你的 API key
export AGENT_MAX_STEPS=15 # 可选,默认 15 步Agent 全程在后台运行,不影响用户当前浏览:
- 扩展端
active: false— 所有新标签页在后台创建,不抢焦点 - Rust 侧兜底恢复 — connect 后若标签页意外抢到焦点,立即恢复原活动页
detect_new_tab不激活 — 发现新标签页只更新内部引用,不激活
| 变量 | 默认值 | 说明 |
|---|---|---|
AGENT_BROWSER_BACKGROUND |
1 |
后台创建标签页 |
AGENT_BROWSER_RESTORE_FOCUS |
1 |
启用兜底恢复焦点(设为 0 禁用) |
通过 Chrome 扩展 + chrome.debugger API 操控浏览器,无需 --remote-debugging-port。
- 在 Chrome 中加载扩展:打开
chrome://extensions→ 开启开发者模式 → 加载已解压的扩展程序 → 选择extension/目录 - 确保当前活动标签页是普通网页(非
chrome://页面) - 运行命令时加
--extension参数
# 一次性提取
.\target\release\agent-browser-cli.exe view --url "https://example.com" --extension
# 常驻管道模式
.\target\release\agent-browser-cli.exe listen --extension| 功能 | 端口模式 | 扩展模式 |
|---|---|---|
| navigate / click / type | ✅ | ✅ |
| extract_tree(含跨域 iframe) | ✅ | ✅ |
| 正文提取 | ✅ | ✅ |
| 等待元素 / 断言 | ✅ | ✅ |
| 文件下载 | ✅ | ✅(通过 chrome.downloads API) |
| 截图 | ✅ | 仅前台 tab 可用,后台 tab 受 chrome.debugger 限制 |
| 退出安全 | ✅ | ✅ 不关用户 tab,不 kill 浏览器 |
| evaluate(任意 JS) | ✅ | ✅ |
| console/异常/网络调试事件 | ✅ | ✅ |
| Agent 自主规划(run_task) | ✅ | ✅ |
| 后台运行不抢焦点 | ✅ | ✅ |
chrome.debugger 的 Page.captureScreenshot 要求 tab 为前台可见状态。后台 tab 截图会超时或失败。
如需截图,请切换到端口模式(--connect)或确保 agent tab 在前台。
# 运行回归测试(需要 fixture 服务器 + Chrome 扩展已加载)
.\tests\regression.ps1# 回归测试(自动,三模式 extract 一致性 + 下载)
.\tests\regression.ps1
# 动态插帧测试(自动,验证 click 不点偏)
.\tests\dynamic_frame_test.ps1
# Tab 存活测试(半自动,需确认 Chrome 有 3+ 标签页)
.\tests\tab_safety_test.ps1资源策略:
block— 阻断图片/CSS/字体/广告(最快,默认)allow— 允许所有资源(完整渲染)smart— 只阻断广告/追踪,允许图片和 CSS
agent-browser-cli prompt直接将内置的 LLM 系统提示词输出到 stdout,可管道传给 AI 框架。
listen 模式下,通过 stdin 发送 JSON 命令,stdout 返回 JSON 响应:
{"action": "navigate", "url": "https://example.com"}
{"action": "click", "target_id": "e5"}
{"action": "type", "target_id": "e3", "text": "hello world"}
{"action": "screenshot"}
{"action": "tree"}
{"action": "meta"}
{"action": "get_content"}
{"action": "wait_for", "by": "text", "value": "欢迎回来", "timeout": 10000}
{"action": "assert_element", "target_id": "e5", "expected": "登录成功"}
{"action": "download_setup", "path": "downloads"}
{"action": "download", "target_id": "e10", "path": "downloads", "timeout": 30000}
{"action": "evaluate", "expression": "document.title"}
{"action": "debug_clear"}
{"action": "debug_inject", "script": "console.log('agent debug', location.href); return document.title;"}
{"action": "debug_events", "kinds": ["console", "exception"], "limit": 100}
{"action": "debug_status"}
{"action": "configure", "media_enabled": true}
{"action": "get_prompt"}
{"action": "run_task", "task": "打开 https://example.com 并读取标题", "max_steps": 15}
{"action": "agent_resume", "checkpoint_id": "cp_xxx"}调试事件仅保存在内存环形缓冲区。单条事件最大 64 KiB,单次 debug_events 响应最多返回约 192 KiB 的事件内容;到达上限会返回 response_truncated: true,应使用 next_cursor 继续读取。过长字符串、集合和深层对象会标记 truncated: true。字段名含 cookie、authorization、token、password、secret 或 API key,以及 Bearer/JWT、长 token、邮箱和手机号等字符串值会自动脱敏。使用 debug_status 确认 Runtime、Log 和 Network 监听均为 listening;扩展模式下需先加载 extension/ 并连接本地 bridge。
扩展模式下
debug_inject/debug_events需等待启动握手完成(约 20–30 秒,见上文「启动握手」)。已实测验证:注入console.log后可由debug_events完整回收该 console 事件。
{"status": "ok", "action": "navigate", "url": "...", "title": "...", "interactive_count": 32, "tree": "[@e1] button \"登录\"\n[@e2] input \"手机号\""}
{"status": "error", "error": "Element [e5] not found in any frame"}media_enabled |
效果 |
|---|---|
true |
清空拦截列表,允许加载所有资源 |
false |
重新注入拦截黑名单 |
{"action": "get_content"}
{"status": "ok", "action": "get_content", "content": {"title": "...", "text": "...", "wordCount": 123, "charCount": 456, "method": "readability"}}使用 Readability 风格算法自动识别页面正文区域,返回结构化文本。适用于:
- 提取文章/新闻正文
- 获取页面主要内容(去除导航/广告/侧栏噪声)
- 为 LLM 提供可读的页面文本(而非仅交互元素)
{"action": "wait_for", "by": "text", "value": "欢迎回来", "timeout": 10000}
{"status": "ok", "action": "wait_for", "result": {"found": true, "target_id": "e5"}}轮询等待指定元素出现,支持三种查询方式:
by: "text"— 按文本内容匹配(大小写不敏感)by: "target_id"— 按 data-agent-id 匹配by: "selector"— 按 CSS 选择器匹配
适用于 SPA 页面等待动态内容渲染完成。
{"action": "assert_element", "target_id": "e5", "expected": "登录成功"}
{"status": "ok", "action": "assert_element", "result": {"passed": true, "actual": "登录成功,欢迎回来", "target_id": "e5"}}适用于 UI 自动化测试中的断言验证。
// 1. 设置下载目录(可选,listen 启动后先配置一次)
{"action": "download_setup", "path": "downloads"}
// 2. 点击下载链接,等待文件下载完成
{"action": "download", "target_id": "e10", "path": "downloads", "timeout": 30000}
{"status": "ok", "action": "download", "result": {"status": "ok", "guid": "...", "download_path": "downloads"}}download_setup 启用浏览器下载行为并设置下载路径。download 点击指定元素触发的下载,并等待下载完成(支持超时)。
from browser_client import BrowserClient
import asyncio
async def main():
async with BrowserClient(connect="http://127.0.0.1:9222") as client:
result = await client.navigate("https://example.com")
print(result["tree"])
await client.screenshot()
asyncio.run(main())import { BrowserClient } from './browserClient';
const client = new BrowserClient({ connect: 'http://127.0.0.1:9222' });
await client.start();
const result = await client.navigate('https://example.com');
console.log(result.tree);
await client.close();每个可交互元素输出一行:
[@eN] role "text_content"
eN— 全局唯一 ID(跨 iframe 递增)role— 元素角色(button, link, input, textbox 等)text_content— 文本内容/placeholder/aria-label(截断到 50 字符)
多 iframe 场景带 frame 前缀:
[frame-0] [@e1] button "登录"
[frame-1] [@e50] input "搜索"
启动时自动注入(CDP 启动参数 + 页面 JS 注入):
--disable-blink-features=AutomationControlled— 隐藏navigator.webdriver--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...— 真实浏览器 UAwindow_size(1280, 720)— 标准 Windows 分辨率
通过 Page.addScriptToEvaluateOnNewDocument 在所有页面加载前注入,覆盖 iframe 和新标签页:
| 保护项 | 措施 |
|---|---|
| Canvas 指纹 | 1% 像素 ±1 噪声 |
| WebGL 指纹 | 伪造 Intel UHD Graphics 620 渲染器 |
navigator.plugins |
填充 PDF 插件、Native Client |
navigator.languages |
固定 ['zh-CN', 'zh', 'en'] |
navigator.hardwareConcurrency |
固定 8 核 |
navigator.deviceMemory |
固定 8 GB |
| 屏幕属性 | 固定 24-bit colorDepth、1280×720 |
| WebRTC | ICE relay-only 策略,防 IP 泄露 |
| 权限查询 | 统一返回 prompt 状态 |
三重机制确保 Chrome 不会残留:
- Stdin 断开自毁 — 管道关闭时自动退出
- Ctrl+C 信号处理 —
tokio::signal::ctrl_c()优雅关闭 - Windows Job Object — 内核级
KILL_ON_JOB_CLOSE,进程崩溃时 OS 自动清理
验证 frame 索引快照在页面动态变化后仍能正确寻址:
# 1. 启动 fixture 服务器
python -m http.server 8080 --directory tests/fixtures &
python -m http.server 8081 --directory tests/fixtures &
# 2. 运行 extract
.\target\debug\agent-browser-cli.exe view --url "http://127.0.0.1:8080/oopif_main.html" --extension
# 3. 在浏览器控制台执行:
# const f = document.createElement('iframe');
# f.src = 'http://127.0.0.1:8081/oopif_frame.html';
# document.body.insertBefore(f, document.body.firstChild);
# 4. 再次运行 extract,确认 f0-e1 仍是原元素验证 view/listen --extension 退出时不会误关用户标签页:
# 1. 在 Chrome 中手动打开 3 个标签页(如 baidu / github / 本地页)
# 2. 运行:
.\target\debug\agent-browser-cli.exe view --url "https://example.com" --extension
# 3. 确认退出后 3 个标签页仍在
# 4. 运行:
.\target\debug\agent-browser-cli.exe listen --extension
# 5. 在 stdin 输入:{"action":"navigate","url":"https://example.com"}
# 6. Ctrl+C 退出,确认 3 个标签页仍在# 生成密钥对(用于固定扩展 ID)
openssl genrsa 2048 | openssl pkcs8 -topk8 -nocrypt > extension.pem
# 打包
chrome --pack-extension=extension --pack-extension-key=extension.pemMIT