Skip to content

Repository files navigation

Agent Browser CLI — v0.9.1-rc1

AI Agent 专属浏览器 CLI — 通过 CDP 协议操控真实 Chrome,为 LLM 提供网页感知与操作能力。

面向个人使用的浏览器自动化效率工具候选版本,具备闭环 Agent、实时反馈、失败报告、成本透明、本地历史、任务 Profile 和轻量安全护栏。

核心能力

  • 接管已登录的 Chrome--connect 模式直连人类已开启的浏览器,100% 保留登录态
  • 扩展模式(无感) — 通过 Chrome 扩展 + chrome.debugger API 操控浏览器,无需 --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.downloads API
  • Windows Job Object — 进程异常退出时 Chrome 自动被内核级机制终止
  • 内置 Agent Promptprompt 子命令直接输出 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"

独立 Agent Chrome(AGENT_BROWSER_MODE=connect

当用户需要完整渲染(如钉钉文档,会检测 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 可执行文件路径

子命令

钉钉文档后台 Markdown 下载(经验记录)

针对 alidocs.dingtalk.com/i/nodes/... 钉钉文档,下载必须保持后台运行,不得抢占用户正在使用的窗口或标签页。

推荐流程:

  1. 使用扩展模式通过 AGENT_ATTACH_EXISTING=1AGENT_ATTACH_URL=<完整 URL> 精确查找并附着已有标签页;不要新建文档标签页,也不要调用 Page.navigate
  2. tree 获取当前 frame 快照,在文档 frame 内点击三点菜单(本次文档为 f1-e5)。
  3. 对“下载到本地”执行 hover_text。钉钉菜单位于 iframe,不能把 iframe 局部坐标直接发给顶层 CDP;hover_text 必须先加上 iframe 的页面偏移,再发送 Input.dispatchMouseEvent(mouseMoved)
  4. 在点击格式前先执行 arm_download_watch,然后点击精确文本 Markdown(.md)。最后执行 await_download_watch,必须收到 state=completefilename.md 结尾。

仅提供链接、没有现成标签页时,已验证的流程是:扩展以 createTab(active:false) 新建临时标签页,导航并等待工具栏完整渲染,再按同一菜单和下载监听流程执行。临时页的元素 ID 每次渲染都会变化,不能复用例如 f1-e5 的编号;应从工具栏语义/几何定位三点详情按钮。本次页面右侧控制顺序为“新建、搜索、三点详情”,应选择从右数第三个空标签按钮。当前路由器的 Target.closeTarget 只解绑调试器,尚未实现所有权校验后的关闭;在补齐该能力前,任务应保留临时标签,绝不关闭用户已有标签。

验证脚本:verify_dingtalk_markdown_download.py。成功标准是扩展下载事件和本地文件同时确认;仅看到菜单、Page.downloadWillBegin 或旧的 Downloads 文件都不能算完成。

重要约束:

  • 禁止 activate_tabchrome.tabs.update({active:true})chrome.windows.update({focused:true})、系统鼠标/API、屏幕坐标点击。
  • 禁止使用“当前活动标签”兜底;活动标签可能是用户的其他工作页面。
  • document.readyState=interactive 在钉钉 SPA 中不是失败依据;新页面导航应等待带匹配 loaderIdPage.lifecycleEvent(name="load")
  • “下载到本地”可能同时存在多个 DOM 镜像节点;悬停允许同一可见控件的重复命中,但格式点击仍必须唯一命中。
  • 格式点击必须只执行一次。若等待逻辑重试点击,可能创建同名的多份下载;重试只能用于观察菜单是否出现。
  • 扩展模式下 Browser.setDownloadBehaviorPage.setDownloadBehavior 可能被拒绝,优先使用 chrome.downloads.onCreated/onChanged 监听实际文件。

view — 单次页面抓取

agent-browser-cli view --url <URL> [--connect <URL>] [--profile <PATH>] [--show]

listen — 管道监听模式

agent-browser-cli listen [--connect <URL>] [--profile <PATH>] [--resources block|allow|smart] [--show] [--extension]

资源策略:

  • block — 阻断图片/CSS/字体/广告(最快,默认)
  • allow — 允许所有资源(完整渲染)
  • smart — 只阻断广告/追踪,允许图片和 CSS

启动握手:发命令前必须先等 ready(重要)

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。

prompt — 输出 Agent 系统提示词

agent-browser-cli prompt

直接将内置的 LLM 系统提示词输出到 stdout,可管道传给 AI 框架。

Agent 自主规划

Agent 采用 闭环控制(ReAct 循环 + 验证 + 恢复),自主完成多步浏览器任务。

观察 → 结构化快照 → LLM 决策 → 执行 → 验证 → 更新状态 → 恢复/重规划 → 循环

通过 MCP 工具

# 在 Claude Code 或其他 MCP 客户端中调用
run_task("打开 https://example.com 并告诉我页面标题")
run_task("在百度搜索 Rust 并点击第一条结果")
run_task("下载这个钉钉文档到桌面")

通过 Python 独立运行

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)

个人效率工具(P9 系列)

从 v0.9.1 起,Agent 提供完整的个人效率闭环:失败报告、实时进度、成本透明、本地历史、任务 Profile、安全护栏

运行任务 → 实时进度 → 记录成本 → 失败报告 → 保存历史 → 对比历史
→ 成功任务存为 Profile → 变量化重复执行 → 敏感动作确认 → 同域限速

失败报告(P9-UX1)

任务结束时自动生成用户可读报告(尤其失败时),保存到 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、操作时间线、失败分析、建议、成本摘要。

实时进度 + 成本统计(P9-UX1.5)

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

诊断与初始化(P9-UX2)

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 漂移。

本地历史(P9-UX3)

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 时零访问)

数据库表:tasksactionseventscheckpointsreportsprofilesprofile_steps。所有 JSON 字段经过敏感信息过滤。

任务 Profile(P9-UX4)

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)

安全确认 + 同域限速(P9-UX5)

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 关键词/动作类型匹配可能存在误报或漏报,个人使用场景可接受。

按需视觉辅助定位(P10-1)

当 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)、targetviewportfull(仅显式开启)
  • 页面稳定 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 思考过程和完整页面文本

暂停与恢复(Pause / Resume)

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 全程在后台运行,不影响用户当前浏览:

三层防护

  1. 扩展端 active: false — 所有新标签页在后台创建,不抢焦点
  2. Rust 侧兜底恢复 — connect 后若标签页意外抢到焦点,立即恢复原活动页
  3. detect_new_tab 不激活 — 发现新标签页只更新内部引用,不激活

环境变量

变量 默认值 说明
AGENT_BROWSER_BACKGROUND 1 后台创建标签页
AGENT_BROWSER_RESTORE_FOCUS 1 启用兜底恢复焦点(设为 0 禁用)

扩展模式

通过 Chrome 扩展 + chrome.debugger API 操控浏览器,无需 --remote-debugging-port

前置条件

  1. 在 Chrome 中加载扩展:打开 chrome://extensions → 开启开发者模式 → 加载已解压的扩展程序 → 选择 extension/ 目录
  2. 确保当前活动标签页是普通网页(非 chrome:// 页面)
  3. 运行命令时加 --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.debuggerPage.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

prompt — 输出 Agent 系统提示词

agent-browser-cli prompt

直接将内置的 LLM 系统提示词输出到 stdout,可管道传给 AI 框架。

JSON 管道协议

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。字段名含 cookieauthorizationtokenpasswordsecret 或 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"}

configure 运行时切换

media_enabled 效果
true 清空拦截列表,允许加载所有资源
false 重新注入拦截黑名单

get_content — 提取页面正文

{"action": "get_content"}
{"status": "ok", "action": "get_content", "content": {"title": "...", "text": "...", "wordCount": 123, "charCount": 456, "method": "readability"}}

使用 Readability 风格算法自动识别页面正文区域,返回结构化文本。适用于:

  • 提取文章/新闻正文
  • 获取页面主要内容(去除导航/广告/侧栏噪声)
  • 为 LLM 提供可读的页面文本(而非仅交互元素)

wait_for — 等待元素出现

{"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 页面等待动态内容渲染完成。

assert_element — 断言元素内容

{"action": "assert_element", "target_id": "e5", "expected": "登录成功"}
{"status": "ok", "action": "assert_element", "result": {"passed": true, "actual": "登录成功,欢迎回来", "target_id": "e5"}}

适用于 UI 自动化测试中的断言验证。

download_setup + download — 文件下载

// 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 点击指定元素触发的下载,并等待下载完成(支持超时)。

SDK

Python

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())

TypeScript

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 注入):

CDP 启动参数层

  • --disable-blink-features=AutomationControlled — 隐藏 navigator.webdriver
  • --user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... — 真实浏览器 UA
  • window_size(1280, 720) — 标准 Windows 分辨率

JS 注入层(指纹浏览器级反检测)

通过 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 不会残留:

  1. Stdin 断开自毁 — 管道关闭时自动退出
  2. Ctrl+C 信号处理tokio::signal::ctrl_c() 优雅关闭
  3. 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 仍是原元素

用户 tab 存活测试

验证 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.pem

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages