关于 opencli-operate
opencli-operate 是面向 AI Agent 的浏览器自动化技能,通过命令行逐步控制 Chrome,并复用已有登录会话。它提供结构化页面检查、交互、数据提取和 API 探索,也可将操作沉淀为可复用的 CLI adapter。
主要功能
- 01通过命令行控制 Chrome
- 02检查结构化页面状态与元素
- 03点击、输入、选择及键盘操作
- 04读取页面数据并检查网络请求
- 05生成并验证可复用 CLI adapter
适用场景
- 01使用已有登录会话操作网站
- 02填写网页表单并核对输入
- 03从页面或 API 提取数据
- 04将重复浏览任务保存为 CLI 命令
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jackwener/ opencli --skill opencli-operate安装后在 Claude Code 中输入/opencli-operate确认已加载。
详细介绍
OpenCLI Operate — 面向 AI Agent 的浏览器自动化
通过命令行逐步控制 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 operate open https://example.com && opencli operate state
# GOOD: fill form in one call (saves 2 round trips)
opencli operate type 3 "hello" && opencli operate type 4 "world" && opencli operate click 7
# GOOD: type + verify in one call
opencli operate type 5 "[email protected]" && opencli operate get value 5
# GOOD: click + wait + state in one call (for page-changing clicks)
opencli operate click 12 && opencli operate wait time 1 && opencli operate state
# BAD: separate calls for each action (wasteful)
opencli operate type 3 "hello" # Don't do this
opencli operate type 4 "world" # when you can chain
opencli operate click 7 # all three together
会改变页面的命令 — 始终放在链的最后(后续命令会看到过时的索引):
open <url>、back、click <会导航的链接/按钮>
规则:当你已经知道索引时进行串联。当需要先发现索引时,单独运行 state。
核心工作流
- 导航:
opencli operate open <url> - 检查:
opencli operate state→ 带有[N]索引的元素 - 交互:使用索引 —
click、type、select、keys - 等待(如需要):
opencli operate wait selector ".loaded"或wait text "Success" - 验证:
opencli operate state或opencli operate get value <N> - 重复:命令之间浏览器保持打开
- 保存:将 TS 适配器写入
~/.opencli/clis/<site>/<command>.ts
命令
导航
opencli operate open <url> # Open URL (page-changing)
opencli operate back # Go back (page-changing)
opencli operate scroll down # Scroll (up/down, --amount N)
opencli operate scroll up --amount 1000
检查(免费且即时)
opencli operate state # Structured DOM with [N] indices — PRIMARY tool
opencli operate screenshot [path.png] # Save visual to file — ONLY for user deliverables
获取(免费且即时)
opencli operate get title # Page title
opencli operate get url # Current URL
opencli operate get text <index> # Element text content
opencli operate get value <index> # Input/textarea value (use to verify after type)
opencli operate get html # Full page HTML
opencli operate get html --selector "h1" # Scoped HTML
opencli operate get attributes <index> # Element attributes
交互
opencli operate click <index> # Click element [N]
opencli operate type <index> "text" # Type into element [N]
opencli operate select <index> "option" # Select dropdown
opencli operate keys "Enter" # Press key (Enter, Escape, Tab, Control+a)
等待
有三种变体 — 根据情况选择合适的一种:
opencli operate wait time 3 # Wait N seconds (fixed delay)
opencli operate wait selector ".loaded" # Wait until element appears in DOM
opencli operate wait selector ".spinner" --timeout 5000 # With timeout (default 30s)
opencli operate wait text "Success" # Wait until text appears on page
何时等待:在 SPA 上执行 open 之后、触发异步加载的 click 之后,以及对动态渲染内容执行 eval 之前。
提取(免费且即时,只读)
仅使用 eval 读取数据。绝不用它来点击、输入或导航。
opencli operate eval "document.title"
opencli operate eval "JSON.stringify([...document.querySelectorAll('h2')].map(e => e.textContent))"
# IMPORTANT: wrap complex logic in IIFE to avoid "already declared" errors
opencli operate eval "(function(){ const items = [...document.querySelectorAll('.item')]; return JSON.stringify(items.map(e => e.textContent)); })()"
选择器安全:始终使用备用选择器 — querySelector 未匹配时返回 null:
# BAD: crashes if selector misses
opencli operate eval "document.querySelector('.title').textContent"
# GOOD: fallback with || or ?.
opencli operate eval "(document.querySelector('.title') || document.querySelector('h1') || {textContent:''}).textContent"
opencli operate eval "document.querySelector('.title')?.textContent ?? 'not found'"
网络(API 发现)
opencli operate network # Show captured API requests (auto-captured since open)
opencli operate network --detail 3 # Show full response body of request #3
opencli operate network --all # Include static resources
沉淀为 CLI(Save as CLI)
opencli operate init hn/top # Generate adapter scaffold at ~/.opencli/clis/hn/top.ts
opencli operate verify hn/top # Test the adapter (adds --limit 3 only if `limit` arg is defined)
init会从当前活动的浏览器会话中自动检测域名(无需手动指定)init会创建文件,并从当前页面填充site、name、domain和columnsverify会端到端运行适配器并打印输出;如果适配器中没有limit参数,则不会传入--limit 3
会话(Session)
opencli operate close # Close automation window
示例:提取 HN 故事
opencli operate open https://news.ycombinator.com
opencli operate state # See [1] a "Story 1", [2] a "Story 2"...
opencli operate eval "JSON.stringify([...document.querySelectorAll('.titleline a')].slice(0,5).map(a => ({title: a.textContent, url: a.href})))"
opencli operate close
示例:填写表单
opencli operate open https://httpbin.org/forms/post
opencli operate state # See [3] input "Customer Name", [4] input "Telephone"
opencli operate type 3 "OpenCLI" && opencli operate type 4 "555-0100"
opencli operate get value 3 # Verify: "OpenCLI"
opencli operate close
保存为可复用的 CLI:完整流程
分步沉淀流程:
# 1. Explore the website
opencli operate open https://news.ycombinator.com
opencli operate state # Understand DOM structure
# 2. Discover APIs (crucial for high-quality adapters)
opencli operate eval "fetch('/api/...').then(r=>r.json())" # Trigger API calls
opencli operate network # See captured API requests
opencli operate network --detail 0 # Inspect response body
# 3. Generate scaffold
opencli operate 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 operate verify hn/top # Runs the adapter and shows output
# 6. If verify fails, edit and retry
# 7. Close when done
opencli operate 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 operate的简写
常见误区
-
form.submit()在自动化中会失败:不要使用form.submit()或eval提交表单。请直接导航到搜索 URL:# BAD: form.submit() often silently fails opencli operate eval "document.querySelector('form').submit()" # GOOD: construct the URL and navigate opencli operate 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 operate 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 operate scroll down && opencli operate state |
| 页面变化后索引失效 | 重新运行 opencli operate state 获取最新索引 |