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 实例,实现以下关键能力:

  1. 复用已登录会话:不需要单独管理 Cookie 或密码,直接使用用户已登录的所有网站
  2. 凭据隔离:登录凭据永远不离开 Chrome 浏览器,Node.js 进程无法获取
  3. 正常指纹:操作看起来像正常用户行为,不容易被反爬虫系统检测

理解 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 启动常驻后台服务,避免每次启动的开销
  • 远程 CDPOPENCLI_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 最佳实践

  1. 适配器版本管理:将自定义适配器纳入 Git 版本控制,与团队共享
  2. 错误处理:根据退出码(0/66/69/77/78)设计不同的错误处理策略
  3. 输出格式选择:脚本集成用 JSON,人工查看用 table,数据导出用 CSV
  4. 适配器测试:生成适配器后立即验证,不要等到需要时才发现已失效
  5. 安全意识:评估自动化操作是否违反目标网站的服务条款

第四部分:实战项目

项目需求

构建一个技术趋势监控工具,每日自动从 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

代码解析

  1. run_opencli() 函数 — 运用了知识点1(内置适配器使用)和退出码处理(0/66/69/77/78)
  2. collect_arxiv() 函数 — 运用了知识点2(自定义适配器),调用我们编写的 arXiv 适配器
  3. 整个脚本的自动化工作流 — 运用了知识点3(AI Agent 集成),可作为 AI Agent 的数据采集层或 cron 定时任务

扩展挑战

  1. 添加邮件通知功能,在报告生成后自动发送到指定邮箱
  2. 增加数据去重和历史对比功能,识别"持续热门"的趋势话题
  3. 将 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 重新分析页面

调试技巧

  1. 开启诊断模式:设置 OPENCLI_DIAGNOSTIC=1 环境变量,获取结构化错误信息(包括 DOM 快照和执行上下文) bash OPENCLI_DIAGNOSTIC=1 opencli hackernews top --limit 5

  2. 开启详细日志:设置 OPENCLI_VERBOSE=1,查看完整的执行过程和浏览器通信细节 bash OPENCLI_VERBOSE=1 opencli hackernews top --limit 5

  3. 逐步调试适配器:使用 browser eval 手动测试 CSS 选择器,确认数据提取逻辑正确 bash # 先导航到页面 opencli browser screenshot --url https://target-site.com # 然后测试选择器 opencli browser eval --script "document.querySelectorAll('.title').length"


第六部分:学习路线推荐

官方文档推荐阅读顺序

  1. GitHub README — 快速入门、安装步骤、核心概念
  2. docs/guide/getting-started.md — 环境搭建、Browser Bridge 配置
  3. docs/guide/plugins.md — 插件开发、社区适配器贡献
  4. 内置适配器源码(clis/ 目录) — 学习适配器编写模式,推荐从简单的 hackernews.js 开始
  5. skills/ 目录 — 理解 AI Agent Skill 集成机制

推荐进阶资源