Skip to content

ranmeizi/cdp-client-tool

Repository files navigation

CDP-CLIENT-TOOL

一个客户端程序,通过 Socket.IO 与 HTTP 接口与网关通信,用于控制浏览器、抓取数据等。适用于在安卓机 / Linux 上运行的数据抓取 Client。

English · README (English)

  • 包名cdp-client-tool
  • 入口ClientEVENTS、类型 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 连接网关

设计

  1. 客户端状态:提供获取客户端状态的能力(如是否存在某脚本文件)。
  2. 下发 / 执行脚本:可下发脚本字符串执行,或将脚本放在客户端 local_scripts 后通过事件执行。脚本在 Node 中以 CommonJS 形式运行,可使用 require() 引用其他 CJS 模块。
  3. 控制:通过 Socket.IO 连接网关,提供统一的控制事件协议。
  4. 浏览器控制:使用 puppeteer-core 通过 CDP 控制浏览器,封装常用流程。

环境搭建

通用

  1. 安装 Git、Node.js
  2. 安装 Chrome 浏览器

Windows / macOS

  1. 使用 --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"
  2. 启动项目并连接网关(可先启动 example 网关,再启动 client)。

Android

需在安卓上安装可运行 Node 的 Linux 环境(如 Termux / AidLux)。

  1. 安装 android-tools
  2. 开启 USB 调试,数据线连接后执行:adb tcpip 5555
  3. 连接手机:adb connect 192.168.1.100:5555
  4. 转发 Chrome 调试端口:adb forward tcp:9222 localabstract:chrome_devtools_remote
  5. 启动项目连接网关

手机重启后需重新执行 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').excuteFnctxbrowsergreetingparams(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。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors