cdp-client-tool
v2.1.4
Published
一个客户端程序,设计了一套socket.io与http接口的通信协议,可以用于控制浏览器,抓取数据等
Maintainers
Readme
CDP-CLIENT-TOOL
一个客户端程序,通过 Socket.IO 与 HTTP 接口与网关通信,用于控制浏览器、抓取数据等。适用于在安卓机 / Linux 上运行的数据抓取 Client。
English · README (English)
- 包名:
cdp-client-tool - 入口:
Client、EVENTS、类型ClientOptions/GatewayConfig/excuteFn
快速开始
# 安装依赖并构建
pnpm install
pnpm run build作为客户端连接网关:
import { Client } from "cdp-client-tool";
const client = new Client({
deviceName: "my-device", // 网关侧展示的设备名
gateways: [
{ name: "local", uri: "http://localhost:3000" },
],
});启动示例网关 + 资源浏览器:
pnpm run start:express # 启动 Express 网关
# 浏览器打开 http://localhost:3000/browser
pnpm run start:client # 启动示例 Client 连接网关设计
- 客户端状态:提供获取客户端状态的能力(如是否存在某脚本文件)。
- 下发 / 执行脚本:可下发脚本字符串执行,或将脚本放在客户端
local_scripts后通过事件执行。脚本在 Node 中以 CommonJS 形式运行,可使用require()引用其他 CJS 模块。 - 控制:通过 Socket.IO 连接网关,提供统一的控制事件协议。
- 浏览器控制:使用 puppeteer-core 通过 CDP 控制浏览器,封装常用流程。
环境搭建
通用
- 安装 Git、Node.js
- 安装 Chrome 浏览器
Windows / macOS
- 使用
--remote-debugging-port=9222启动 Chrome。
macOS 示例:open -n -a "Google Chrome" --args \ --remote-debugging-port=9222 \ --user-data-dir="/Users/xxx/Library/Application Support/Google/Chrome/Profile 1" - 启动项目并连接网关(可先启动 example 网关,再启动 client)。
Android
需在安卓上安装可运行 Node 的 Linux 环境(如 Termux / AidLux)。
- 安装 android-tools
- 开启 USB 调试,数据线连接后执行:
adb tcpip 5555 - 连接手机:
adb connect 192.168.1.100:5555 - 转发 Chrome 调试端口:
adb forward tcp:9222 localabstract:chrome_devtools_remote - 启动项目连接网关
手机重启后需重新执行 adb 连接与端口转发。
网关与 Socket 协议
默认通过 Socket.IO 连接网关;如需其他传输可在 onInit 中自行实现,建议仍使用 Socket.IO 以复用现有事件协议。
消息类型
type SendMessageType<T = any> = { payload: T }
type ReturnMessageType<T = any> = { code: string; payload: T }客户端预设事件(网关 → 设备)
文件系统
| 事件 | 说明 | payload |
|------|------|--------|
| set_file | 保存文件到 local_scripts 目录 | { filename, content } |
| read_dir | 读取目录,返回 { name, type: 'file' \| 'dir' }[] | { path },如 "local_scripts" |
| read_file | 读取文件内容(仅允许 local_scripts、screenshots) | { path } |
| rm | 删除文件(仅允许上述两目录) | { path } |
| is_file_exist | 检测文件是否存在 | { path } |
脚本执行
| 事件 | 说明 | payload |
|------|------|--------|
| exec_local_script | 执行 local_scripts 下脚本,CJS 运行可 require(),走脚本队列 | { filename, params? },如 { filename: "task1.cjs", params: { share_code: "hk-00700" } } |
| exec_remote_script | 执行下发的脚本字符串(类 CJS 环境,可 require),走脚本队列 | { raw: Buffer, params? } |
| script_queue | 查询当前设备脚本队列快照(网关轮询或按需拉取) | {},回调返回 { running, pending, capacity } |
| interrupt_script | 中断脚本:排队中则移除,运行中则 terminate Worker,队列会自动执行下一任务 | { jobId },回调返回 { ok: boolean, reason?: string } |
| undo_script | 撤销脚本:与 interrupt_script 同逻辑,用于排队任务撤销 | { jobId },回调返回 { ok: boolean, reason?: string } |
脚本执行采用队列(默认容量 10):请求会立即返回 executing / queued / overflow,实际在队列中顺序执行。脚本入口:module.exports = async function capture(ctx) { ... },类型为 import('cdp-client-tool').excuteFn,ctx 含 browser、greeting、params(server 下发的可选参数)。资源浏览器中,鼠标悬停任务可查看 params。可通过 interrupt_script / undo_script 中断运行中或撤销排队中的任务。下发脚本时返回执行 id,网关可据此下发取消任务。
客户端上报事件(设备 → 网关)
| 事件 | 说明 | payload |
|------|------|--------|
| report_result | 脚本执行过程中的结果上报事件,由客户端主动推送给网关,用于异步接收任务结果 | { jobId, result } |
report_result 适用于“下发任务先返回 queued/executing,最终结果异步回传”的场景。推荐网关侧按 jobId 建立等待中的 Action(Promise)并在收到上报后 resolve/reject。
脚本侧上报示例(worker 内)
const { sleep, reportResult } = require("cdp-client-tool");
async function main() {
await sleep(1000);
reportResult({ stage: "half" }); // 可选:过程上报
await sleep(1000);
reportResult({ ok: true, data: { price: 123.45 } }); // 最终上报
}
main().catch((e) => reportResult({ ok: false, error: e?.message || String(e) }));示例:exec_local_script
// 网关或调用方发送,可带 params 传递参数给脚本
socket.emit('exec_local_script', {
payload: {
filename: 'task1.cjs',
params: { share_code: 'hk-00700' }
}
}, (result) => console.log(result));示例:set_file
socket.emit('set_file', {
payload: {
filename: 'script.js',
content: `
async function capture(ctx) { return ctx.greeting; }
module.exports = capture;
`
}
}, (res) => console.log(res));其余事件可自定义扩展。
架构说明(网关 + 资源浏览器)
HTTP (页面 + 接口)
┌─────────────── Browser ───────────────┐
│ 资源浏览器 UI:设备列表、脚本队列(运行中│
│ + 已运行时间、排队)、local_scripts / │
│ screenshots 目录树、预览/下载、删除 │
└─────────────────┬─────────────────────┘
▼
┌────────────── Express 网关 ────────────┐
│ HTTP API:设备列表、目录、读/删文件 │
│ Socket.IO:多设备连接,HTTP 转事件 │
└─────────────────┬─────────────────────┘
│ Socket.IO
┌─────────────┼─────────────┐
▼ ▼ ▼
Device A Device B Device C
local_scripts local_scripts local_scripts
screenshots screenshots screenshots- 多台设备(运行本库的 Client)通过 Socket.IO 连接同一网关,连接时上报
deviceName,网关以此区分设备。 - 前端通过 HTTP 访问「设备 → 目录 → 文件」的虚拟结构,网关将请求转为对对应设备的
read_dir/read_file/rm等事件。 - 网关定时向各设备拉取
script_queue并缓存;前端定时请求 GET/api/devices获取设备列表及每设备的脚本队列状态,资源浏览器页展示「运行中脚本 + 已运行时间」与排队列表。
HTTP 接口规范(资源浏览器)
Base 示例:http://localhost:3000。路径统一为虚拟路径:/{device_name}/local_scripts/... 或 /{device_name}/screenshots/...。
错误体:{ "code": "400" | "404" | "500", "message": "string" }
| 接口 | Method | Path | 说明 |
|------|--------|------|------|
| 设备列表 | GET | /api/devices | { devices: [{ name, connectedAt?, scriptQueue?, queueUpdatedAt?, queueError? }] },网关定时拉取各设备 script_queue 并缓存,供前端轮询 |
| 脚本队列 | GET | /api/scripts/queue?device= | { running, pending, capacity },单设备队列快照(可走缓存) |
| 中断脚本 | POST | /api/scripts/interrupt | Body: { device, jobId },转设备 interrupt_script,返回 { ok: boolean } |
| 撤销脚本 | POST | /api/scripts/undo | Body: { device, jobId },转设备 undo_script,返回 { ok: boolean } |
| 读目录 | GET | /api/fs/dir?device=&path= | { entries: [{ name, type }] },type 为 file 或 dir |
| 读文件 | GET | /api/fs/file?device=&path= | 文件流,带 Content-Type / Content-Disposition |
| 删文件 | DELETE | /api/fs/file?device=&path= | { ok: true, message: "deleted" } |
| 写文件(可选) | POST | /api/fs/file | Body: { device, path, content },转设备 set_file |
虚拟结构:/{device_name}/local_scripts/...、/{device_name}/screenshots/...,path 须落在此两棵树下,否则 400。
