关于 qiaomu-opencli-browser
qiaomu-opencli-browser 是供 AI Agent 使用的浏览器自动化技能,通过 OpenCLI 命令行控制 Chrome。它可检查页面结构、与元素交互、发现网络 API,并将浏览过程整理为可复用的 CLI 适配器。
主要功能
- 01通过命令行控制 Chrome
- 02结构化 DOM 检查
- 03页面交互与数据提取
- 04网络 API 发现
- 05创建可复用 CLI 适配器
适用场景
- 01自动执行浏览器工作流
- 02提取网页数据
- 03探索 API 并构建 CLI 适配器
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ joeseesun/ qiaomu-opencli-skills --skill qiaomu-opencli-browser安装后在 Claude Code 中输入/qiaomu-opencli-browser确认已加载。
详细介绍
OpenCLI Browser — 面向 AI Agent 的浏览器自动化
通过 CLI 逐步控制 Chrome。复用现有登录会话,无需密码。
前置条件
opencli doctor # Verify extension + daemon connectivity
要求:Chrome 正在运行,并已安装 OpenCLI Browser Bridge 扩展。
关键规则
- 始终使用
state检查页面,绝不要使用screenshot—state会返回带有[N]元素索引的结构化 DOM,速度快且不消耗 token。screenshot需要进行视觉处理,速度较慢。只有用户明确要求保存视觉图像时,才使用screenshot。 - 始终使用
click/type/select进行交互,绝不要使用eval来点击或输入 —eval "el.click()"会绕过 scrollIntoView 和 CDP 点击流程,导致屏幕外元素操作失败。使用state查找[N]索引,然后执行click <N>。 - 使用
get value而非截图验证输入 — 执行type后,运行get value <index>进行确认。 - 每次页面变化后都运行
state— 执行open、click(针对链接)或scroll后,始终运行state,查看新元素及其索引。绝不要猜测索引。 - 尽可能使用
&&链接命令 — 将open + state、多个type调用以及type + get value合并到单个&&链中。每次工具调用都有开销;链接命令可以减少开销。 eval仅供只读使用 —eval只能用于提取数据(JSON.stringify(...)),绝不能用于点击、输入或导航。始终将其包装在 IIFE 中以避免变量冲突:eval "(function(){ const x = ...; return JSON.stringify(x); })()"。- 尽量减少工具调用总数 — 操作前规划好步骤。完成一项任务通常需要 3-5 次工具调用,而非 15-20 次。将
open + state合并为一次调用。将type + type + click合并为一次调用。只有需要发现新索引时,才单独运行state。 - 优先使用
network发现 API — 大多数网站都有 JSON API。基于 API 的适配器比 DOM 抓取更可靠。
命令开销指南
| 开销 | 命令 | 使用时机 |
|---|---|---|
| 免费且即时 | state、get *、eval、network、scroll、keys | 默认使用这些命令 |
| 免费但会更改页面 | open、click、type、select、back | 交互后运行 state |
| 开销高(视觉 token) | screenshot | 仅当用户需要保存图像时使用 |
操作链接规则
命令可以通过 && 链接。浏览器通过守护进程保持运行,因此可以安全地链接命令。
尽可能始终链接命令 — 工具调用越少,完成越快:
# GOOD: open + inspect in one call (saves 1 round trip)
opencli browser open https://example.com && opencli browser state
# GOOD: fill form in one call (saves 2 round trips)
opencli browser type 3 "hello" && opencli browser type 4 "world" && opencli browser click 7
# GOOD: type + verify in one call
opencli browser type 5 "[email protected]" && opencli browser get value 5
# GOOD: click + wait + state in one call (for page-changing clicks)
opencli browser click 12 && opencli browser wait time 1 && opencli browser state
# BAD: separate calls for each action (wasteful)
opencli browser type 3 "hello" # Don't do this
opencli browser type 4 "world" # when you can chain
opencli browser click 7 # all three together
会更改页面的命令 — 始终放在命令链末尾(后续命令会看到过期的索引):
open <url>、back、click <link/button that navigates>
规则:已知索引时进行链接。需要先发现索引时,单独运行 state。
核心工作流
- 导航:
opencli browser open <url> - 检查:
opencli browser state→ 带有[N]索引的元素 - 交互:使用索引 —
click、type、select、keys - 等待(如有需要):
opencli browser wait selector ".loaded"或wait text "Success" - 验证:
opencli browser state或opencli browser get value <N> - 重复:浏览器会在各命令之间保持打开
- 保存:将 TS 适配器写入
~/.opencli/clis/<site>/<command>.ts
命令
导航
opencli browser open <url> # Open URL (page-changing)
opencli browser back # Go back (page-changing)
opencli browser scroll down # Scroll (up/down, --amount N)
opencli browser scroll up --amount 1000
检查(免费且即时)
opencli browser state # Structured DOM with [N] indices — PRIMARY tool
opencli browser screenshot [path.png] # Save visual to file — ONLY for user deliverables
获取(免费且即时)
opencli browser get title # Page title
opencli browser get url # Current URL
opencli browser get text <index> # Element text content
opencli browser get value <index> # Input/textarea value (use to verify after type)
opencli browser get html # Full page HTML
opencli browser get html --selector "h1" # Scoped HTML
opencli browser get attributes <index> # Element attributes
交互
opencli browser click <index> # Click element [N]
opencli browser type <index> "text" # Type into element [N]
opencli browser select <index> "option" # Select dropdown
opencli browser keys "Enter" # Press key (Enter, Escape, Tab, Control+a)
等待
有三种方式 — 根据情况选择合适的方式:
opencli browser wait time 3 # Wait N seconds (fixed delay)
opencli browser wait selector ".loaded" # Wait until element appears in DOM
opencli browser wait selector ".spinner" --timeout 5000 # With timeout (default 30s)
opencli browser wait text "Success" # Wait until text appears on page
何时等待:在 SPA 上执行 open 后、执行会触发异步加载的 click 后,以及对动态渲染内容执行 eval 前。
提取(免费且即时,只读)
eval 只能用于读取数据。绝不能用它来点击、输入或导航。
opencli browser eval "document.title"
opencli browser eval "JSON.stringify([...document.querySelectorAll('h2')].map(e => e.textContent))"
# IMPORTANT: wrap complex logic in IIFE to avoid "already declared" errors
opencli browser eval "(function(){ const items = [...document.querySelectorAll('.item')]; return JSON.stringify(items.map(e => e.textContent)); })()"
选择器安全性:始终使用备用选择器 — querySelector 未匹配时会返回 null:
# BAD: crashes if selector misses
opencli browser eval "document.querySelector('.title').textContent"
# GOOD: fallback with || or ?.
opencli browser eval "(document.querySelector('.title') || document.querySelector('h1') || {textContent:''}).textContent"
opencli browser eval "document.querySelector('.title')?.textContent ?? 'not found'"
网络(API 发现)
opencli browser network # Show captured API requests (auto-captured since open)
opencli browser network --detail 3 # Show full response body of request #3
opencli browser network --all # Include static resources
沉淀(保存为 CLI)
opencli browser init hn/top # Generate adapter scaffold at ~/.opencli/clis/hn/top.ts
opencli browser verify hn/top # Test the adapter (adds --limit 3 only if `limit` arg is defined)
init会从当前活动的浏览器会话中自动检测域名(无需指定)init会创建文件,并根据当前页面填充site、name、domain和columnsverify会端到端运行适配器并打印输出;如果适配器中没有limit参数,就不会传递--limit 3
会话
opencli browser close # Close automation window
示例:提取 HN 故事
opencli browser open https://news.ycombinator.com
opencli browser state # See [1] a "Story 1", [2] a "Story 2"...
opencli browser eval "JSON.stringify([...document.querySelectorAll('.titleline a')].slice(0,5).map(a => ({title: a.textContent, url: a.href})))"
opencli browser close
示例:填写表单
opencli browser open https://httpbin.org/forms/post
opencli browser state # See [3] input "Customer Name", [4] input "Telephone"
opencli browser type 3 "OpenCLI" && opencli browser type 4 "555-0100"
opencli browser get value 3 # Verify: "OpenCLI"
opencli browser close
保存为可复用 CLI — 完整工作流
分步沉淀流程:
# 1. Explore the website
opencli browser open https://news.ycombinator.com
opencli browser state # Understand DOM structure
# 2. Discover APIs (crucial for high-quality adapters)
opencli browser eval "fetch('/api/...').then(r=>r.json())" # Trigger API calls
opencli browser network # See captured API requests
opencli browser network --detail 0 # Inspect response body
# 3. Generate scaffold
opencli browser init hn/top # Creates ~/.opencli/clis/hn/top.ts
# 4. Edit the adapter (fill in func logic)
# - If API found: use fetch() directly (Strategy.PUBLIC or COOKIE)
# - If no API: use page.evaluate() for DOM extraction (Strategy.UI)
# 5. Verify
opencli browser verify hn/top # Runs the adapter and shows output
# 6. If verify fails, edit and retry
# 7. Close when done
opencli browser close
适配器示例:
// ~/.opencli/clis/hn/top.ts
import { cli, Strategy } from '@jackwener/opencli/registry';
cli({
site: 'hn',
name: 'top',
description: 'Top Hacker News stories',
domain: 'news.ycombinator.com',
strategy: Strategy.PUBLIC,
browser: false,
args: [{ name: 'limit', type: 'int', default: 5 }],
columns: ['rank', 'title', 'score', 'url'],
func: async (_page, kwargs) => {
const limit = Math.min(Math.max(1, kwargs.limit ?? 5), 50);
const resp = await fetch('https://hacker-news.firebaseio.com/v0/topstories.json');
const ids = await resp.json();
return Promise.all(
ids.slice(0, limit).map(async (id: number, i: number) => {
const item = await (await fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json`)).json();
return { rank: i + 1, title: item.title, score: item.score, url: item.url ?? '' };
})
);
},
});
保存到 ~/.opencli/clis/<site>/<command>.ts → 即可立即通过 opencli <site> <command> 使用。
策略指南
| 策略 | 适用场景 | browser: |
|---|---|---|
Strategy.PUBLIC | 公共 API,无需身份验证 | false |
Strategy.COOKIE | 需要登录 Cookie | true |
Strategy.UI | 直接操作 DOM | true |
始终优先使用 API,而非 UI — 如果你在浏览过程中发现了 API,请直接使用 fetch()。
提示
- 始终先运行
state— 切勿猜测元素索引,务必先检查 - 会话会持续保留 — 浏览器会在命令之间保持打开,无需重新打开
- 使用
eval提取数据 —eval "JSON.stringify(...)"比多次调用get更快 - 使用
network查找 API — JSON API 比 DOM 抓取更可靠 - 别名:
opencli op是opencli browser的简写
常见问题
-
自动化中
form.submit()会失败 — 不要使用form.submit()或eval提交表单。请直接导航到搜索 URL:# BAD: form.submit() often silently fails opencli browser eval "document.querySelector('form').submit()" # GOOD: construct the URL and navigate opencli browser open "https://github.com/search?q=opencli&type=repositories" -
GitHub DOM 经常变化 — 如果有
data-testid属性,请优先使用;它们比类名或标签结构更稳定。 -
SPA 页面提取前需要
wait— 在单页应用中执行open或click后,DOM 不会立即就绪。执行eval前,务必使用wait selector或wait text。 -
点击前先运行
state— 运行opencli browser state,检查可用的交互元素及其索引。切勿凭记忆猜测索引。 -
evaluate在浏览器上下文中运行 — 适配器中的page.evaluate()会在浏览器内执行。Node.js API(fs、path、process)不可用。网络调用请使用fetch(),页面数据请使用 DOM API。 -
page.evaluate中的反引号会破坏 JSON 存储 — 编写需要以 JSON 格式存储或传输的适配器时,请避免在page.evaluate中使用模板字面量。请使用字符串拼接或函数形式的 evaluate:// BAD: template literal backticks break when adapter is in JSON page.evaluate(`document.querySelector("${selector}")`) // GOOD: function-style evaluate page.evaluate((sel) => document.querySelector(sel), selector)
故障排除
| 错误 | 解决方法 |
|---|---|
| "Browser not connected" | 运行 opencli doctor |
| "attach failed: chrome-extension://" | 暂时禁用 1Password |
| 未找到元素 | opencli browser scroll down && opencli browser state |
| 页面更改后索引失效 | 再次运行 opencli browser state 获取最新索引 |