npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cdp-client-tool

v2.1.4

Published

一个客户端程序,设计了一套socket.io与http接口的通信协议,可以用于控制浏览器,抓取数据等

Readme

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。