OpenCLI - 完整学习教程
OpenCLI - 完整学习教程
教程级别: 从零到一 预计学习时间: 4-6 小时 前置知识: 基本命令行操作、Node.js 环境配置、JavaScript/TypeScript 基础(适配器开发需要)
环境搭建指南
系统要求
- 操作系统:macOS / Linux / Windows(WSL2 推荐)
- 运行时/依赖版本:Node.js >= 21.0.0、npm >= 10.0.0
- 浏览器:Chrome 或 Chromium(需安装 Browser Bridge Extension)
安装步骤
# 1. 确认 Node.js 版本
node --version
# 需要 v21.0.0 或更高版本
# 2. 全局安装 OpenCLI
npm install -g @jackwener/opencli
# 3. 克隆仓库(用于获取 Browser Bridge Extension)
git clone https://github.com/jackwener/opencli.git
cd opencli
# 4. 安装 Browser Bridge Chrome 扩展
# 打开 Chrome,访问 chrome://extensions
# 启用右上角"开发者模式"
# 点击"加载已解压的扩展程序"
# 选择 opencli 仓库中的 extension/ 目录
验证安装
# 验证 OpenCLI 安装
opencli --version
# 预期输出:v1.7.0 或更高版本
# 验证 Browser Bridge 连接
opencli doctor
# 预期输出:
# ✅ Node.js version: v21.x.x
# ✅ Chrome Browser: Connected
# ✅ Browser Bridge: Active
# ✅ Built-in Adapters: 91 loaded
# 测试基本命令
opencli hackernews top --limit 3 --format table
预期输出:
✅ Node.js version: v21.x.x
✅ Chrome Browser: Connected
✅ Browser Bridge: Active
✅ Built-in Adapters: 91 loaded
Rank | Title | Points
------|--------------------------------|--------
1. | Show HN: I built a... | 342
2. | The future of AI agents... | 289
3. | Why Rust is gaining... | 256
第一部分:入门篇
1.1 核心概念:适配器(Adapter)
概念讲解:
适配器(Adapter)是 OpenCLI 的核心抽象。每个适配器是一个标准 JavaScript 模块,定义了"如何从特定网站提取结构化数据"的确定性规则。理解适配器是使用 OpenCLI 的基础。
适配器的关键特征: - 确定性:给定相同的页面,始终返回相同结构的数据 - 零 LLM 成本:执行时不需要调用大语言模型 - 标准化:所有适配器遵循统一的模块接口(name、description、commands) - 可组合:一个适配器可包含多个命令(如 bilibili 适配器包含 trending、search、info 等命令)
代码示例:
# 查看 OpenCLI 有哪些内置适配器
opencli list
# 使用 hackernews 适配器的 top 命令
opencli hackernews top --limit 5 --format json
# 使用 github 适配器的 repo 命令
opencli github repo jackwener/opencli --format table
# 使用不同输出格式
opencli hackernews top --limit 3 --format csv
opencli hackernews top --limit 3 --format yaml
执行结果:
[
{
"rank": "1.",
"title": "Show HN: I built a compiler in 500 lines",
"url": "https://example.com/compiler",
"points": "342 points"
},
{
"rank": "2.",
"title": "The future of AI agents in production",
"url": "https://example.com/ai-agents",
"points": "289 points"
}
]
练习题:
1. 尝试使用 opencli bilibili trending --limit 5 --format json 获取 Bilibili 热门视频列表
2. 使用 --format csv 导出 Hacker News 数据到文件:opencli hackernews top --format csv > hn.csv
1.2 Browser Bridge 与浏览器连接
概念讲解:
Browser Bridge Extension 是 OpenCLI 与浏览器之间的桥梁。它通过 Chrome Extension native messaging API 连接到用户正在运行的 Chrome 实例,实现以下关键能力:
- 复用已登录会话:不需要单独管理 Cookie 或密码,直接使用用户已登录的所有网站
- 凭据隔离:登录凭据永远不离开 Chrome 浏览器,Node.js 进程无法获取
- 正常指纹:操作看起来像正常用户行为,不容易被反爬虫系统检测
理解 Browser Bridge 是后续所有操作的基础——无论是使用内置适配器还是生成新适配器,都需要浏览器连接。
代码示例:
# 检查浏览器连接状态
opencli doctor
# 截取网页截图(验证浏览器连接)
opencli browser screenshot --url https://news.ycombinator.com --output ./hn-screenshot.png
# 在浏览器中执行 JavaScript
opencli browser eval --script "document.title"
# 查看网络请求
opencli browser network --url https://api.github.com
预期输出:
# opencli browser eval --script "document.title"
"Hacker News"
# opencli browser screenshot --url https://news.ycombinator.com --output ./hn-screenshot.png
Screenshot saved to ./hn-screenshot.png (1280x720)
注意事项:
- Chrome 浏览器必须在运行状态,Browser Bridge Extension 必须已启用
- 如果 opencli doctor 报连接失败,检查 Chrome 扩展是否已正确加载
- 首次使用需要手动加载扩展(chrome://extensions → 开发者模式 → 加载已解压的扩展程序)
练习题:
1. 执行 opencli browser eval --script "navigator.userAgent" 查看浏览器 User-Agent
2. 截取任意网页截图并保存到本地文件
第二部分:进阶篇
2.1 适配器生成四步流程
详细讲解:
OpenCLI 最强大的功能是为新网站生成适配器。这个过程分为四步,每一步都有明确的输入和输出。理解这个流程是掌握 OpenCLI 的关键。
第一步:explore(探索) 记录用户在真实浏览器中的交互行为,分析页面结构和数据位置。
# 探索目标网站
opencli explore https://lobste.rs
# 系统会打开浏览器,记录你的交互行为
# 点击、滚动、输入等操作都会被记录
# 完成后按 Ctrl+C 结束记录
预期输出:
🔍 Exploring https://lobste.rs...
✅ Recording interactions...
- Navigated to https://lobste.rs
- Clicked element: .story a
- Scrolled down (2 times)
- Detected data patterns: story titles, scores, tags
📝 Recording saved. Run `opencli synthesize` to generate draft.
第二步:synthesize(综合) 将记录的交互行为转化为适配器结构草稿。
# 从记录生成适配器草稿
opencli synthesize
预期输出:
📋 Analyzing recorded interactions...
✅ Draft adapter generated:
- Source: https://lobste.rs
- Detected commands: top, newest, search
- Data fields: title, url, score, tags, comments
📝 Draft saved. Run `opencli generate` to create final adapter.
第三步:generate(生成) AI 辅助将草稿转为完整可执行适配器代码,并自动验证。
# 生成并验证适配器
opencli generate --url https://lobste.rs --action "get story list"
预期输出:
🤖 Generating adapter with AI assistance...
✅ Adapter code generated
🧪 Running validation tests...
✅ Test 1: Navigate to lobste.rs - PASSED
✅ Test 2: Extract story titles - PASSED
✅ Test 3: Extract scores - PASSED
📝 Adapter saved to: ~/.opencli/adapters/lobsters.js
第四步:cascade(级联验证) 验证认证策略,确保适配器在生产环境中可用。
# 验证认证策略
opencli cascade
预期输出:
🔐 Checking authentication strategy for lobste.rs...
✅ Strategy: PUBLIC (no authentication required)
- Tested: GET https://lobste.rs → 200 OK
- Data extraction: PASSED
✅ Adapter lobsters is production-ready!
注意事项: - explore 步骤需要手动在浏览器中操作,确保操作覆盖了你需要的数据 - generate 步骤会消耗一次 LLM 调用(生成后不再需要) - 如果 generate 失败,可以手动编辑草稿后重新生成 - 对于需要登录的网站,cascade 步骤会检测认证策略(COOKIE/HEADER/BEARER/ADVANCED)
练习题: 1. 选择一个你常用的网站(如 Product Hunt、Reddit),尝试走完四步生成流程 2. 比较不同网站的认证策略(PUBLIC vs COOKIE)
2.2 自定义适配器开发
详细讲解:
除了四步自动生成流程,你还可以手动编写适配器。这在需要精细控制数据提取逻辑时非常有用。适配器是一个标准 JavaScript/TypeScript 模块,遵循统一的接口规范。
代码示例:
// ~/.opencli/adapters/my-custom-adapter.js
// 自定义适配器:获取 Lobsters 热门文章
module.exports = {
name: 'lobsters',
description: 'Fetch Lobsters stories',
commands: {
top: {
description: 'Get top stories from Lobsters',
options: [
{ flag: '--limit <n>', description: 'Number of stories', default: 20 }
],
execute: async (options, browser) => {
// 导航到目标页面
await browser.goto('https://lobste.rs/');
// 使用确定性 CSS 选择器提取数据
const stories = await browser.eval(`
Array.from(document.querySelectorAll('.story'))
.slice(0, ${options.limit})
.map(el => ({
title: el.querySelector('.link a')?.innerText,
url: el.querySelector('.link a')?.href,
score: el.querySelector('.score')?.innerText,
tags: Array.from(el.querySelectorAll('.tag'))
.map(t => t.innerText),
comments: el.querySelector('.comments a')?.innerText
}))
`);
return stories;
}
},
newest: {
description: 'Get newest stories from Lobsters',
options: [
{ flag: '--limit <n>', description: 'Number of stories', default: 20 }
],
execute: async (options, browser) => {
await browser.goto('https://lobste.rs/recent');
const stories = await browser.eval(`
Array.from(document.querySelectorAll('.story'))
.slice(0, ${options.limit})
.map(el => ({
title: el.querySelector('.link a')?.innerText,
url: el.querySelector('.link a')?.href,
score: el.querySelector('.score')?.innerText,
date: el.querySelector('.byline time')?.innerText
}))
`);
return stories;
}
}
}
};
# 验证自定义适配器是否被识别
opencli list | grep lobsters
# 使用自定义适配器
opencli lobsters top --limit 5 --format json
opencli lobsters newest --limit 3 --format table
预期输出:
[
{
"title": "Writing a compiler in Rust",
"url": "https://example.com/rust-compiler",
"score": "42",
"tags": ["rust", "compilers"],
"comments": "18 comments"
}
]
注意事项:
- browser.eval() 中使用标准的 DOM API(querySelector、querySelectorAll)
- 始终使用可选链(?.)防止元素不存在时崩溃
- CSS 选择器可能因网站改版而失效,需要定期检查
- v1.6.10 起推荐使用 TypeScript 格式编写适配器
练习题: 1. 为你常访问的一个网站手动编写适配器,提取列表数据 2. 为适配器添加第二个命令(如 search 或 detail)
第三部分:高级篇
3.1 AI Agent 集成
OpenCLI 提供原生 AI Agent Skill 集成,让 Claude Code 等 AI 工具能自动发现和调用 OpenCLI 命令。
# 安装 OpenCLI Skills 到 Claude Code
npx skills add jackwener/opencli
# 验证 Skills 安装
# 在 Claude Code 中,Agent 可以自动发现并调用:
# - opencli-usage: 发现可用的适配器
# - opencli-browser: 底层浏览器控制
# - opencli-oneshot: 单次执行操作
# - opencli-explorer: 完整的适配器生成工作流
Python AI Agent 集成示例:
#!/usr/bin/env python3
"""
基于官方 README 和 dev.to 文章的 AI Agent 集成示例
演示如何将 OpenCLI 作为 AI Agent 的数据采集层
"""
import subprocess
import json
import sys
def fetch_hackernews_top(limit=10):
"""通过 OpenCLI 获取 Hacker News 热门文章"""
result = subprocess.run(
["opencli", "hackernews", "top", "--limit", str(limit), "--format", "json"],
capture_output=True, text=True
)
if result.returncode == 0:
return json.loads(result.stdout)
elif result.returncode == 66:
print("警告:结果为空")
return []
elif result.returncode == 69:
print("错误:服务不可用,检查 Browser Bridge 连接")
sys.exit(1)
elif result.returncode == 77:
print("错误:需要认证")
sys.exit(1)
else:
print(f"未知错误:退出码 {result.returncode}")
print(result.stderr)
sys.exit(1)
def analyze_trends(articles):
"""简单的趋势分析(不依赖 LLM)"""
# 按分数排序
sorted_articles = sorted(
articles,
key=lambda x: int(x.get('points', '0').replace(' points', '') or '0'),
reverse=True
)
return sorted_articles[:5]
if __name__ == "__main__":
# 获取数据
articles = fetch_hackernews_top(limit=20)
# 分析趋势
top_articles = analyze_trends(articles)
# 输出结果
print("=== Hacker News 热门趋势 ===")
for i, article in enumerate(top_articles, 1):
print(f"{i}. {article.get('title', 'N/A')}")
print(f" 分数: {article.get('points', 'N/A')}")
print(f" 链接: {article.get('url', 'N/A')}")
print()
# 运行 AI Agent 脚本
python3 agent.py
预期输出:
=== Hacker News 热门趋势 ===
1. Show HN: I built a compiler in 500 lines
分数: 342 points
链接: https://example.com/compiler
2. The future of AI agents in production
分数: 289 points
链接: https://example.com/ai-agents
3.2 环境变量与配置优化
- Daemon 模式:
OPENCLI_DAEMON_PORT=9515 opencli daemon启动常驻后台服务,避免每次启动的开销 - 远程 CDP:
OPENCLI_CDP_ENDPOINT=http://remote:9222连接远程 Chrome 实例,适合无头服务器环境 - 诊断模式:
OPENCLI_DIAGNOSTIC=1开启结构化诊断,用于调试适配器失败 - 详细日志:
OPENCLI_VERBOSE=1输出详细执行日志
# 启动 Daemon 模式
OPENCLI_DAEMON_PORT=9515 opencli daemon &
# 使用 Daemon 执行命令(更快)
opencli hackernews top --limit 5
# 开启诊断模式调试适配器
OPENCLI_DIAGNOSTIC=1 opencli mysite list
# 连接远程 Chrome(CI/CD 环境推荐)
OPENCLI_CDP_ENDPOINT=http://ci-server:9222 opencli hackernews top --format json
3.3 最佳实践
- 适配器版本管理:将自定义适配器纳入 Git 版本控制,与团队共享
- 错误处理:根据退出码(0/66/69/77/78)设计不同的错误处理策略
- 输出格式选择:脚本集成用 JSON,人工查看用 table,数据导出用 CSV
- 适配器测试:生成适配器后立即验证,不要等到需要时才发现已失效
- 安全意识:评估自动化操作是否违反目标网站的服务条款
第四部分:实战项目
项目需求
构建一个技术趋势监控工具,每日自动从 Hacker News、GitHub Trending 和 arXiv 采集数据,生成结构化趋势报告。综合运用以下知识点: 1. 内置适配器使用(Hacker News、GitHub) 2. 自定义适配器开发(arXiv 适配器) 3. AI Agent 集成(Python 脚本 + 退出码处理)
项目设计
- 数据源:Hacker News(内置适配器)、GitHub Trending(内置适配器)、arXiv(自定义适配器)
- 输出格式:JSON 数据文件 + Markdown 趋势报告
- 技术选型:OpenCLI + Python 3 + cron 定时任务
- 错误处理:基于退出码的重试机制
完整实现代码
// ~/.opencli/adapters/arxiv.js
// 自定义适配器:arXiv 论文搜索(知识点2:自定义适配器开发)
module.exports = {
name: 'arxiv',
description: 'Search arXiv papers',
commands: {
search: {
description: 'Search papers by keyword',
options: [
{ flag: '--query <q>', description: 'Search query', required: true },
{ flag: '--limit <n>', description: 'Number of results', default: 10 }
],
execute: async (options, browser) => {
const url = `https://arxiv.org/search/?query=${encodeURIComponent(options.query)}&searchtype=all`;
await browser.goto(url);
const papers = await browser.eval(`
Array.from(document.querySelectorAll('.arxiv-result'))
.slice(0, ${options.limit})
.map(el => ({
title: el.querySelector('.title')?.innerText?.trim(),
authors: el.querySelector('.authors')?.innerText?.trim(),
abstract: el.querySelector('.abstract-short')?.innerText?.trim(),
url: el.querySelector('p.list-title a')?.href,
published: el.querySelector('.is-size-7')?.innerText?.trim()
}))
`);
return papers;
}
}
}
};
#!/usr/bin/env python3
"""
tech_trends.py — 技术趋势监控工具
知识点1:内置适配器使用 + 退出码处理
知识点2:自定义适配器(arXiv)
知识点3:AI Agent 集成
"""
import subprocess
import json
import sys
from datetime import datetime
from pathlib import Path
def run_opencli(adapter, command, args=None, fmt="json"):
"""
通用 OpenCLI 调用函数
知识点1:使用内置适配器 + 标准退出码处理
"""
cmd = ["opencli", adapter, command, "--format", fmt]
if args:
for k, v in args.items():
cmd.extend([f"--{k}", str(v)])
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
if result.returncode == 0:
return json.loads(result.stdout) if fmt == "json" else result.stdout
elif result.returncode == 66:
print(f" 警告:{adapter} {command} 返回空结果")
return []
elif result.returncode == 69:
print(f" 错误:{adapter} {command} 服务不可用")
return []
elif result.returncode == 77:
print(f" 错误:{adapter} {command} 需要认证")
return []
else:
print(f" 错误:{adapter} {command} 执行失败 (退出码: {result.returncode})")
return []
def collect_hackernews():
"""采集 Hacker News 热门文章"""
print("📡 采集 Hacker News...")
articles = run_opencli("hackernews", "top", {"limit": 10})
return {"source": "Hacker News", "articles": articles}
def collect_github():
"""采集 GitHub 热门仓库"""
print("📡 采集 GitHub Trending...")
repos = run_opencli("github", "trending", {"limit": 10})
return {"source": "GitHub Trending", "repos": repos}
def collect_arxiv():
"""
采集 arXiv AI 论文
知识点2:使用自定义适配器
"""
print("📡 采集 arXiv AI 论文...")
papers = run_opencli("arxiv", "search", {"query": "AI agent", "limit": 5})
return {"source": "arXiv", "papers": papers}
def generate_report(data_list):
"""生成 Markdown 趋势报告"""
date_str = datetime.now().strftime("%Y-%m-%d")
report = f"# 技术趋势日报 — {date_str}\n\n"
for data in data_list:
source = data["source"]
report += f"## {source}\n\n"
if source == "Hacker News":
for i, article in enumerate(data.get("articles", []), 1):
title = article.get("title", "N/A")
points = article.get("points", "N/A")
url = article.get("url", "")
report += f"{i}. **{title}** ({points})\n {url}\n\n"
elif source == "GitHub Trending":
for i, repo in enumerate(data.get("repos", []), 1):
name = repo.get("name", "N/A")
stars = repo.get("stars", "N/A")
desc = repo.get("description", "")
report += f"{i}. **{name}** (⭐{stars})\n {desc}\n\n"
elif source == "arXiv":
for i, paper in enumerate(data.get("papers", []), 1):
title = paper.get("title", "N/A")
authors = paper.get("authors", "")
report += f"{i}. **{title}**\n {authors}\n\n"
return report
if __name__ == "__main__":
# 知识点3:AI Agent 集成 — 作为自动化工作流的一部分
print(f"=== 技术趋势监控 — {datetime.now().strftime('%Y-%m-%d %H:%M')} ===\n")
# 采集数据
data_sources = []
data_sources.append(collect_hackernews())
data_sources.append(collect_github())
data_sources.append(collect_arxiv())
# 保存原始 JSON 数据
output_dir = Path("./trends-data")
output_dir.mkdir(exist_ok=True)
date_str = datetime.now().strftime("%Y-%m-%d")
json_path = output_dir / f"{date_str}.json"
with open(json_path, "w", encoding="utf-8") as f:
json.dump(data_sources, f, ensure_ascii=False, indent=2)
print(f"\n💾 JSON 数据已保存: {json_path}")
# 生成 Markdown 报告
report = generate_report(data_sources)
md_path = output_dir / f"{date_str}.md"
with open(md_path, "w", encoding="utf-8") as f:
f.write(report)
print(f"📄 Markdown 报告已保存: {md_path}")
# 设置 cron 定时任务(每天早上 9 点执行)
# crontab -e
# 添加以下行:
# 0 9 * * * cd /path/to/project && python3 tech_trends.py >> /var/log/trends.log 2>&1
# 手动运行测试
python3 tech_trends.py
预期输出:
=== 技术趋势监控 — 2026-04-13 10:00:00 ===
📡 采集 Hacker News...
📡 采集 GitHub Trending...
📡 采集 arXiv AI 论文...
💾 JSON 数据已保存: trends-data/2026-04-13.json
📄 Markdown 报告已保存: trends-data/2026-04-13.md
代码解析
run_opencli()函数 — 运用了知识点1(内置适配器使用)和退出码处理(0/66/69/77/78)collect_arxiv()函数 — 运用了知识点2(自定义适配器),调用我们编写的 arXiv 适配器- 整个脚本的自动化工作流 — 运用了知识点3(AI Agent 集成),可作为 AI Agent 的数据采集层或 cron 定时任务
扩展挑战
- 添加邮件通知功能,在报告生成后自动发送到指定邮箱
- 增加数据去重和历史对比功能,识别"持续热门"的趋势话题
- 将 JSON 数据存入数据库(SQLite),构建长期趋势可视化仪表板
第五部分:常见问题与排查指南
常见错误及解决方案
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
Browser Bridge: Not Connected |
Chrome 扩展未加载或浏览器未运行 | 打开 Chrome → chrome://extensions → 确认 Browser Bridge 已启用 |
Error: CDP connection failed |
Chrome DevTools Protocol 连接失败 | 检查 Chrome 是否运行,重启 Chrome 和 Browser Bridge 扩展 |
Exit code 66: Empty result |
适配器执行成功但未提取到数据 | 检查 CSS 选择器是否正确,网站结构可能已变更 |
Exit code 69: Unavailable |
目标网站不可访问 | 检查网络连接和目标网站是否可正常访问 |
Exit code 77: Auth required |
目标页面需要登录 | 确保在 Chrome 中已登录目标网站,刷新登录状态 |
Exit code 78: Config error |
配置错误 | 检查环境变量和适配器配置文件语法 |
TypeError: Cannot read property of null |
CSS 选择器匹配失败 | 网站结构变更,使用 opencli explore 重新分析页面 |
调试技巧
-
开启诊断模式:设置
OPENCLI_DIAGNOSTIC=1环境变量,获取结构化错误信息(包括 DOM 快照和执行上下文)bash OPENCLI_DIAGNOSTIC=1 opencli hackernews top --limit 5 -
开启详细日志:设置
OPENCLI_VERBOSE=1,查看完整的执行过程和浏览器通信细节bash OPENCLI_VERBOSE=1 opencli hackernews top --limit 5 -
逐步调试适配器:使用
browser eval手动测试 CSS 选择器,确认数据提取逻辑正确bash # 先导航到页面 opencli browser screenshot --url https://target-site.com # 然后测试选择器 opencli browser eval --script "document.querySelectorAll('.title').length"
第六部分:学习路线推荐
官方文档推荐阅读顺序
- GitHub README — 快速入门、安装步骤、核心概念
- docs/guide/getting-started.md — 环境搭建、Browser Bridge 配置
- docs/guide/plugins.md — 插件开发、社区适配器贡献
- 内置适配器源码(clis/ 目录) — 学习适配器编写模式,推荐从简单的 hackernews.js 开始
- skills/ 目录 — 理解 AI Agent Skill 集成机制
推荐进阶资源
- dev.to 深度文章:OpenCLI 架构详解 — 涵盖 Self-Repair Protocol、四步生成流程、设计哲学
- Apiyi.com 五大核心能力详解 — 双引擎架构、AI Agent 集成模式、认证策略
- GitHub Issues — 社区常见问题和功能讨论