7.0 KiB
7.0 KiB
分布式浏览器控制后台
通过 中央服务器 + Worker 代理 架构,远程控制多台电脑上的比特浏览器,并使用 DrissionPage 执行自动化任务。
架构概览
前端 / Postman 中央服务器(第三台机器) 电脑 A / B
─────────────── ───────────────────── ──────────
REST API ──── HTTP ────→ FastAPI Server Worker Agent
├── Worker Manager ←── WebSocket ──┤
└── Task Dispatcher ──── WebSocket ──→ 比特浏览器
+ DrissionPage
- 中央服务器:接收前端 API 请求,管理 Worker 状态,路由并派发任务
- Worker 代理:运行在每台电脑上,通过 WebSocket 连接服务器,接收任务后本地控制比特浏览器 + DrissionPage
快速开始
1. 安装依赖
pip install -r requirements.txt
2. 启动中央服务器
在第三台机器(或任一台能被其他机器访问的机器)上运行:
python -m server.main
默认监听 0.0.0.0:8000。可通过环境变量修改:
set SERVER_HOST=0.0.0.0
set SERVER_PORT=8000
python -m server.main
3. 启动 Worker(每台电脑上各运行一个)
电脑 A:
python -m worker.main --server ws://服务器IP:8000/ws --worker-id pc-a --worker-name "电脑A"
电脑 B:
python -m worker.main --server ws://服务器IP:8000/ws --worker-id pc-b --worker-name "电脑B"
Worker 启动后会自动:
- 连接中央服务器
- 上报本机比特浏览器窗口列表
- 等待接收任务
注意:每台电脑需先启动比特浏览器客户端(默认 API 端口 54345)。
内网穿透(隧道)
项目内置 独立 Python 隧道,与 Worker 集成。线下电脑无需单独安装 frp 等工具,启动 Worker 时会同时建立隧道,将本机端口(如比特浏览器 API 54345)暴露到云服务器,便于从公网访问该机器上的服务。
- 云服务器:随
python -m server.main自动启动隧道服务端(控制端口 8001、流端口 8003、代理端口从 8010 起按 Worker 分配)。 - 线下电脑:Worker 启动时默认开启隧道客户端,连接云服务器并注册
worker_id,云上会为该 Worker 分配一个代理端口(如 8010、8011…)。访问云服务器IP:8010即等价于访问该 Worker 本机的127.0.0.1:54345。
环境变量(可选)
| 位置 | 变量 | 默认值 | 说明 |
|---|---|---|---|
| 服务器 | TUNNEL_CONTROL_PORT |
8001 | 隧道控制端口 |
| 服务器 | TUNNEL_STREAM_PORT |
8003 | 隧道流端口 |
| 服务器 | TUNNEL_PROXY_BASE_PORT |
8010 | 代理端口起始 |
| Worker | TUNNEL_ENABLED |
1 | 是否启用隧道 |
| Worker | TUNNEL_SERVER |
(从 SERVER_WS_URL 解析) | 隧道服务端地址 |
| Worker | TUNNEL_LOCAL_PORT |
54345 | 暴露的本地端口 |
禁用隧道:python -m worker.main --no-tunnel ...
API 接口
查看在线 Worker
GET /api/workers
响应示例:
[
{
"worker_id": "pc-a",
"worker_name": "电脑A",
"browsers": [
{"id": "abc123", "name": "BOSS主号", "remark": "张三"}
],
"online": true,
"current_task_id": null
}
]
提交任务
POST /api/tasks
Content-Type: application/json
{
"task_type": "boss_recruit",
"account_name": "BOSS主号",
"params": {
"job_title": "前端工程师",
"max_greet": 5
}
}
路由规则:
- 指定
worker_id→ 直接发到该 Worker - 指定
account_name→ 自动找到拥有该浏览器的 Worker - 两者都传 →
worker_id优先
查询任务状态
GET /api/tasks/{task_id}
查询任务列表
GET /api/tasks?worker_id=pc-a&status=success&limit=20
健康检查
GET /health
项目结构
boss_dp/
├── server/ # 中央服务器
│ ├── main.py # FastAPI 入口(含 WebSocket 端点)
│ ├── config.py # 服务器配置
│ ├── models.py # Pydantic 数据模型
│ ├── api/
│ │ ├── workers.py # Worker 查询 API
│ │ └── tasks.py # 任务提交与查询 API
│ └── core/
│ ├── worker_manager.py # Worker 注册、状态管理、账号映射
│ └── task_dispatcher.py # 任务路由与派发
├── worker/ # Worker 代理(每台电脑部署)
│ ├── main.py # 启动入口
│ ├── config.py # Worker 配置
│ ├── ws_client.py # WebSocket 客户端(心跳、重连)
│ ├── bit_browser.py # 比特浏览器 API 封装
│ ├── browser_control.py # DrissionPage 通用控制封装
│ └── tasks/
│ ├── base.py # 任务处理器基类
│ ├── registry.py # 处理器注册表
│ └── boss_recruit.py # BOSS 直聘招聘任务
├── common/
│ └── protocol.py # 共享消息协议
├── tunnel/ # 内网穿透(独立隧道,与 Worker 集成)
│ ├── __init__.py
│ ├── protocol.py # 隧道控制协议
│ ├── server.py # 隧道服务端(云上)
│ └── client.py # 隧道客户端(线下,随 Worker 启动)
├── requirements.txt
└── README.md
扩展新任务
- 在
worker/tasks/下新建文件,继承BaseTaskHandler - 实现
execute方法 - 在
common/protocol.py的TaskType中添加新类型 - 在
worker/tasks/registry.py的register_all_handlers()中注册
# worker/tasks/my_task.py
from worker.tasks.base import BaseTaskHandler
class MyTaskHandler(BaseTaskHandler):
task_type = "my_task"
async def execute(self, task_id, params, progress_cb):
await progress_cb(task_id, "开始执行...")
# ... 你的自动化逻辑 ...
return {"status": "done"}
配置项
服务器 (server/config.py)
| 环境变量 | 默认值 | 说明 |
|---|---|---|
SERVER_HOST |
0.0.0.0 |
监听地址 |
SERVER_PORT |
8000 |
监听端口 |
API_TOKEN |
(空) | 非空时校验 Authorization Header |
Worker (worker/config.py)
| 环境变量 | 默认值 | 说明 |
|---|---|---|
SERVER_WS_URL |
ws://127.0.0.1:8000/ws |
服务器 WebSocket 地址 |
WORKER_ID |
worker-1 |
Worker 唯一标识 |
WORKER_NAME |
本机 |
Worker 显示名称 |
BIT_API_BASE |
http://127.0.0.1:54345 |
比特浏览器本地 API |