- 人工智能
- 大模型
- LLM 网关
- AI Agent
- 即时通讯
【免费下载链接】openclaw-zero-token
OpenClaw: Use All Major AI Models NO API Token! Claude/ChatGPT/Gemini/DeepSeek/Doubao/Grok/Qwen/Manus/Kimi
本篇技术指南围绕 OpenClaw 仓库中的browser-cdp技能展开,讲解如何用一个轻量 HTTP 代理把 Chrome DevTools Protocol(CDP)封装成 REST 接口,从而在无需 Playwright / Puppeteer 等重型依赖的前提下完成网页导航、截图、JS 求值、元素点击、表单填写与 Chrome 扩展安装等真实浏览器自动化操作。读完本文,你将能独立启动 cdp_proxy.py 代理,并熟练使用/targets、/navigate、/screenshot、/eval、/click、/new六个端点搭建可复用的浏览器自动化工作流。
技能定位:SKILL.md 说了什么
browser-cdp技能的定义文件位于 skills/browser-cdp/SKILL.md。其 YAML frontmatter 声明了技能名称、触发描述与 OpenClaw 元数据:
--- name: browser-cdp description: "Control a browser via Chrome DevTools Protocol (CDP) proxy. Use when: (1) navigating to URLs and reading page content, (2) taking screenshots, (3) executing JavaScript in the browser, (4) clicking elements or filling forms, (5) searching and installing Chrome Web Store extensions, (6) interacting with web APIs that require a real browser. NOT for: simple HTTP requests (use curl), local file operations, or when no CDP proxy is available." metadata: { "openclaw": { "emoji": "🌐", "requires": { "bins": ["curl"] } } } ---这段元数据不是摆设:OpenClaw 的 Agent 技能系统会解析 SKILL.md 的 frontmatter 来决定技能何时被加载。从 src/agents/skills/frontmatter.ts 的实现看,metadata.openclaw块中的requires、emoji、always、os、install等字段都会被解析进OpenClawSkillMetadata,其中requires.bins用于声明技能运行所需的可执行文件——browser-cdp声明需要curl,因为整个技能的使用方式就是通过curl调用本地代理的 REST 接口。技能正文(Markdown 部分)则只在技能被触发后才加载,这与 skills/skill-creator/SKILL.md 中描述的 AgentSkills 规范一致。
简单概括技能的适用边界:
- 适合使用:打开 URL 并读取页面内容、截取当前页面截图、在页面上执行 JavaScript、点击按钮或填写表单、搜索并安装 Chrome 扩展、需要真实浏览器上下文来交互的网页 API。
- 不适合使用:简单 HTTP 请求(直接用
curl)、下载文件(用curl -O)、解析本地保存的 HTML(用python3配合 BeautifulSoup)、以及 CDP 代理未启动的情况(应先请用户启动代理)。
环境准备:安装依赖并启动 CDP 代理
安装 Python 依赖
cdp_proxy.py依赖psutil(用于进程信息与浏览器查找),安装命令为:
pip install psutil若未安装,脚本会在启动时直接报错退出并提示安装命令(见 cdp_proxy.py)。
启动代理
代理默认监听http://localhost:3456,从仓库根目录启动:
python3 skills/browser-cdp/scripts/cdp_proxy.py启动成功后,脚本会依次输出浏览器路径、调试端口、浏览器 PID、代理监听地址与可用端点列表。代理启动后,Chrome/Edge 会以远程调试模式(--remote-debugging-port)运行,HTTP 代理再把 CDP 命令转发到浏览器调试端口。
从源码看启动细节
cdp_proxy.py的启动逻辑比文档描述更完整,值得了解几个关键点(对应 main()):
- 命令行参数:除默认端口外,还支持
--port(代理监听端口,默认 3456)、--host(默认 127.0.0.1)、--chrome-path(显式指定浏览器可执行文件路径)、--debug-port(Chrome 调试端口,默认自动选择)。 - 浏览器自动探测:
find_chrome_path()会按平台搜索候选路径——Windows 上查找chrome.exe/msedge.exe的标准安装位置,macOS 上查找/Applications/Google Chrome.app与Microsoft Edge.app,Linux 上则依次尝试google-chrome、google-chrome-stable、chromium-browser、chromium、microsoft-edge等命令名;探测不到时脚本报错提示--chrome-path(见 find_chrome_path)。 - 空闲端口分配:
find_free_port()从 9222 开始向上扫描 100 个端口,找到第一个可用的作为调试端口(见 find_free_port)。 - 浏览器启动参数:
start_browser()会附带一组抑制干扰的 flag,包括--no-first-run、--no-default-browser-check、--disable-background-networking、--disable-popup-blocking、--disable-sync、--new-window等(见 start_browser),确保自动化场景下浏览器行为可预期。 - 就绪等待:启动后脚本以 0.5 秒间隔最多轮询 20 次,探测
http://127.0.0.1:<debug_port>/json是否可访问;超时则终止浏览器进程并报错(见 main())。
API 参考:六个 REST 端点详解
以下所有端点均相对http://localhost:3456提供。端点与底层 CDP 方法的对应关系可以从 CDPProxyHandler 中直接读出:
| 端点 | 方法 | 底层 CDP 调用 | 用途 |
|---|---|---|---|
/targets | GET | 浏览器/json列表 | 列出所有打开的浏览器标签页 |
/navigate?url=<URL> | GET | Page.navigate | 导航标签页到指定 URL |
/screenshot | GET | Page.captureScreenshot | 截取当前页面 PNG 截图 |
/eval | POST | Runtime.evaluate | 在页面中执行 JavaScript |
/click?selector=<CSS> | GET | Runtime.evaluate+element.click() | 点击匹配 CSS 选择器的元素 |
/new | GET | 浏览器/json/new | 打开新标签页并返回其 target ID |
GET /targets —— 列出所有标签页
curl -s http://localhost:3456/targets | python3 -m json.tool响应示例:
[ { "id": "ABC123", "title": "Google", "url": "https://google.com" } ]实际响应还会带上type字段(_handle_targets从/json原始列表抽取id、title、url、type,见 cdp_proxy.py)。/targets返回的id可用来配合其他端点的?target=<targetId>参数定向操作指定标签页。
GET /navigate —— 导航到 URL
curl -s "http://localhost:3456/navigate?url=https://example.com"默认使用最近创建的标签页;也可以指定目标标签页:?target=<targetId>。若未传url参数,代理返回 400 错误Missing url parameter;若当前没有可用浏览器目标,则返回No browser target available(见 cdp_proxy.py)。
GET /screenshot —— 截图
# 保存到文件 curl -s -o screenshot.png http://localhost:3456/screenshot截图以 PNG 二进制数据返回(代理内部把 CDP 返回的 base64 数据解码后以image/png直接写入响应体,见 cdp_proxy.py)。因此用curl -o保存文件时不要加-s之外的重定向干扰,直接落盘即可。
POST /eval —— 执行 JavaScript
/eval是唯一需要 POST 的端点,请求体是纯文本(非 JSON),需显式声明Content-Type: text/plain:
curl -s -X POST http://localhost:3456/eval \ -H "Content-Type: text/plain" \ -d "document.title"多行脚本可以用 stdin 管道或 heredoc 传入。/eval的语义类似 REPL:返回最后一个表达式的值。底层调用Runtime.evaluate时开启了returnByValue: true和awaitPromise: true,因此返回 Promise 的表达式也会被等待并返回其值(见 cdp_proxy.py);代理还会尝试把 JSON 字符串结果(如JSON.stringify的输出)解析为结构化 JSON 返回。如果误用 GET 访问/eval,代理会返回提示Use POST for /eval。
批量提取页面所有链接的经典写法:
curl -s -X POST http://localhost:3456/eval \ -H "Content-Type: text/plain" \ -d "JSON.stringify(Array.from(document.querySelectorAll('a')).map(a => ({text: a.innerText, href: a.href})))"GET /click —— 点击元素
curl -s "http://localhost:3456/click?selector=%23submit-btn"selector参数是 CSS 选择器,需要 URL 编码(#→%23,空格 →+或%20)。实现上代理注入一段 JS:document.querySelector(selector).click();元素不存在时返回Element not found,成功则返回{success: true}(见 cdp_proxy.py)。注意该端点使用的是 DOM 的el.click(),适用于大多数按钮/链接点击;对于依赖真实鼠标事件(如 hover 菜单)的复杂交互,可改用/eval派发MouseEvent。
GET /new —— 打开新标签页
curl -s http://localhost:3456/new响应示例:
{ "id": "NEW_TAB_ID", "title": "about:blank", "url": "about:blank" }新标签页初始为about:blank,随后可用返回的id配合/navigate定向导航(见 cdp_proxy.py)。
常见工作流实战
工作流一:导航并提取页面内容
# 打开页面 curl -s "http://localhost:3456/navigate?url=https://example.com" # 提取全部文本 curl -s -X POST http://localhost:3456/eval \ -H "Content-Type: text/plain" \ -d "document.body.innerText" # 提取所有链接(文本 + 地址) curl -s -X POST http://localhost:3456/eval \ -H "Content-Type: text/plain" \ -d "JSON.stringify([...document.querySelectorAll('a')].map(a => ({text: a.textContent.trim(), href: a.href})))"这个组合是“读取网页”类任务的最小闭环:先导航,再用document.body.innerText抓全文,或用querySelectorAll结构化抓取特定元素。由于/eval有returnByValue与 JSON 字符串自动解析,返回结果可直接交给 Agent 做后续决策。
工作流二:截取页面截图
curl -s "http://localhost:3456/navigate?url=https://example.com" curl -s -o page.png http://localhost:3456/screenshot导航后立即截图可能因页面尚未渲染完成而拿到空白图,稳妥起见可在导航与截图之间用/eval等待关键元素出现,例如轮询document.querySelector('#main') !== null。
工作流三:搜索并安装 Chrome 扩展
Chrome Web Store 的搜索不需要登录:
# 搜索扩展(URL 中空格需编码为 %20) curl -s "http://localhost:3456/navigate?url=https://chromewebstore.google.com/search/example%20extension" # 从搜索结果中提取扩展 ID curl -s -X POST http://localhost:3456/eval \ -H "Content-Type: text/plain" \ -d "JSON.stringify([...document.querySelectorAll('a[data-id]')].map(a => ({id: a.dataset.id, title: a.textContent.trim()})))" # 用扩展 ID 打开详情页 curl -s "http://localhost:3456/navigate?url=https://chromewebstore.google.com/detail/<extension-id>" # 然后点击 "Add to Chrome" 按钮(选择器需 URL 编码) curl -s "http://localhost:3456/click?selector=%5Bdata-id%3Dinstall-button%5D"注意#、[、]、=等字符在 URL 查询串里都必须正确编码(#→%23、[→%5B、]→%5D、=→%3D),否则会被当成 URL 结构字符截断参数。安装按钮点击后浏览器通常会弹出确认,可在/click之后再用/eval轮询安装状态或再次document.querySelector校验。
工作流四:填写表单并提交
# 导航到表单页 curl -s "http://localhost:3456/navigate?url=https://example.com/login" # 填充字段 curl -s -X POST http://localhost:3456/eval \ -H "Content-Type: text/plain" \ -d "document.querySelector('#username').value = 'myuser'" curl -s -X POST http://localhost:3456/eval \ -H "Content-Type: text/plain" \ -d "document.querySelector('#password').value = 'mypass'" # 提交(选择器中的空格编码为 +) curl -s "http://localhost:3456/click?selector=%23login-form+%3E+button"这里展示了?selector=%23login-form+%3E+button的编码写法:#login-form > button中的#、>与空格分别编码为%23、%3E、+。对于复杂多步交互,按 SKILL.md 的建议可以链式组合/eval与/click:每次/eval先校验页面状态,再执行下一步操作。
注意事项与故障排查
综合 SKILL.md 的 Notes 与代理源码的错误处理路径,实践中有以下要点:
- 代理必须先启动:任何端点调用前,
python3 skills/browser-cdp/scripts/cdp_proxy.py必须在运行;代理未启动时curl会连接失败,此时应请用户先启动代理。 - 没有可用标签页时的报错:若浏览器没有可用的 page 类型 target(
_get_target优先挑选type == "page"的标签页,其次回退到列表第一个 target),各端点会返回No browser target available;可先调用/new开一个新标签页(见 cdp_proxy.py)。 - 查询参数必须 URL 编码:
url、selector中的特殊字符(#、[、]、>、空格等)都需编码,否则参数解析会出错。 /eval是 REPL 语义:返回最后一个表达式的值;多语句脚本请用分号连接或写成 IIFE(立即执行函数表达式)。- 截图是 PNG 二进制:用
-o落盘,不要期望得到 JSON。 - 定向标签页:大多数端点支持
?target=<targetId>,/targets与/new返回的 ID 可用于精确控制多标签页场景。 - 信号量抑制:代理启动的浏览器关闭了弹窗、同步、后台网络等功能,某些依赖弹窗或浏览器同步的服务可能表现不同,这是自动化场景的预期行为。
从源码角度,代理的错误处理也很直白:CDP 请求失败(超时 30 秒或网络异常)时返回{"error": ...},HTTP 状态码 500;缺少必要参数(如navigate无url、click无selector)返回 400;未知端点返回 404Unknown endpoint。熟悉这些返回形态有助于在脚本中做分支判断。
小结
browser-cdp技能的价值在于把 CDP 的复杂协议面收敛成六个可被curl直接调用的 REST 端点,让 Agent 以最小的依赖成本获得真实浏览器能力。无论是抓取动态渲染的页面、执行登录态操作、安装扩展,还是编写可复现的浏览器自动化脚本,都可以基于 SKILL.md 的端点约定与 cdp_proxy.py 的实现快速落地:代理层负责浏览器生命周期与 CDP 编解码,上层只需组合navigate→eval→click→screenshot的调用链即可完成绝大多数网页交互任务。
- 人工智能
- 大模型
- LLM 网关
- AI Agent
- 即时通讯
【免费下载链接】openclaw-zero-token
OpenClaw: Use All Major AI Models NO API Token! Claude/ChatGPT/Gemini/DeepSeek/Doubao/Grok/Qwen/Manus/Kimi
相关推荐
AionUi CDP 远程调试集成指南:通过 Chrome DevTools Protocol 与 MCP 驱动应用内浏览器
AionUi CDP 远程调试集成指南:通过 Chrome DevTools Protocol 与 MCP 驱动应用内浏览器 AionUi 内置了一个可被 AI
人工智能AI 应用交互助手不存账号密码如何驱动真实浏览器:BossHunter的Chrome DevTools Protocol实战
不存账号密码如何驱动真实浏览器:BossHunter的Chrome DevTools Protocol实战 BossHunter 是一个智能求职 Agent:它
browser-harness 实战指南:让 LLM Agent 通过一条可编辑的 CDP WebSocket 直接驱动真实浏览器
browser harness 实战指南:让 LLM Agent 通过一条可编辑的 CDP WebSocket 直接驱动真实浏览器 Browser Harnes
AI 应用AI 技能浏览器控制GUI 自动化MCP 服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考