- 移除extension模块,将功能迁移至node-agent - 修复类型导出问题,使用export type明确类型导出 - 统一数据库连接方式,从直接导入改为使用config/database - 更新文档中的项目结构描述 - 添加多个服务的实用方法,如getForecast、getBalances等 - 修复类型错误和TS1205警告 - 优化RedisService调用方式 - 添加新的实体类型定义 - 更新审计日志格式,统一字段命名
7.4 KiB
7.4 KiB
Node Agent 设计文档
定位: Win Node Agent - 无 API 平台执行代理
更新日期: 2026-03-20
最高优先级参考: Business_ClosedLoops.md
1. 概述
1.1 背景
Extension (浏览器插件) 方案存在以下局限性:
- Manifest V3 权限限制
- 反检测能力不足
- 无法多实例并发
- 任务调度不可靠
Node Agent 基于 Playwright 构建,提供更强大的自动化能力。
1.2 核心能力
| 能力 | 说明 |
|---|---|
| 无 API 平台采集 | TikTok Shop, Temu, 1688 等 |
| 自动化操作 | 刊登、订单处理、广告投放 |
| 反检测 | 指纹隔离、代理 IP、浏览器上下文隔离 |
| 多实例并发 | 支持多店铺同时运行 |
2. 技术栈
| 层级 | 技术 | 版本 | 用途 |
|---|---|---|---|
| Runtime | Node.js | 18+ | 运行环境 |
| Automation | Playwright | 1.58+ | 浏览器自动化 |
| Language | TypeScript | 5.x | 开发语言 |
| Communication | Axios | - | HTTP 通信 |
3. 架构设计
3.1 系统架构
┌─────────────────────────────────────────────────────────────┐
│ Crawlful Hub │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Server │ │ Hub │ │ Dashboard │ │
│ │ (业务逻辑) │◄───►│ (任务调度) │◄───►│ (控制台) │ │
│ └──────────────┘ └──────┬───────┘ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Node Agent │ │
│ │ (Playwright) │ │
│ └────────┬─────────┘ │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Browser #1 │ │ Browser #2 │ │ Browser #N │ │
│ │ (店铺A) │ │ (店铺B) │ │ (店铺N) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
3.2 核心类设计
export class NodeAgent {
private hubUrl: string;
private nodeId: string;
private heartbeatInterval: number = 30000;
private pollInterval: number = 10000;
async start(): Promise<void>;
async register(): Promise<void>;
async heartbeat(): Promise<void>;
async pollTasks(): Promise<void>;
async executeTask(task: NodeTask): Promise<void>;
async reportReceipt(receipt: any): Promise<void>;
}
3.3 任务类型
export enum TaskType {
COLLECT_PRODUCT = 'COLLECT_PRODUCT',
COLLECT_ORDER = 'COLLECT_ORDER',
PUBLISH_PRODUCT = 'PUBLISH_PRODUCT',
PROCESS_ORDER = 'PROCESS_ORDER',
SYNC_INVENTORY = 'SYNC_INVENTORY',
MANAGE_AD = 'MANAGE_AD',
}
4. 核心功能
4.1 节点注册
private async register() {
await axios.post(`${this.hubUrl}/api/v1/nodes/register`, {
nodeId: this.nodeId,
version: '1.0.0',
os: os.type(),
hostname: os.hostname(),
shops: []
});
}
4.2 任务轮询
private async pollTasks() {
const response = await axios.get(
`${this.hubUrl}/api/v1/nodes/pull-task?nodeId=${this.nodeId}`
);
if (response.data?.task) {
await this.executeTask(response.data.task);
}
}
4.3 任务执行
private async executeTask(task: NodeTask) {
try {
const browser = await chromium.launch({
headless: false,
proxy: { server: task.proxyUrl }
});
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 }
});
const page = await context.newPage();
// 执行具体任务...
await browser.close();
await this.reportReceipt({
taskId: task.id,
traceId: task.traceId,
status: 'success',
resultData: {}
});
} catch (err) {
await this.reportReceipt({
taskId: task.id,
traceId: task.traceId,
status: 'failed',
errorMessage: err.message
});
}
}
5. 店铺隔离策略
5.1 一店一上下文
interface ShopContext {
shopId: string;
profileDir: string;
proxy: ProxyConfig;
fingerprintPolicy: FingerprintConfig;
}
5.2 同店任务串行
class TaskQueue {
private queues: Map<string, TaskQueue> = new Map();
async addTask(shopId: string, task: Task) {
if (!this.queues.has(shopId)) {
this.queues.set(shopId, new TaskQueue());
}
await this.queues.get(shopId).add(task);
}
}
6. 反检测策略
| 策略 | 说明 |
|---|---|
| 指纹隔离 | 每个店铺独立浏览器指纹 |
| 代理 IP | 每个店铺独立代理 |
| 行为模拟 | 随机延迟、鼠标轨迹 |
| User-Agent | 随机 UA 轮换 |
7. 目录结构
node-agent/
├── src/
│ ├── main.ts # 入口
│ ├── index.ts # NodeAgent 类
│ ├── tasks/ # 任务处理器
│ │ ├── collectProduct.ts
│ │ ├── publishProduct.ts
│ │ └── processOrder.ts
│ ├── platforms/ # 平台适配器
│ │ ├── tiktok.ts
│ │ ├── temu.ts
│ │ └── ali1688.ts
│ └── utils/ # 工具函数
│ ├── logger.ts
│ └── fingerprint.ts
├── package.json
└── tsconfig.json
8. 配置
interface AgentConfig {
hubUrl: string;
nodeId: string;
heartbeatInterval: number;
pollInterval: number;
maxConcurrentBrowsers: number;
proxyPool: ProxyConfig[];
}
9. 相关文档
本文档基于业务闭环设计,最后更新: 2026-03-20