🚀 快速安装
复制以下命令并运行,立即安装此 Skill:
npx skills add https://skills.sh/aradotso/trending-skills/opencli-web-automation
💡 提示:需要 Node.js 和 NPM
OpenCLI 网页自动化 (OpenCLI Web Automation)
技能来自 ara.so — Daily 2026 Skills 合集
OpenCLI 通过复用 Chrome 已登录的浏览器会话,将任何网站转换为命令行界面。它开箱即用地支持 19 个站点和 80 多个命令,并允许您通过将 TypeScript 或 YAML 文件放入 clis/ 文件夹来添加新的适配器。
安装 (Installation)
# 通过 npm 全局安装 (Install globally via npm)
npm install -g @jackwener/opencli
# 一次性设置:发现 Playwright MCP 令牌并分发到所有工具
# (One-time setup: discovers Playwright MCP token and distributes to all tools)
opencli setup
# 验证一切正常 (Verify everything is working)
opencli doctor --live
前提条件 (Prerequisites)
- Node.js >= 18.0.0
- Chrome 浏览器正在运行并登录到目标网站 (running and logged into the target site)
- Chrome 中已安装 Playwright MCP Bridge 扩展程序
从源码安装(开发)(Install from Source – Development)
git clone git@github.com:jackwener/opencli.git
cd opencli
npm install
npm run build
npm link
环境配置 (Environment Configuration)
# 必需:在运行 opencli setup 后,在 ~/.zshrc 或 ~/.bashrc 中设置
# (Required: set in ~/.zshrc or ~/.bashrc after running opencli setup)
export PLAYWRIGHT_MCP_EXTENSION_TOKEN="<your-token-from-setup>"
MCP 客户端配置(Claude/Cursor/Codex ~/.config/*/config.json)(MCP client config – Claude/Cursor/Codex ~/.config/*/config.json):
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["-y", "@playwright/mcp@latest", "--extension"],
"env": {
"PLAYWRIGHT_MCP_EXTENSION_TOKEN": "$PLAYWRIGHT_MCP_EXTENSION_TOKEN"
}
}
}
}
关键 CLI 命令 (Key CLI Commands)
发现与注册表 (Discovery & Registry)
opencli list # 显示所有已注册的命令 (Show all registered commands)
opencli list -f yaml # 以 YAML 格式输出注册表 (Output registry as YAML)
opencli list -f json # 以 JSON 格式输出注册表 (Output registry as JSON)
运行内置命令 (Running Built-in Commands)
# 公共 API 命令(无需浏览器登录)(Public API commands - no browser login needed)
opencli hackernews top --limit 10
opencli github search "playwright automation"
opencli bbc news
# 浏览器命令(必须在 Chrome 中登录网站)(Browser commands - must be logged into site in Chrome)
opencli bilibili hot --limit 5
opencli twitter trending
opencli zhihu hot -f json
opencli reddit frontpage --limit 20
opencli xiaohongshu search "TypeScript"
opencli youtube search "browser automation"
opencli linkedin search "senior engineer"
输出格式 (Output Formats)
所有命令都支持 --format / -f:
opencli bilibili hot -f table # 丰富的终端表格(默认)(Rich terminal table - default)
opencli bilibili hot -f json # JSON(可管道到 jq)(JSON - pipe to jq)
opencli bilibili hot -f yaml # YAML
opencli bilibili hot -f md # Markdown
opencli bilibili hot -f csv # CSV 导出 (CSV export)
opencli bilibili hot -v # 详细模式:显示管道调试步骤 (Verbose: show pipeline debug steps)
AI 智能体工作流(创建新命令)(AI Agent Workflow – Creating New Commands)
# 1. 深度探索一个网站 — 发现 API、认证、功能 (Deep explore a site — discovers APIs, auth, capabilities)
opencli explore https://example.com --site mysite
# 2. 从探索工件合成 YAML 适配器 (Synthesize YAML adapters from explore artifacts)
opencli synthesize mysite
# 3. 一步到位:探索 → 合成 → 注册 (One-shot: explore → synthesize → register in one command)
opencli generate https://example.com --goal "hot posts"
# 4. 策略级联 — 自动探测 PUBLIC → COOKIE → HEADER 认证
# (Strategy cascade — auto-probes PUBLIC → COOKIE → HEADER auth)
opencli cascade https://api.example.com/data
探索工件保存到 .opencli/explore/<site>/:
manifest.json— 站点元数据 (site metadata)endpoints.json— 发现的 API 端点 (discovered API endpoints)capabilities.json— 推断的命令功能 (inferred command capabilities)auth.json— 认证策略 (authentication strategy)
添加新适配器 (Adding a New Adapter)
选项 1:YAML 声明式适配器 (Option 1: YAML Declarative Adapter)
将一个 .yaml 文件放入 clis/ — 下次运行时自动注册:
# clis/producthunt.yaml
site: producthunt
commands:
- name: trending
description: 获取 Product Hunt 上的热门产品 (Get trending products on Product Hunt)
args:
- name: limit
type: number
default: 10
pipeline:
- type: navigate
url: https://www.producthunt.com
- type: waitFor
selector: "[data-test='post-item']"
- type: extract
selector: "[data-test='post-item']"
fields:
name:
selector: "h3"
type: text
tagline:
selector: "p"
type: text
votes:
selector: "[data-test='vote-button']"
type: text
url:
selector: "a"
attr: href
- type: limit
count: "{{limit}}"
选项 2:TypeScript 适配器 (Option 2: TypeScript Adapter)
// clis/producthunt.ts
import type { CLIAdapter } from "../src/types";
const adapter: CLIAdapter = {
site: "producthunt",
commands: [
{
name: "trending",
description: "获取 Product Hunt 上的热门产品 (Get trending products on Product Hunt)",
options: [
{
flags: "--limit <n>",
description: "结果数量 (Number of results)",
defaultValue: "10",
},
],
async run(options, browser) {
const page = await browser.currentPage();
await page.goto("https://www.producthunt.com");
await page.waitForSelector("[data-test='post-item']");
const products = await page.evaluate(() => {
return Array.from(
document.querySelectorAll("[data-test='post-item']")
).map((el) => ({
name: el.querySelector("h3")?.textContent?.trim() ?? "",
tagline: el.querySelector("p")?.textContent?.trim() ?? "",
votes:
el
.querySelector("[data-test='vote-button']")
?.textContent?.trim() ?? "",
url:
(el.querySelector("a") as HTMLAnchorElement)?.href ?? "",
}));
});
return products.slice(0, Number(options.limit));
},
},
],
};
export default adapter;
常见模式 (Common Patterns)
模式:认证的 API 提取(Cookie 注入)(Pattern: Authenticated API Extraction – Cookie Injection)
// 当站点公开 JSON API 但需要登录 cookie 时 (When a site exposes a JSON API but requires login cookies)
async run(options, browser) {
const page = await browser.currentPage();
// 先导航以确保 cookie 处于活动状态 (Navigate first to ensure cookies are active)
await page.goto("https://api.example.com");
const data = await page.evaluate(async () => {
const res = await fetch("/api/v1/feed?limit=20", {
credentials: "include", // 重用浏览器 cookie (reuse browser cookies)
});
return res.json();
});
return data.items;
}
模式:Header 令牌提取 (Pattern: Header Token Extraction)
// 从浏览器存储中提取认证令牌用于 API 调用 (Extract auth tokens from browser storage for API calls)
async run(options, browser) {
const page = await browser.currentPage();
await page.goto("https://example.com");
const token = await page.evaluate(() => {
return localStorage.getItem("auth_token") ||
sessionStorage.getItem("token");
});
const data = await page.evaluate(async (tok) => {
const res = await fetch("/api/data", {
headers: { Authorization: `Bearer ${tok}` },
});
return res.json();
}, token);
return data;
}
模式:带等待的 DOM 抓取 (Pattern: DOM Scraping with Wait)
async run(options, browser) {
const page = await browser.currentPage();
await page.goto("https://news.ycombinator.com");
// 等待动态内容加载 (Wait for dynamic content to load)
await page.waitForSelector(".athing", { timeout: 10000 });
return page.evaluate((limit) => {
return Array.from(document.querySelectorAll(".athing"))
.slice(0, limit)
.map((row) => ({
title: row.querySelector(".titleline a")?.textContent?.trim(),
url: (row.querySelector(".titleline a") as HTMLAnchorElement)?.href,
score:
row.nextElementSibling
?.querySelector(".score")
?.textContent?.trim() ?? "0",
}));
}, Number(options.limit));
}
模式:分页 (Pattern: Pagination)
async run(options, browser) {
const page = await browser.currentPage();
const results = [];
let pageNum = 1;
while (results.length < Number(options.limit)) {
await page.goto(`https://example.com/posts?page=${pageNum}`);
await page.waitForSelector(".post-item");
const items = await page.evaluate(() =>
Array.from(document.querySelectorAll(".post-item")).map((el) => ({
title: el.querySelector("h2")?.textContent?.trim(),
url: (el.querySelector("a") as HTMLAnchorElement)?.href,
}))
);
if (items.length === 0) break;
results.push(...items);
pageNum++;
}
return results.slice(0, Number(options.limit));
}
维护命令 (Maintenance Commands)
# 诊断所有工具的令牌和配置 (Diagnose token and config across all tools)
opencli doctor
# 测试实时浏览器连接 (Test live browser connectivity)
opencli doctor --live
# 交互式修复不匹配的配置 (Fix mismatched configs interactively)
opencli doctor --fix
# 非交互式修复所有配置 (Fix all configs non-interactively)
opencli doctor --fix -y
测试 (Testing)
npm run build
# 运行所有测试 (Run all tests)
npx vitest run
# 仅单元测试 (Unit tests only)
npx vitest run src/
# 仅端到端测试 (E2E tests only)
npx vitest run tests/e2e/
# CI 的无头浏览器模式 (Headless browser mode for CI)
OPENCLI_HEADLESS=1 npx vitest run tests/e2e/
故障排除 (Troubleshooting)
| 症状 (Symptom) | 修复 (Fix) |
|---|---|
Failed to connect to Playwright MCP Bridge |
确保扩展程序已在 Chrome 中启用;安装后重启 Chrome (Ensure extension is enabled in Chrome; restart Chrome after install) |
空数据 / Unauthorized (Empty data / Unauthorized) |
打开 Chrome,导航到网站,登录或刷新页面 (Open Chrome, navigate to the site, log in or refresh the page) |
| Node API 错误 (Node API errors) | 升级到 Node.js >= 18 (Upgrade to Node.js >= 18) |
| 找不到令牌 (Token not found) | 运行 opencli setup 或 opencli doctor --fix |
| 登录会话过期 (Stale login session) | 在 Chrome 中访问目标网站并与之交互,以证明人为存在 (Visit the target site in Chrome and interact with it to prove human presence) |
调试详细模式 (Debug Verbose Mode)
# 查看完整的管道执行步骤 (See full pipeline execution steps)
opencli bilibili hot -v
# 检查探索发现的内容 (Check what explore discovered)
cat .opencli/explore/mysite/endpoints.json
cat .opencli/explore/mysite/auth.json
项目结构(供适配器作者参考)(Project Structure – for Adapter Authors)
opencli/
├── clis/ # 将 .ts 或 .yaml 适配器放入此文件夹(自动注册)(Drop .ts or .yaml adapters here - auto-registered)
│ ├── bilibili.ts
│ ├── twitter.ts
│ └── hackernews.yaml
├── src/
│ ├── types.ts # CLIAdapter、Command 接口 (CLIAdapter, Command interfaces)
│ ├── browser.ts # Playwright MCP 桥接包装器 (Playwright MCP bridge wrapper)
│ ├── loader.ts # 动态适配器加载器 (Dynamic adapter loader)
│ └── output.ts # table/json/yaml/md/csv 格式化器 (table/json/yaml/md/csv formatters)
├── tests/
│ └── e2e/ # 每个站点的端到端测试 (E2E tests per site)
└── CLI-EXPLORER.md # 完整的 AI 智能体探索工作流 (Full AI agent exploration workflow)
📄 原始文档
完整文档(英文):
https://skills.sh/aradotso/trending-skills/opencli-web-automation
💡 提示:点击上方链接查看 skills.sh 原始英文文档,方便对照翻译。
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

评论(0)