feat(monitor): 抖音 Web 接口客户端 —— 绕开爬虫子进程,直接发 HTTP
移植自 mac-agent-os 的 mediacrawler_adapter:不起子进程、不开页面,用浏览器里那份
登录态直接调抖音 Web 接口。产物键名照抄 store/douyin,所以 ingest 那条链路一个字不用改。
**目前能用的(真环境实测,非推断)**:
profile/other : 200, 7075 字节 —— 博主主页指标(粉丝/获赞/作品数/昵称)
aweme/detail : 200, 45425 字节 —— 单条作品详情(含点赞/评论/收藏/分享)
**目前不能用的:作品列表 `aweme/post`。** 两个互相独立的原因:
1. 这个接口被抖音单独升级成了真校验:不带 x-tt-argus 回 403「Uifid Not Found」,
带上 dummy 值回 200 + **空 body**。也就是说「头在不在」骗得过,「真校验」过不了。
同一套头打 profile/other 和 aweme/detail 都是通的 —— 抖音是挑着接口加保护的,
挑中的恰好是「批量拉作品列表」这个最敏感的动作。
2. 改走页面截获也不行:CDP 浏览器打开博主主页会落到「验证码中间页」(当天大量探测的
代价,过几小时要重测)。
所以现在的边界是:**已知作品的指标刷新能做,自动发现新作品做不了**。
**排查中控住变量后得到的两条事实**(都写进注释了):
· `Accept` / `Accept-Language` / `Referer` 才是主页接口能返回真数据的原因 —— 只有
UA+client hints+Cookie 时是 200 但仅 121 字节的空壳,补上这三个头变 7074 字节。
(我先前猜的 sec-ch-ua 不是关键。)
· 因此 UA 与 client hints 必须**成套地取自同一个浏览器**,所以 BrowserIdentity 一次
从 CDP 取齐 cookie + UA + hints,而不是各自写死。
「200 + 空 body 必须当场报错」也是刻意写死的:放过去它会在下游变成「这个博主没作品」,
把一次失败伪装成一条正常结果 —— 爬虫那条路正是这么栽的,还被翻译成「账号被封」。
测试 +11:cookie 解析、请求头成套性(含 uifid 缺失/回退)、产物键名与 store 对齐、
以及 _get 的三条失败路径(空 body / 403 带网关原话 / 正常返回)。
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
# 系统监控面板 (10_dashboard) 架构设计
|
||||
|
||||
> 版本: 1.0.0 | 更新: 2026-05-16
|
||||
> 定位: 系统级监控层, 联邦架构可视化面板
|
||||
|
||||
---
|
||||
|
||||
## 一、架构总览
|
||||
|
||||
```
|
||||
10_dashboard/ ← 系统级监控面板
|
||||
├── app.py FastAPI 后端 (插件注册 + API 路由)
|
||||
├── run.py 独立启动入口
|
||||
├── config.yaml (预留) 数据源配置
|
||||
├── static/index.html 前端 SPA
|
||||
├── plugins/
|
||||
│ ├── __init__.py 插件管理器
|
||||
│ ├── base.py DashboardPlugin 基类
|
||||
│ └── ave.py AVE 视频工厂数据源插件
|
||||
└── PLANS/ARCHITECTURE.md 本文件
|
||||
```
|
||||
|
||||
## 二、数据流
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ 用户浏览器 (SPA) │
|
||||
└─────────────────┬──────────────┬────────────────┘
|
||||
│ GET /api/* │
|
||||
▼ ▼
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ 10_dashboard/app.py (FastAPI) │
|
||||
│ │
|
||||
│ /api/plugins → 插件列表 │
|
||||
│ /api/summary → 所有插件聚合总览 │
|
||||
│ /api/productions → AVE 插件 │
|
||||
│ /api/assets/* → AVE asset_manager │
|
||||
│ /api/costs/* → AVE 插件 │
|
||||
└─────────┬──────────────────────┬──────────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌──────────────┐ ┌──────────────────┐
|
||||
│ AVE 插件 │ │ (未来) Matrix │
|
||||
│ plugins/ave.py│ │ guardd / 其他 │
|
||||
│ → AVE DB │ │ → 各自 DB/API │
|
||||
└──────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
**核心原则**:
|
||||
- 数据不搬家: Dashboard 只读, 不复制数据
|
||||
- 插件隔离: 每个模块的数据源在自己的 plugin 中处理
|
||||
- 增量接入: 新模块只需实现 DashboardPlugin 基类
|
||||
|
||||
## 三、插件协议
|
||||
|
||||
```python
|
||||
class DashboardPlugin:
|
||||
name: str # "ave", "matrix", "guardd"
|
||||
label: str # "视频工厂", "矩阵养号", "系统状态"
|
||||
order: int # 展示排序
|
||||
|
||||
def get_summary(self) -> dict
|
||||
def get_productions(self, limit, offset, strategy, status) -> list
|
||||
def get_production_detail(self, id) -> dict|None
|
||||
def get_cost_breakdown(self) -> list
|
||||
def get_sidebar_links(self) -> list[dict]
|
||||
def is_available(self) -> bool
|
||||
```
|
||||
|
||||
## 四、与 AVE 的边界
|
||||
|
||||
| 组件 | 归属 | 说明 |
|
||||
|:-----|:----:|:-----|
|
||||
| `lib/dashboard.py` | **09_ave** | AVE 数据写入层 (production/step/asset/cost 埋点) |
|
||||
| `asset_manager/` | **09_ave** | AVE 素材索引 (AssetIndex/CacheManager/AssetSearch) |
|
||||
| `cost_tracker.py` | **09_ave** | AVE 费用追踪 |
|
||||
| `plugins/ave.py` | **10_dashboard** | AVE 数据读取适配器 |
|
||||
| `app.py` | **10_dashboard** | 系统级后端, 加载所有插件 |
|
||||
| `static/index.html` | **10_dashboard** | 前端 SPA, 模块化展示 |
|
||||
|
||||
## 五、接入新模块 (示例: Matrix)
|
||||
|
||||
```python
|
||||
# 10_dashboard/plugins/matrix.py
|
||||
from plugins.base import DashboardPlugin
|
||||
|
||||
class MatrixDashboardPlugin(DashboardPlugin):
|
||||
name = "matrix"
|
||||
label = "矩阵养号"
|
||||
order = 2
|
||||
|
||||
def get_summary(self) -> dict:
|
||||
# 读取 matrix.db 返回统计数据
|
||||
...
|
||||
|
||||
def is_available(self) -> bool:
|
||||
return Path("~/matrix/data/matrix.db").exists()
|
||||
```
|
||||
|
||||
然后在 `app.py` 的 `_register_plugins()` 中添加 `MatrixDashboardPlugin` 即可。
|
||||
|
||||
## 六、启动方式
|
||||
|
||||
```bash
|
||||
# 方式 1: 通过 AVE 入口 (推荐)
|
||||
cd 09_ave/scripts && python main.py dashboard
|
||||
|
||||
# 方式 2: 独立启动
|
||||
cd 10_dashboard && python run.py
|
||||
|
||||
# 方式 3: uvicorn (开发模式)
|
||||
cd 10_dashboard && uvicorn app:app --reload --port 9988
|
||||
```
|
||||
|
||||
## 七、迁移要点 (Phase 1)
|
||||
|
||||
1. ✅ 目录搬移: `dashboard/` → `10_dashboard/`
|
||||
2. ✅ Import 路径: app.py 通过 `../09_ave/scripts/` 引用 AVE 模块
|
||||
3. ✅ 插件框架: base.py + ave.py 实现
|
||||
4. ✅ main.py 入口: dashboard 命令指向新路径
|
||||
5. ✅ 前端兼容: 旧 API 路径保持不变
|
||||
6. ⬜ 多机同步: 通过坚果云 / Gitee 同步 10_dashboard/
|
||||
@@ -0,0 +1,179 @@
|
||||
# AgentOS 联邦架构 v3.0 — 完整蓝图
|
||||
|
||||
> **版本**: 3.0.0 | **更新**: 2026-06-17
|
||||
> **目标**: 统一三机联邦,每机智能体可独立运作,Dashboard 可统一指挥
|
||||
|
||||
---
|
||||
|
||||
## 一、系统架构总览
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ 用户入口层 │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
|
||||
│ │ Web看板 │ │ 智能体 │ │ CLI终端 │ │ 定时任务 │ │
|
||||
│ │ (SPA) │ │ (AI) │ │ (SSH) │ │ (cron/task) │ │
|
||||
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬───────┘ │
|
||||
└───────┼──────────────┼──────────────┼───────────────┼─────────┘
|
||||
│ │ │ │
|
||||
┌───────▼──────────────▼──────────────▼───────────────▼─────────┐
|
||||
│ API 网关层 (FastAPI :9988) │
|
||||
│ │
|
||||
│ /api/plugins/* — 插件元信息 │
|
||||
│ /api/identity — 本机身份 │
|
||||
│ /api/machines — 联邦机器状态 │
|
||||
│ /api/health — 健康检查 │
|
||||
│ /api/matrix/* — 矩阵养号全套 (accounts/nurture/blueprint) │
|
||||
│ /api/federation/* — 联邦远程操作 (nurture/exec/collect/login) │
|
||||
│ /api/machine/* — 远程命令执行 │
|
||||
│ /api/push/* — 心跳推送 │
|
||||
└───────┬──────────────────────┬──────────────────┬──────────────┘
|
||||
│ │ │
|
||||
┌───────▼────────┐ ┌─────────▼────────┐ ┌────▼──────────┐
|
||||
│ 本机执行 │ │ 远程 SSH 执行 │ │ 跨机数据聚合 │
|
||||
│ subprocess │ │ remote_exec.py │ │ data_aggregtor│
|
||||
│ mc run / mc ✅│ │ SSH → 远程 mc │ │ HTTP拉取 │
|
||||
└────────────────┘ └──────────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、API 分层
|
||||
|
||||
### 2.1 插件层 (plugins/)
|
||||
|
||||
| 插件 | 职责 | API |
|
||||
|:-----|:-----|:----|
|
||||
| `guardd` | 联邦心跳/机器状态 | `/api/machines`, `/api/push/*` |
|
||||
| `matrix` | 矩阵养号 | `/api/plugins/matrix/*` |
|
||||
| `federation` | 联邦操作 | `/api/federation/*` |
|
||||
| `scheduler` | 定时调度 | `/api/plugins/scheduler/*` |
|
||||
| `sms_proxy_api` | 短信服务 | `/api/sms/*` |
|
||||
|
||||
### 2.2 路由层 (routes/)
|
||||
|
||||
| 路由 | 职责 | 端点 |
|
||||
|:-----|:-----|:-----|
|
||||
| `routes/matrix.py` | 账号管理+养号+蓝图+原子操作 | `/api/matrix/*` |
|
||||
|
||||
### 2.3 服务层 (services/)
|
||||
|
||||
| 服务 | 职责 |
|
||||
|:-----|:-----|
|
||||
| `remote_exec.py` | SSH远程执行引擎 |
|
||||
| `data_aggregator.py` | 联邦数据聚合 |
|
||||
| `operation_queue.py` | 操作队列 |
|
||||
| `resource_lock.py` | 资源锁 |
|
||||
| `preflight.py` | 前置检查 |
|
||||
| `log_aggregator.py` | 日志聚合 |
|
||||
|
||||
---
|
||||
|
||||
## 三、视图完整清单 (25个)
|
||||
|
||||
| 导航组 | 视图 | 实现状态 | API 依赖 |
|
||||
|:-------|:-----|:---------|:---------|
|
||||
| **矩阵** | 账号管理 (`matrix-sms-proxy`) | ✅ 功能完整 | `/api/matrix/accounts` |
|
||||
| | 养号执行 (`matrix-nurture`) | 🔧 近期修复 | `/api/matrix/nurture/start` |
|
||||
| | 信息采集 (`matrix-collect`) | 🟡 待验证 | `/api/matrix/collect/*` |
|
||||
| | 内容发布 (`matrix-publish`) | 🟡 待验证 | `/api/matrix/publish/*` |
|
||||
| | 蓝图管理 (`matrix-blueprints`) | ✅ 功能完整 | `/api/matrix/blueprints` |
|
||||
| | 定向评论 (`matrix-comment`) | 🟡 待验证 | `/api/matrix/comment/*` |
|
||||
| | 定时任务 (`matrix-schedule`) | 🟡 待验证 | `/api/matrix/schedule/*` |
|
||||
| | 语料库 (`matrix-corpus`) | 🟡 待验证 | `/api/matrix/corpus/*` |
|
||||
| **视频工厂** | 渲染任务 (`ave-render`) | 🟡 待验证 | `/api/productions` |
|
||||
| | 脚本生成 (`ave-script`) | 🟡 待验证 | `/api/characters` |
|
||||
| | 素材库 (`ave-materials`) | 🟡 待验证 | `/api/assets/*` |
|
||||
| | 模板 (`ave-templates`) | 🟡 待验证 | `/api/capabilities` |
|
||||
| **内容采集** | 采集任务 (`crawl-tasks`) | 🟡 待验证 | `/api/crawl/*` |
|
||||
| | 源管理 (`crawl-sources`) | 🟡 待验证 | `/api/crawl/*` |
|
||||
| | 采集历史 (`crawl-history`) | 🟡 待验证 | `/api/crawl/*` |
|
||||
| **联邦** | 机器状态 (`machines`) | ✅ 功能完整 | `/api/machines` |
|
||||
| | 一键同步 (`fleet-sync`) | ✅ 功能完整 | `/api/git-sync` |
|
||||
| | 对账检查 (`fleet-reconcile`) | 🟡 待验证 | `/api/fleet/reconcile` |
|
||||
| | 远程Shell (`fleet-exec`) | 🟡 待验证 | `/api/machine/exec` |
|
||||
| **服务** | MCP状态 (`serve-mcp`) | 🔴 未实现 | N/A |
|
||||
| | Dashboard日志 (`serve-dashboard`) | 🟡 待验证 | N/A |
|
||||
| | 全局定时任务 (`serve-schedule`) | 🔴 未实现 | N/A |
|
||||
|
||||
---
|
||||
|
||||
## 四、执行链路 (关键路径)
|
||||
|
||||
### 4.1 养号执行链路(已修复 ✅)
|
||||
|
||||
```
|
||||
用户点击「执行选中」
|
||||
→ nurtureExecSelected() ← index.html JS
|
||||
→ POST /api/matrix/nurture/start ← routes/matrix.py
|
||||
→ 自动选蓝图 + 路由到机器
|
||||
→ 本机: subprocess mc run ← local path
|
||||
→ 远程: remote_exec exec_nurture ← SSH path
|
||||
→ SSH → mc run ← remote path
|
||||
→ mc/engine.py ← 身份分组+浏览器
|
||||
→ cdp_connector.py ← Camoufox
|
||||
```
|
||||
|
||||
### 4.2 智能登录链路(待验证 ⚠️)
|
||||
|
||||
```
|
||||
用户点击「登录」
|
||||
→ POST /api/federation/login
|
||||
→ remote_exec exec_login
|
||||
→ SSH → mc smart-login {account_id}
|
||||
→ douyin_login.py / xiaohongshu_login.py
|
||||
```
|
||||
|
||||
### 4.3 信息采集链路(待验证 ⚠️)
|
||||
|
||||
```
|
||||
用户点击「采集」
|
||||
→ POST /api/federation/collect
|
||||
→ remote_exec exec_collect
|
||||
→ SSH → mc collect
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、三机统一环境
|
||||
|
||||
| 项目 | chengzigedeAir | 5kechengdeAir | 7kecheng |
|
||||
|:-----|:--------------|:-------------|:---------|
|
||||
| Python venv | agent-os ✅ | agent-os ✅ | agent-os ✅ |
|
||||
| camoufox | 0.4.11 ✅ | 0.4.11 ✅ | 0.4.11 ✅ |
|
||||
| playwright | 1.58.0 ✅ | 1.58.0 ✅ | 1.58.0 ✅ |
|
||||
| Git版本 | cc04e9d93a | cc04e9d93a | cc04e9d93a |
|
||||
| Dashboard | launchd ✅ | launchd ✅ | launchd ✅ |
|
||||
| 身份目录 | phone_*命名 ✅ | phone_*命名 ✅ | phone_*命名 ✅ |
|
||||
| 账号总数 | 30 (联邦聚合) | 30 (联邦聚合) | 30 (联邦聚合) |
|
||||
|
||||
---
|
||||
|
||||
## 六、任务优先级 (Phase 3 执行计划)
|
||||
|
||||
### P0 — 核心功能修复(本机优先)
|
||||
|
||||
| # | 任务 | 视图 | 预估 |
|
||||
|:-:|:-----|:-----|:----|
|
||||
| 1 | 养号执行端到端验证:API→mc run→浏览器→执行 | matrix-nurture | ✅ DONE |
|
||||
| 2 | 账号管理视图修复:编辑/删除/状态显示 | matrix-sms-proxy | 1h |
|
||||
| 3 | 蓝图管理视图修复:增删改+编排 | matrix-blueprints | 1h |
|
||||
| 4 | 信息采集端到端:触发→执行→结果回显 | matrix-collect | 2h |
|
||||
| 5 | 智能登录端到端:从看板触发远程登录 | federation | 2h |
|
||||
|
||||
### P1 — 联邦功能
|
||||
|
||||
| # | 任务 | 视图 | 预估 |
|
||||
|:-:|:-----|:-----|:----|
|
||||
| 6 | 远程执行路由:本机/远程账号智能分发 | 全部矩阵视图 | 2h |
|
||||
| 7 | 执行结果回显:进度条+日志流 | matrix-nurture | 2h |
|
||||
| 8 | 联邦定时任务:跨机定时执行 | serve-schedule | 3h |
|
||||
|
||||
### P2 — 完善
|
||||
|
||||
| # | 任务 | 视图 | 预估 |
|
||||
|:-:|:-----|:-----|:----|
|
||||
| 9 | 语料库管理 | matrix-corpus | 2h |
|
||||
| 10 | 定向评论 | matrix-comment | 2h |
|
||||
| 11 | 远程Shell | fleet-exec | 1h |
|
||||
| 12 | 对账检查可视化 | fleet-reconcile | 1h |
|
||||
@@ -0,0 +1,266 @@
|
||||
# AgentOS 联邦系统 — 状态机架构方案 v3.0
|
||||
|
||||
> 目标:让账号在指定动作中随意切换,不受意外打扰,遇到问题自动回到正轨
|
||||
> 基于现有 `CommandBus` / `ORACLE.yaml` / `guardd` 框架,不重复造轮子
|
||||
|
||||
---
|
||||
|
||||
## 一、现有系统总览(读代码后的正确理解)
|
||||
|
||||
### 1.1 三台机器的真实角色
|
||||
|
||||
```
|
||||
┌─ Dashboard Web 服务 ────────────────────┐
|
||||
│ chengzigedeAir (master) :9988 │ ← 唯一运行 Dashboard 的机器
|
||||
│ 5kechengdeAir (worker) ❌ 不跑 Web │
|
||||
│ 7kecheng (worker) ❌ 不跑 Web │
|
||||
└─────────────────────────────────────────┘
|
||||
|
||||
用户在任意电脑打开 http://100.111.43.6:9988 即可操作 Dashboard。
|
||||
不是"三台都打开本地看板"。
|
||||
```
|
||||
|
||||
**各机器的身份归属**(来自 ORACLE.yaml):
|
||||
|
||||
| 机器 | 身份 | 所属平台账号 |
|
||||
|:-----|:------|:-----------|
|
||||
| chengzigedeAir | phone_15370103682 | douyin_test + xhs_01 |
|
||||
| | douyin_133 / douyin_133_2 / douyin_134 | 各一个抖音 |
|
||||
| 5kechengdeAir | douyin_01_camo | douyin_01 + xhs_01 |
|
||||
| | douyin_02_camo | douyin_02 + xhs_02 |
|
||||
| | douyin_camo01 | douyin_camo01 + xhs_03 |
|
||||
| 7kecheng | 13个身份 | 各一个抖音 + 小红书 |
|
||||
|
||||
### 1.2 现有五层架构(不是新设计,是读出已有的)
|
||||
|
||||
```
|
||||
Layer 5: Dashboard UI (静态前端 SPA)
|
||||
→ 本地访问 localhost:9988 或远程访问 100.111.43.6:9988
|
||||
|
||||
Layer 4: FastAPI 后端路由
|
||||
→ app.py (plugins/ 插件管理, 数据聚合)
|
||||
→ routes/ops.py (POST /api/ops/run — 统一执行入口)
|
||||
→ routes/... (各功能路由)
|
||||
|
||||
Layer 3: 命令分发总线 — CommandBus
|
||||
→ services/command_bus.py
|
||||
→ CommandBus.dispatch(type, accounts, params)
|
||||
→ 按 machine 分组 → MachineSession
|
||||
→ 本机: subprocess.Popen (mc run / mc collect / ...)
|
||||
→ 远程: SSH → remote_exec → 结果回传
|
||||
|
||||
Layer 2: 执行引擎 — mc CLI + 养号脚本
|
||||
→ mc run → nurture_loop() → run_one_round()
|
||||
→ 养号: nurture_blueprint.py (Python step list)
|
||||
→ 登录: sms_login.py / xhs_login.py / douyin_login.py
|
||||
→ 状态检测: _execute_op() + read_state() + BehaviorConfig
|
||||
|
||||
Layer 1: 浏览器管理层 — Camoufox
|
||||
→ CDPConnector → Camoufox (Firefox)
|
||||
→ 身份目录: agent-local/tools/matrix/identities/{name}/
|
||||
→ guardd 守护: 每60s检测孤儿浏览器/磁盘/超时
|
||||
```
|
||||
|
||||
### 1.3 命令分发全过程
|
||||
|
||||
```
|
||||
你在 Dashboard 选账号 → 选蓝图 → 填参数 → 点执行
|
||||
↓
|
||||
POST /api/ops/run {
|
||||
"type": "nurture",
|
||||
"accounts": ["douyin_01"],
|
||||
"params": {"blueprint": "douyin_daily", "rounds": 3}
|
||||
}
|
||||
↓
|
||||
CommandBus.dispatch()
|
||||
→ 从 ORACLE.yaml 查到 douyin_01 属于机器 A
|
||||
→ 获取/创建 MachineSession(A)
|
||||
→ preflight(): SSH可达? 活跃命令<3?
|
||||
→ 本机: Popen("mc run --accounts=douyin_01 --blueprint=douyin_daily --rounds=3")
|
||||
→ 远程: SSH("mc run ... > /tmp/ops_xxx.log &")
|
||||
↓
|
||||
GET /api/ops/status ← 轮询状态
|
||||
→ 本地: 读 runtime/nurture/results/{run_id}.json
|
||||
→ 远程: SSH cat 远程的结果文件
|
||||
↓
|
||||
执行结果写文件 → Dashboard 显示
|
||||
```
|
||||
|
||||
**这就是现有的框架。我 v1/v2 里写的"新五层模型"是重复造轮子,已废弃。**
|
||||
|
||||
---
|
||||
|
||||
## 二、我用状态机要加的东西(不做新框架,只加新模块)
|
||||
|
||||
### 2.1 加什么
|
||||
|
||||
| 模块 | 位置 | 说明 | 依赖现有代码 |
|
||||
|:-----|:------|:-----|:-----------|
|
||||
| `login_state_machine.py` | `matrix_modules/account/` | 登录检测 + Cookie恢复 + SMS重登 | 复用 `xhs_login.py` `sms_login.py` `douyin_login.py` |
|
||||
| `blueprint_engine.py` | `matrix_modules/` | 蓝图执行引擎(注入状态检查钩子) | 复用 `nurture_blueprint.py` `runner.py` 的 step 格式 |
|
||||
| `cooldown_manager.py` | `matrix_modules/nurture/` | 操作冷却管理 | 对接现有 `BehaviorConfig` |
|
||||
| `vision_bridge.py` | ✅ 已存在 | oMLX 视觉分析 | 独立模块 |
|
||||
|
||||
### 2.2 不加什么
|
||||
|
||||
| ❌ 不加 | 原因 |
|
||||
|:---------|:------|
|
||||
| 新的命令分发 | `CommandBus` + `MachineSession` 已经完整 |
|
||||
| 新的路由 API | `ops.py` 的 `POST /api/ops/run` 已定义格式 |
|
||||
| 新的 ORACLE | ORACLE.yaml 已经是宪法 |
|
||||
| 新的身份管理 | 身份目录 + 账号分配已经在 ORACLE 中 |
|
||||
| 新的看板 | Dashboard 已有完整前后端 |
|
||||
|
||||
### 2.3 状态机怎么嵌入现有流程
|
||||
|
||||
```
|
||||
现有流程:
|
||||
POST /api/ops/run → CommandBus → subprocess(Popen mc run) → 写结果文件
|
||||
|
||||
我要加的 (在 mc run 内部加钩子):
|
||||
mc run → 登录状态机(加在开头) → 蓝图执行 → 每步后检查验证弹窗 → 冷却管理
|
||||
↑ 复用现有 nurture_blueprint.py
|
||||
```
|
||||
|
||||
核心改动点:**在 `nurture_blueprint.py` / `runner.py` 的执行循环里插入三个钩子**:
|
||||
|
||||
```python
|
||||
# 现有代码 (runner.py nurture_loop)
|
||||
for round in range(rounds):
|
||||
for step in blueprint_steps:
|
||||
result = await step.fn(page) # ← 现有代码
|
||||
|
||||
# 改为:
|
||||
for round in range(rounds):
|
||||
# 钩子1: 每轮开始前检测登录(新增)
|
||||
await login_state_machine.ensure_login(page, account)
|
||||
|
||||
for step in blueprint_steps:
|
||||
# 钩子2: 执行每步后检查验证(新增)
|
||||
result = await step.fn(page) # ← 现有代码
|
||||
if result == 'VERIFY':
|
||||
await verification_handler.handle(page)
|
||||
continue
|
||||
|
||||
# 钩子3: 冷却等待(新增)
|
||||
await cooldown_manager.wait(step.op)
|
||||
```
|
||||
|
||||
**不改现有代码结构,只插入三个钩子。**
|
||||
|
||||
---
|
||||
|
||||
## 三、蓝图:保持现有 JSON 格式 + 参数模板
|
||||
|
||||
### 3.1 当前 JSON 格式(保留不动)
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "douyin_comment",
|
||||
"steps": [
|
||||
{"step_id": 1, "op": "goto_url", "args": {"url": "@url"}},
|
||||
{"step_id": 2, "op": "wait_watch", "args": {}},
|
||||
{"step_id": 3, "op": "open_comments", "args": {}},
|
||||
{"step_id": 4, "op": "post_comment", "args": {"text": "@comment_text"}},
|
||||
{"step_id": 5, "op": "close_comments", "args": {}}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**`@url` `@corpus` `@keyword` 这种参数模板系统很好**,保留并在 Dashboard 执行时替换。
|
||||
|
||||
### 3.2 怎么区分评论的两种模式
|
||||
|
||||
抖音评论有**两种入口**(当前代码已有这两种操作):
|
||||
|
||||
| op | 场景 | 当前实现位置 |
|
||||
|:---|:------|:-----------|
|
||||
| `post_comment` | 在视频评论区直接发评论 | `nurture_blueprint.py:op_comment()` |
|
||||
| `reply_comment` | 回复某条已有评论 | `runner.py:reply_comment` (蓝图 `douyin_reply` 中用) |
|
||||
|
||||
蓝图选哪个 op 取决于你下发的参数。评论时如果给了 `reply_to` 就用 `reply_comment`,否则用 `post_comment`。
|
||||
|
||||
### 3.3 语料库 + 多账号跟踪评论
|
||||
|
||||
语料库存放:
|
||||
```
|
||||
05_tools/07_matrix/corpus/
|
||||
├── corpus_praise.json → ["好作品!", "太棒了!", ...]
|
||||
├── corpus_question.json → ["请问怎么做的?", ...]
|
||||
└── corpus_thread.json → [
|
||||
{"step1": "第一句: 好作品!", "step2": "第二句回复: 同意!", "step3": "第三句: 关注了"}
|
||||
]
|
||||
```
|
||||
|
||||
**跟踪评论(A→B→C)通过蓝图序列实现**:
|
||||
|
||||
```python
|
||||
# 在 sequence_runner.py 中:
|
||||
SEQUENCE = [
|
||||
{"blueprint": "comment", "account": "xhs_01", "params": {"url": "@input_url", "text": "@corpus_thread[0]"}},
|
||||
{"blueprint": "reply_comment", "account": "douyin_test", "params": {"target_text": "@corpus_thread[0]", "reply": "@corpus_thread[1]"}},
|
||||
{"blueprint": "reply_comment", "account": "douyin_133", "params": {"target_text": "@corpus_thread[1]", "reply": "@corpus_thread[2]"}},
|
||||
]
|
||||
```
|
||||
|
||||
每条语料的 step1/step2/step3 会被自动取用。这个不走新框架,直接走现有的 CommandBus 顺序下发。
|
||||
|
||||
---
|
||||
|
||||
## 四、登录状态机(唯一真正要写的新模块)
|
||||
|
||||
### 4.1 接口
|
||||
|
||||
```python
|
||||
class LoginStateMachine:
|
||||
async def ensure_login(self, page, account_id: str, platform: str) -> bool:
|
||||
"""确保登录,返回 True=已登录"""
|
||||
|
||||
async def _detect(self, page, platform: str) -> str:
|
||||
"""检测状态: 'logged_in' / 'not_logged' / 'unknown'"""
|
||||
# DOM 检测: xhs → .user-avatar douyin → [data-e2e=user-avatar]
|
||||
|
||||
async def _recover_cookie(self, page) -> bool:
|
||||
"""刷新页面让 cookie 生效"""
|
||||
|
||||
async def _recover_sms(self, page, phone: str) -> bool:
|
||||
"""SMS 验证码登录"""
|
||||
# 复用 sms_login.py 的原子操作
|
||||
```
|
||||
|
||||
### 4.2 用法
|
||||
|
||||
```python
|
||||
# 在 runner.py nurture_loop 开头加:
|
||||
async def nurture_loop(...):
|
||||
lsm = LoginStateMachine()
|
||||
ok = await lsm.ensure_login(page, identity_name, platform)
|
||||
if not ok:
|
||||
return {"status": "failed", "error": "login_failed"}
|
||||
# ... 继续现有逻辑
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、执行计划(只做增量,不重构)
|
||||
|
||||
| 任务 | 文件 | 工作量 | 前置依赖 |
|
||||
|:-----|:------|:------|:--------|
|
||||
| 写 LoginStateMachine | `matrix_modules/account/login_state_machine.py` | 半天 | 无(复用现有原子操作) |
|
||||
| 加登录钩子到 nurture_loop | 改 `runner.py` + `nurture_blueprint.py` | 1小时 | LoginStateMachine |
|
||||
| 加验证处理钩子到 op 执行后 | 改 `runner.py` | 1小时 | 无(复现现有 _handle_verify) |
|
||||
| 加冷却管理 | `matrix_modules/nurture/cooldown_manager.py` | 1小时 | 无 |
|
||||
| 语料库目录 + 蓝图参数扩展 | `corpus/*.json` + 改 blueprint JSON | 半天 | 无 |
|
||||
| Dashboard 参数表单对接 | `static/index.html` (Vite 迁移后) | 跟 Vite 一起 | Vite 迁移完成 |
|
||||
|
||||
---
|
||||
|
||||
## 六、误区总结(防止再跑偏)
|
||||
|
||||
| 我原来写错的 | 实际上 | 参考文件 |
|
||||
|:------------|:-------|:--------|
|
||||
| "五层新架构" | 已有 `CommandBus` + `MachineSession` + `ORACLE.yaml` | `services/command_bus.py` |
|
||||
| "Dashboard三台都跑" | 只有 chengzigedeAir:9988 | `DEPLOYMENT.md` |
|
||||
| "蓝图是新概念" | 已有 14 个 JSON + 参数模板 `@url` `@corpus` | `blueprints/*.json` |
|
||||
| "新框架要造" | 只在现有代码插三个钩子 | `runner.py` `nurture_blueprint.py` |
|
||||
| "命令格式要定" | 已有 `POST /api/ops/run` 格式已定 | `routes/ops.py` `BUSINESS_ARCHITECTURE_v4.md` |
|
||||
@@ -0,0 +1,239 @@
|
||||
# Vite + Vanilla JS 前端重构计划
|
||||
|
||||
> 创建日期: 2026-06-17 | 执行日期: 2026-06-18
|
||||
> 状态: ⏳ 计划已定,待执行
|
||||
|
||||
---
|
||||
|
||||
## 一、为什么要做
|
||||
|
||||
### 当前问题
|
||||
- `static/index.html` 7700 行,一个文件塞了所有视图
|
||||
- 没有模块化,函数全部全局作用域,名字冲突风险高
|
||||
- 改一行代码必须重启 Dashboard 才能看到效果(没有热更新)
|
||||
- 尝试按行号拆分失败:JS 里的 HTML 模板字面量打断函数边界
|
||||
|
||||
### 目标
|
||||
- 每个视图一个文件,50-300 行
|
||||
- Vite HMR:改代码即时生效,不用重启
|
||||
- `import/export` 代替全局函数
|
||||
- 构建产物输出到 `static/`,Dashboard 原样服务
|
||||
|
||||
---
|
||||
|
||||
## 二、技术栈
|
||||
|
||||
| 层 | 选型 | 理由 |
|
||||
|:---|:-----|:------|
|
||||
| 构建 | **Vite 6** | 零配置启动、HMR、按需编译 |
|
||||
| 语言 | **Vanilla JS** (ES Modules) | 不需要 Vue/React,你的是表格+按钮 UI |
|
||||
| 样式 | **CSS Variables** + 内联样式 | 保持现有设计,不引入 CSS 框架 |
|
||||
| 后端 | **FastAPI** (不变) | 纯 API 层,不碰后端 |
|
||||
| 部署 | Vite build → `static/` 目录 | Dashboard 直接服务静态文件 |
|
||||
|
||||
**不做 Vue/React 的原因**:
|
||||
- 你的页面主要是表格、按钮、选择器,没有复杂的双向绑定
|
||||
- 引入框架 = 额外的学习成本 + 构建配置
|
||||
- Vanilla JS + 原生 `import/export` 足够
|
||||
|
||||
---
|
||||
|
||||
## 三、文件结构
|
||||
|
||||
```
|
||||
agent-sync/05_tools/10_dashboard/
|
||||
├── frontend/ # 新建:Vite 项目目录
|
||||
│ ├── index.html # 入口 HTML(空壳,只含 <div id="app">)
|
||||
│ ├── vite.config.js # Vite 配置
|
||||
│ ├── package.json # 依赖
|
||||
│ └── src/
|
||||
│ ├── main.js # 入口:渲染 app.html、初始化路由
|
||||
│ ├── style.css # 全局样式(从旧 index.html 的 <style> 迁移)
|
||||
│ ├── api.js # fetch 封装 + 所有 API 调用
|
||||
│ ├── router.js # switchView + 侧边栏导航逻辑
|
||||
│ ├── state.js # 全局状态(_allAccounts, currentView 等)
|
||||
│ ├── components/ # 可复用组件
|
||||
│ │ ├── account-selector.js # 共享账号选择器(核心组件)
|
||||
│ │ ├── sidebar.js # 侧边栏导航
|
||||
│ │ ├── stats-bar.js # 顶部状态栏
|
||||
│ │ ├── result-table.js # 结果表格(通用)
|
||||
│ │ └── shell-placeholder.js # _renderShell 替代
|
||||
│ └── views/ # 每个视图一个文件
|
||||
│ ├── matrix-summary.js
|
||||
│ ├── matrix-accounts.js # 账号管理
|
||||
│ ├── matrix-nurture.js # 养号执行(含 nurturePreflight 等)
|
||||
│ ├── matrix-collect.js # 信息采集(含 collectLogin/collectExec)
|
||||
│ ├── matrix-comment.js # 定向评论
|
||||
│ ├── matrix-like.js # 收藏点赞
|
||||
│ ├── matrix-login.js # 登录管理(跳转)
|
||||
│ ├── matrix-blueprints.js # 蓝图管理
|
||||
│ ├── matrix-atom-ops.js # 原子操作
|
||||
│ ├── matrix-schedule.js # 定时任务
|
||||
│ ├── matrix-corpus.js # 语料库
|
||||
│ ├── matrix-run.js # 命令与任务
|
||||
│ ├── ops-command.js # 联邦指挥台
|
||||
│ ├── ops-history.js # 执行历史
|
||||
│ ├── federation.js # 联邦相关
|
||||
│ ├── fleet-sync.js # 一键同步
|
||||
│ ├── fleet-exec.js # 远程 Shell
|
||||
│ ├── ave-render.js # 视频工厂
|
||||
│ └── settings.js # 设置
|
||||
├── static/ # 构建产物输出目录
|
||||
│ └── (构建后自动生成)
|
||||
└── PLANS/VITE_MIGRATION_PLAN.md # 本文件
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、执行步骤(按顺序)
|
||||
|
||||
### Phase 1: 搭建 Vite 项目 (预计 30min)
|
||||
|
||||
```bash
|
||||
cd agent-sync/05_tools/10_dashboard
|
||||
npm create vite@latest frontend -- --template vanilla
|
||||
cd frontend
|
||||
npm install
|
||||
```
|
||||
|
||||
然后:
|
||||
1. 配置 `vite.config.js`:`base: '/static/'`、`build.outDir: '../static'`
|
||||
2. 复制旧 `index.html` 的 `<style>` 内容到 `src/style.css`
|
||||
3. 复制旧 `index.html` 的 HTML 骨架到 `src/main.js` 的 innerHTML
|
||||
4. 验证:`npm run dev` → 能看到页面
|
||||
|
||||
### Phase 2: 迁移核心基础设施 (预计 1h)
|
||||
|
||||
按依赖顺序迁移:
|
||||
|
||||
1. **`src/api.js`** — 封装所有 fetch 调用
|
||||
- `api.getAccounts()`, `api.collectHomepage()`, `api.nurtureStart()` 等
|
||||
- 每个函数返回 Promise,统一错误处理
|
||||
|
||||
2. **`src/router.js`** — 导航路由
|
||||
- `switchView(view)` 函数 → `import()` 动态加载视图文件
|
||||
- 侧边栏高亮逻辑
|
||||
- 子菜单展开/收起
|
||||
|
||||
3. **`src/state.js`** — 全局状态
|
||||
- `_allAccounts`, `_nurtureAccounts` 等
|
||||
- 事件通知机制(账号变更时通知各视图刷新)
|
||||
|
||||
4. **`src/components/account-selector.js`** — 核心组件
|
||||
- 从旧 JS 的 `_renderAccountSelector()` 迁移
|
||||
- 导出为 `class AccountSelector` 或 `function renderAccountSelector()`
|
||||
- 支持 `onSelectionChange` 回调
|
||||
|
||||
### Phase 3: 逐个迁移视图 (预计 3h)
|
||||
|
||||
按优先级从高到低:
|
||||
|
||||
1. `matrix-nurture.js` — 养号执行(含预检、执行、轮询)
|
||||
2. `matrix-collect.js` — 信息采集(含登录+采集)
|
||||
3. `matrix-comment.js` — 定向评论
|
||||
4. `matrix-like.js` — 收藏点赞
|
||||
5. `matrix-blueprints.js` — 蓝图管理
|
||||
6. `matrix-accounts.js` — 账号管理
|
||||
7. `ops-command.js` — 联邦指挥台
|
||||
8. 其余视图
|
||||
|
||||
### Phase 4: 联调 + 构建 (预计 30min)
|
||||
|
||||
1. `npm run build` → 输出到 `../static/`
|
||||
2. 重启 Dashboard 验证所有视图
|
||||
3. 对比旧版,确保功能一致
|
||||
|
||||
---
|
||||
|
||||
## 五、每个视图的迁移模式
|
||||
|
||||
旧版模式:
|
||||
```javascript
|
||||
// index.html 中
|
||||
async function loadMatrixXxx() {
|
||||
const el = document.getElementById('view-matrix-xxx');
|
||||
el.innerHTML = `<div>...${data}...</div>`;
|
||||
}
|
||||
```
|
||||
|
||||
新版模式:
|
||||
```javascript
|
||||
// views/matrix-xxx.js
|
||||
import { api } from '../api.js';
|
||||
import { renderAccountSelector } from '../components/account-selector.js';
|
||||
import { state } from '../state.js';
|
||||
|
||||
export async function loadView(container) {
|
||||
const data = await api.getSomeData();
|
||||
container.innerHTML = renderTemplate(data);
|
||||
// 绑定事件...
|
||||
}
|
||||
```
|
||||
|
||||
然后 `router.js` 中:
|
||||
```javascript
|
||||
case 'matrix-xxx':
|
||||
import('./views/matrix-xxx.js').then(m => m.loadView(el));
|
||||
break;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、关键注意事项
|
||||
|
||||
### 1. `<script>` 标签的迁移
|
||||
旧 index.html 的 `<script>` 标签内包含所有 JS。迁移后:
|
||||
- 旧文件保留为备份(重命名为 `index_legacy.html`)
|
||||
- 新 Vite 项目从零构建
|
||||
|
||||
### 2. CSS 变量的兼容
|
||||
旧样式使用 CSS 变量(`--bg`, `--text` 等),全部迁移到 `src/style.css`。
|
||||
Vite 会自动注入到 HTML。
|
||||
|
||||
### 3. 模板字面量的迁移
|
||||
Old: `` `<div>${data}</div>` ``
|
||||
New: `` `<div>${data}</div>` `` — 完全一样,只是放到单独的文件中。
|
||||
Vite 对模板字面量没有特殊处理,它们就是普通 JS。
|
||||
|
||||
### 4. 动态 import 路由
|
||||
`router.js` 使用 `import('./views/xxx.js')` 按需加载视图。
|
||||
Vite 会自动代码分割,首次只加载当前视图需要的代码。
|
||||
|
||||
### 5. 后端兼容
|
||||
后端不需要任何改动。Vite 构建产物输出到 `static/`,FastAPI 继续服务。
|
||||
只是 `index.html` 变成 Vite 生成的版本(含构建后的脚本引用)。
|
||||
|
||||
### 6. 回滚方案
|
||||
任何时候出问题:
|
||||
```bash
|
||||
cd frontend
|
||||
git checkout -- index.html # 恢复旧版
|
||||
rm -rf frontend # 删除 Vite 项目
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、验收标准
|
||||
|
||||
- [ ] `npm run dev` 能启动并看到完整页面
|
||||
- [ ] 所有导航视图能正常渲染(22个视图)
|
||||
- [ ] 养号执行能正常运行(预检→执行→验证)
|
||||
- [ ] 信息采集能正常运行
|
||||
- [ ] 共享账号选择器在所有视图正常
|
||||
- [ ] `npm run build` 后 Dashboard 能正常服务
|
||||
- [ ] 三台机器同步后都能工作
|
||||
|
||||
---
|
||||
|
||||
## 八、时间预估
|
||||
|
||||
| 阶段 | 时间 | 说明 |
|
||||
|:-----|:-----|:------|
|
||||
| Phase 1 搭建 | 30min | Vite 项目初始化 |
|
||||
| Phase 2 核心 | 1h | api/router/state/组件 |
|
||||
| Phase 3 视图 (7个主要) | 2h | 养号/采集/评论/点赞/蓝图/账号/指挥台 |
|
||||
| Phase 3 视图 (其余) | 1h | 联邦/设置/视频工厂等 |
|
||||
| Phase 4 联调 | 30min | 构建+验证+三机同步 |
|
||||
| **总计** | **~5h** | |
|
||||
|
||||
明天上午开始,预计一天内完成。
|
||||
@@ -0,0 +1,210 @@
|
||||
# AgentOS Agent Initialization Guide
|
||||
|
||||
> **Version**: 1.0.0 | **Updated**: 2026-06-17
|
||||
> **Purpose**: Teach AI agents how to understand and operate this system correctly.
|
||||
> **Scope**: 3-machine federated system (chengzigedeAir / 5kechengdeAir / 7kecheng)
|
||||
|
||||
---
|
||||
|
||||
## 1. Identity Card
|
||||
|
||||
| Field | Value |
|
||||
|:------|:------|
|
||||
| System | AgentOS — Federated AI Exoskeleton |
|
||||
| Machines | chengzigedeAir (master), 5kechengdeAir (worker), 7kecheng (worker) |
|
||||
| Connection | Tailscale mesh network (100.x.x.x) |
|
||||
| Dashboard | Port 9988 on each machine, launchd auto-start |
|
||||
| Git Repo | `~/workbuddy-agent-os/agent-sync/` (synced to all 3 machines) |
|
||||
|
||||
---
|
||||
|
||||
## 2. Python Environment (MOST IMPORTANT)
|
||||
|
||||
**Never use system Python.** The correct path is:
|
||||
|
||||
```
|
||||
$HOME/.workbuddy/binaries/python/envs/agent-os/bin/python3
|
||||
```
|
||||
|
||||
Or use the dynamic variable (for scripts):
|
||||
|
||||
```bash
|
||||
$MC_PYTHON
|
||||
```
|
||||
|
||||
### Key packages installed:
|
||||
- camoufox 0.4.11
|
||||
- playwright 1.58.0
|
||||
- uvicorn 0.46.0
|
||||
- orjson 3.11.9
|
||||
|
||||
### Common mistakes:
|
||||
- ❌ `python3 -m mc run` → ⚠️ No module named mc (needs PYTHONPATH)
|
||||
- ✅ `cd $AGENT_SYNC/05_tools/07_matrix/scripts && $MC_PYTHON -m mc run ...`
|
||||
- ❌ Running `pip install camoufox` → Already installed in venv
|
||||
- ❌ Using `matrix nurture run` → Legacy tool, use `mc run` instead
|
||||
|
||||
---
|
||||
|
||||
## 3. Command Architecture
|
||||
|
||||
```
|
||||
User → Dashboard (port 9988)
|
||||
→ /api/matrix/nurture/start ← 养号执行入口
|
||||
→ routes/matrix.py ← 自动选蓝图 + 路由到机器
|
||||
→ 本机: subprocess mc run ← 模式1
|
||||
→ 远程: remote_exec exec_nurture ← 模式2 (SSH)
|
||||
→ mc run ← 真正的执行引擎
|
||||
→ mc/engine.py ← 身份分组 + 浏览器启动
|
||||
→ cdp_connector.py ← Camoufox 启动
|
||||
→ matrix_modules/nurture/* ← 原子操作
|
||||
```
|
||||
|
||||
### Key commands for agents:
|
||||
|
||||
```bash
|
||||
# 正确的养号执行(新路径,推荐)
|
||||
cd $AGENT_SYNC/05_tools/07_matrix/scripts
|
||||
$MC_PYTHON -m mc run --accounts=douyin_01 --blueprints=douyin_daily --rounds=10
|
||||
|
||||
# 查看账号列表
|
||||
$MC_PYTHON -m mc account list
|
||||
|
||||
# 智能登录
|
||||
$MC_PYTHON -m mc smart-login douyin_01
|
||||
|
||||
# 远程执行(通过 Dashboard API)
|
||||
curl -X POST http://localhost:9988/api/federation/nurture \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"machine":"7kecheng","accounts":["douyin_137"],"blueprints":["douyin_daily"],"rounds":10}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Identity Directory Resolution
|
||||
|
||||
**Directory naming**: Identity dirs are named by phone number, NOT account ID:
|
||||
```
|
||||
identities/
|
||||
├── phone_18550099569/ ← 身份目录(手机号命名)
|
||||
│ ├── config.yaml
|
||||
│ └── user_data/ ← 浏览器持久化数据
|
||||
├── phone_15358497926/
|
||||
│ ├── config.yaml
|
||||
│ └── user_data/
|
||||
```
|
||||
|
||||
**Account-to-identity mapping**: `accounts.yaml` links account IDs to identity dirs:
|
||||
```yaml
|
||||
- id: douyin_136 # 账号 ID
|
||||
identity_dir: phone_18550099569 # 身份目录(映射关系)
|
||||
phone: '18550099569'
|
||||
platform: douyin
|
||||
owner_machine: 7kecheng # 所属机器
|
||||
```
|
||||
|
||||
**How `mc run` resolves it** (`mc/engine.py:269`):
|
||||
```python
|
||||
# Step 1: Get identity_dir from account info
|
||||
identity_dir = acct.get("identity_dir", acct["id"]) # → "phone_18550099569"
|
||||
|
||||
# Step 2: Strip "identities/" prefix if present
|
||||
identity_dir = identity_dir.replace("identities/", "") # → "phone_18550099569"
|
||||
|
||||
# Step 3: Resolve full path
|
||||
full_path = IDENTITIES_ROOT / identity_dir # → ~/.../identities/phone_18550099569/
|
||||
```
|
||||
|
||||
**❗ NEVER look for `identities/{account_id}/`.** The directories are named by phone number.
|
||||
|
||||
---
|
||||
|
||||
## 5. Machine Routing & Blueprint Auto-Selection
|
||||
|
||||
### Machine routing:
|
||||
Each account has an `owner_machine` field. The API auto-routes:
|
||||
- Local (owner_machine == this machine) → `subprocess.Popen`
|
||||
- Remote (owner_machine != this machine) → SSH via `remote_exec.py`
|
||||
|
||||
### Blueprint auto-selection:
|
||||
| Account Platform | Default Blueprint |
|
||||
|:-----------------|:------------------|
|
||||
| `douyin` | `douyin_daily` |
|
||||
| `xiaohongshu` | `xhs_daily` |
|
||||
|
||||
---
|
||||
|
||||
## 6. Dashboard API
|
||||
|
||||
The Dashboard runs on each machine (port 9988, launchd auto-start on boot).
|
||||
|
||||
### Key API endpoints:
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|:---------|:-------|:------------|
|
||||
| `/api/identity` | GET | Returns this machine's identity |
|
||||
| `/api/machines` | GET | Returns all machines' status |
|
||||
| `/api/matrix/accounts` | GET | List all accounts (federated) |
|
||||
| `/api/matrix/nurture/start` | POST | Execute nurture (see usage below) |
|
||||
| `/api/federation/nurture` | POST | Remote nurture execution |
|
||||
| `/api/health` | GET | Health check |
|
||||
|
||||
### `/api/matrix/nurture/start` request format:
|
||||
|
||||
```json
|
||||
{
|
||||
"accounts": ["douyin_01", "xhs_01"],
|
||||
"rounds": 10,
|
||||
"blueprint": "douyin_daily", // optional, auto-detect if empty
|
||||
"machine": "7kecheng", // optional, auto-route if empty
|
||||
"dry_run": true // preview only, don't execute
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Common Pitfalls for AI Agents
|
||||
|
||||
| Mistake | Why | Fix |
|
||||
|:--------|:----|:----|
|
||||
| Using `python3` | Wrong Python (no packages) | Use `$MC_PYTHON` or absolute venv path |
|
||||
| Running `matrix nurture run` | Legacy CLI, doesn't handle identity mapping | Use `mc run` instead |
|
||||
| Looking for `identities/{account_id}/` | Dirs named by phone number | Check `accounts.yaml` → `identity_dir` field |
|
||||
| Using `--dry-run` flag | `mc run` doesn't support it | Use API's `dry_run: true` field instead |
|
||||
| Installing packages with pip | Already in agent-os venv | Use `$HOME/.workbuddy/binaries/python/envs/agent-os/bin/pip3` if needed |
|
||||
| Running `mc run` from wrong directory | Module not found | Must `cd` to `$AGENT_SYNC/05_tools/07_matrix/scripts` first |
|
||||
| Using CDP port 9222 | Legacy Chrome, now uses Camoufox | Default: camoufox persistence mode |
|
||||
|
||||
---
|
||||
|
||||
## 8. Quick Health Check
|
||||
|
||||
```bash
|
||||
# Check Python venv
|
||||
$HOME/.workbuddy/binaries/python/envs/agent-os/bin/python3 -c "from camoufox import AsyncCamoufox; print('OK')"
|
||||
|
||||
# Check mc CLI
|
||||
PYTHONPATH=$AGENT_SYNC/05_tools/07_matrix/scripts $HOME/.workbuddy/binaries/python/envs/agent-os/bin/python3 -m mc --help
|
||||
|
||||
# Check Dashboard
|
||||
curl -s --connect-timeout 3 http://localhost:9988/api/identity
|
||||
|
||||
# List accounts
|
||||
PYTHONPATH=$AGENT_SYNC/05_tools/07_matrix/scripts $HOME/.workbuddy/binaries/python/envs/agent-os/bin/python3 -m mc account list
|
||||
|
||||
# Test nurture preview
|
||||
curl -s -X POST http://localhost:9988/api/matrix/nurture/start \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"accounts":["douyin_test"],"rounds":1,"dry_run":true}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Environment Variables
|
||||
|
||||
| Variable | Typical Value | Purpose |
|
||||
|:---------|:--------------|:--------|
|
||||
| `$AGENT_SYNC` | `~/workbuddy-agent-os/agent-sync` | Synced git repo root |
|
||||
| `$AGENT_LOCAL` | `~/workbuddy-agent-os/agent-local` | Local (gitignored) data |
|
||||
| `$MC_PYTHON` | `~/.../agent-os/bin/python3` | Dynamic Python discovery |
|
||||
| `$HOME` | `/Users/chengzige` (or `5kecheng`/`7kecheng`) | Machine-specific home |
|
||||
@@ -0,0 +1,316 @@
|
||||
# Matrix 养号系统 — 全面架构文档 v2.2
|
||||
|
||||
> **最后更新**:2026-05-10
|
||||
> **作者**:Claw
|
||||
> **核心原则**:原子操作 × 状态机 × 唯一特征码 × 蓝图链
|
||||
|
||||
---
|
||||
|
||||
## 0. 总架构哲学
|
||||
|
||||
每个操作都是一条因果链:
|
||||
```
|
||||
[唯一前置状态] → [原子操作] → [唯一后置状态]
|
||||
↑ ↓
|
||||
上一个操作的后置 下一个操作的前置
|
||||
```
|
||||
|
||||
**关键规则**:
|
||||
1. 每个状态必须有**唯一的特征码组合**(URL + DOM锚点 + video数量 + 其他)
|
||||
2. 每个操作执行前**必须先验证前置状态**
|
||||
3. 每个操作执行后**必须验证后置状态**
|
||||
4. 验证失败 → 不执行操作,先恢复到一个已知状态
|
||||
5. 所有状态可查询、可追踪、可恢复
|
||||
|
||||
---
|
||||
|
||||
## 1. 完整状态机
|
||||
|
||||
### 1.1 状态定义与特征码
|
||||
|
||||
| 状态ID | 特征码 | 描述 |
|
||||
|--------|--------|------|
|
||||
| `INIT` | 浏览器刚启动,无页面 | 初始态 |
|
||||
| `LOGIN` | URL=`douyin.com` + sessionid Cookie 存在 + `[data-e2e="user-avatar"]` 可见 | 已登录首页 |
|
||||
| `HOME_GRID` | URL=`douyin.com/jingxuan` + `[data-e2e="alink-item"]` >= 3 + video=1(背景) | 精选页卡片列表 |
|
||||
| `HOME_RECOMMEND` | URL=`douyin.com/?recommend=1` + `[data-e2e="alink-item"]` >= 3 | 推荐页卡片列表 |
|
||||
| `VIDEO_PLAYER` | URL 含 `/video/` 或 `modal_id` + video>=2 + `[data-e2e="video-player-digg"]` 存在 | 视频播放页 |
|
||||
| `COMMENT_PANEL` | `VIDEO_PLAYER` + `[data-e2e="comment-list"]` 可见 + `.public-DraftEditor-content` 存在 | 评论区已打开 |
|
||||
| `INPUT_FOCUSED` | `COMMENT_PANEL` + `document.activeElement` 是 `.public-DraftEditor-content` + 光标闪烁 | 输入框已聚焦 |
|
||||
| `TEXT_ENTERED` | `INPUT_FOCUSED` + `.public-DraftEditor-content` 的 `textContent.length > 0` | 文字已输入 |
|
||||
| `COMMENT_SENT` | 评论已发送 + `[data-e2e="comment-list"]` 内含刚发的文本 | 评论已发送 |
|
||||
| `SEARCH` | URL 含 `/search/` + `[data-e2e="searchbar-input"]` | 搜索结果页 |
|
||||
| `VERIFY_CODE` | `.second-verify-panel` 或 `input[placeholder*="验证码"]` 可见 | 验证码弹窗 |
|
||||
| `UNKNOWN` | 无法匹配任何已知特征码 | 未知状态 |
|
||||
|
||||
### 1.2 状态迁移图
|
||||
|
||||
```
|
||||
INIT → LOGIN → HOME_GRID → VIDEO_PLAYER → COMMENT_PANEL → INPUT_FOCUSED → TEXT_ENTERED → COMMENT_SENT
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
HOME_GRID SEARCH ←回首页→ VERIFY_CODE ←聚焦失败→ 发送失败→
|
||||
↓ ↑
|
||||
VIDEO_PLAYER ←—— 点卡片/导航视频URL ————————————————————————————————————————
|
||||
```
|
||||
|
||||
### 1.3 状态检测函数
|
||||
|
||||
核心检测函数 `detect_state(page)` 返回当前状态ID:
|
||||
|
||||
```python
|
||||
async def detect_state(page) -> str:
|
||||
"""返回当前状态ID(唯一可识别)"""
|
||||
# 检测优先级:从最具体到最通用
|
||||
# 1. 验证码弹窗
|
||||
if has_verify_popup: return "VERIFY_CODE"
|
||||
# 2. 评论发送成功
|
||||
if has_comment_list_with_text: return "COMMENT_SENT"
|
||||
# 3. 文字已输入
|
||||
if editor_has_text: return "TEXT_ENTERED"
|
||||
# 4. 输入框聚焦
|
||||
if editor_is_focused: return "INPUT_FOCUSED"
|
||||
# 5. 评论区打开
|
||||
if comment_panel_visible: return "COMMENT_PANEL"
|
||||
# 6. 视频播放
|
||||
if video_player_active: return "VIDEO_PLAYER"
|
||||
# 7. 搜索结果
|
||||
if search_page: return "SEARCH"
|
||||
# 8. 首页/推荐
|
||||
if home_page: return "HOME_GRID" / "HOME_RECOMMEND"
|
||||
# 9. 已登录
|
||||
if logged_in: return "LOGIN"
|
||||
return "UNKNOWN"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 原子操作完整清单
|
||||
|
||||
每个原子操作 = (名称, 前置状态, 操作, 后置状态, 超时, 重试策略)
|
||||
|
||||
### 2.1 登录段
|
||||
|
||||
| 原子操作 | 前置 | 操作 | 后置 | 特征码变化 |
|
||||
|---------|------|------|------|-----------|
|
||||
| `navigate_login` | `INIT` | goto douyin.com → 等待页面加载 | `LOGIN` | URL→douyin + sessionid存在 |
|
||||
|
||||
### 2.2 首页段
|
||||
|
||||
| 原子操作 | 前置 | 操作 | 后置 | 特征码变化 |
|
||||
|---------|------|------|------|-----------|
|
||||
| `goto_home` | `LOGIN`/任意 | 导航到 douyin.com/?recommend=1 | `HOME_GRID` | URL→jingxuan + alink-item≥3 |
|
||||
| `click_video_card` | `HOME_GRID` | 双击 `.discover-video-card-item` 或 `[data-e2e="alink-item"]` | `VIDEO_PLAYER` | video≥2 + `/video/` 或 player UI |
|
||||
| `search_keyword` | `HOME_GRID` | 输入关键词+Enter | `SEARCH` | URL→/search/ |
|
||||
| `click_search_result` | `SEARCH` | 点击第一个结果卡片 | `VIDEO_PLAYER` | video≥2 |
|
||||
| `scroll_feed` | `HOME_GRID` | 鼠标滚轮/键盘下滑 | `HOME_GRID` | URL不变,卡片刷新 |
|
||||
|
||||
### 2.3 视频播放段
|
||||
|
||||
| 原子操作 | 前置 | 操作 | 后置 | 特征码变化 |
|
||||
|---------|------|------|------|-----------|
|
||||
| `wait_watch` | `VIDEO_PLAYER` | 等待N秒 | `VIDEO_PLAYER` | video 内容变化(可选) |
|
||||
| `like_video` | `VIDEO_PLAYER` | 按Z/点digg按钮 | `VIDEO_PLAYER` | digg_state→digged |
|
||||
| `collect_video` | `VIDEO_PLAYER` | 点收藏按钮 | `VIDEO_PLAYER` | 收藏状态变化 |
|
||||
| `follow_author` | `VIDEO_PLAYER` | 按G/点关注 | `VIDEO_PLAYER` | 关注按钮变化 |
|
||||
| `next_video` | `VIDEO_PLAYER` | 键盘ArrowDown / 滚轮 | `VIDEO_PLAYER` | video.src变化 |
|
||||
| `open_comments` | `VIDEO_PLAYER` | 按X / 点评论图标 | `COMMENT_PANEL` | comment-list可见 + .public-DraftEditor-content存在 |
|
||||
|
||||
### 2.4 评论段
|
||||
|
||||
| 原子操作 | 前置 | 操作 | 后置 | 特征码变化 |
|
||||
|---------|------|------|------|-----------|
|
||||
| `focus_editor` | `COMMENT_PANEL` | Playwright locator双击 `.public-DraftEditor-content` | `INPUT_FOCUSED` | activeElement=编辑器 |
|
||||
| `type_comment` | `INPUT_FOCUSED` | `page.keyboard.type()` 逐字输入 | `TEXT_ENTERED` | editor textContent>0 |
|
||||
| `send_comment` | `TEXT_ENTERED` | 点击发送按钮 / Ctrl+Enter / Alt+Enter | `COMMENT_SENT` / `VERIFY_CODE` | comment-list含文本 |
|
||||
| `close_comments` | `COMMENT_PANEL` | 按X / Escape | `VIDEO_PLAYER` | comment-list消失 |
|
||||
|
||||
### 2.5 恢复段
|
||||
|
||||
| 原子操作 | 前置 | 操作 | 后置 | 特征码变化 |
|
||||
|---------|------|------|------|-----------|
|
||||
| `recover_home` | 任意 | 导航到 douyin.com → 等待卡片加载 | `HOME_GRID` | URL+卡片 |
|
||||
| `recover_video` | `HOME_GRID`/任意 | 点卡片进入视频 | `VIDEO_PLAYER` | video≥2 |
|
||||
| `recover_comments` | `VIDEO_PLAYER` | 开评论(键盘+DOM双策略) | `COMMENT_PANEL` | comment-list可见 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 完整蓝图链:评论流程
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 蓝图:douyin_comment_send │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ Step 1: goto_home │
|
||||
│ pre: INIT or any post: HOME_GRID │
|
||||
│ anchor: URL=jingxuan + alink-item≥3 │
|
||||
│ fail: 重试3次,截图 │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ Step 2: click_video_card │
|
||||
│ pre: HOME_GRID post: VIDEO_PLAYER │
|
||||
│ anchor: video≥2 + player UI │
|
||||
│ 操作: 双击 .discover-video-card-item 或 alink-item │
|
||||
│ fail: goto_home → 重试 │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ Step 3: open_comments │
|
||||
│ pre: VIDEO_PLAYER post: COMMENT_PANEL │
|
||||
│ anchor: comment-list可见 + Draft-editor存在 │
|
||||
│ 操作: 键盘X / DOM点评论图标 / 键盘x │
|
||||
│ fail: 恢复VIDEO_PLAYER → 重试 │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ Step 4: focus_editor │
|
||||
│ pre: COMMENT_PANEL post: INPUT_FOCUSED │
|
||||
│ anchor: activeElement = .public-DraftEditor-content │
|
||||
│ 操作: Playwright locator 双击编辑器 │
|
||||
│ 兜底: DOM focus + click / 坐标(479,687)双击 │
|
||||
│ fail: 恢复COMMENT_PANEL → 重试 │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ Step 5: type_comment │
|
||||
│ pre: INPUT_FOCUSED post: TEXT_ENTERED │
|
||||
│ anchor: editor.textContent.length > 0 │
|
||||
│ 操作: page.keyboard.type(text, delay=40) │
|
||||
│ 兜底: execCommand('insertText')逐字符注入 │
|
||||
│ 等待: 1.5s 让 React 处理(发送按钮出现) │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ Step 6: send_comment │
|
||||
│ pre: TEXT_ENTERED post: COMMENT_SENT │
|
||||
│ anchor: comment-list含刚发的文本 │
|
||||
│ 操作: 找发送按钮点击 / Ctrl+Enter / Alt+Enter │
|
||||
│ 兜底: 3次尝试找按钮 → 键盘兜底 │
|
||||
│ 验证: 检查 [data-e2e="comment-list"] 内文本 │
|
||||
│ fail: 检测 VERIFY_CODE │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ Step 7: goto_home (下一轮) │
|
||||
│ pre: COMMENT_SENT post: HOME_GRID │
|
||||
│ 操作: 导航到 douyin.com │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 数据表结构
|
||||
|
||||
### `atomic_ops` — 原子操作注册表
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | INTEGER PK | |
|
||||
| op_name | TEXT UNIQUE | 操作名 |
|
||||
| description | TEXT | 描述 |
|
||||
| action_type | TEXT | click/nav/key/eval/wait |
|
||||
| target | TEXT | 操作目标(选择器/键名/URL) |
|
||||
| pre_state | TEXT | 前置状态ID |
|
||||
| post_state | TEXT | 后置状态ID |
|
||||
| timeout | INTEGER | 超时秒数 |
|
||||
| retry | INTEGER | 重试次数 |
|
||||
| verify_rule | TEXT | 后置验证规则(JSON) |
|
||||
| created_at | DATETIME | |
|
||||
|
||||
### `anchor_rules` — 状态特征码规则
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | INTEGER PK | |
|
||||
| state_name | TEXT | 状态ID |
|
||||
| field | TEXT | 检测字段(url/videoCount/selector等) |
|
||||
| operator | TEXT | eq/neq/gt/gte/lt/lte/includes |
|
||||
| value | TEXT | 期望值 |
|
||||
| logic_group | INTEGER | 同一组AND,不同组OR |
|
||||
| active | BOOLEAN | |
|
||||
| created_at | DATETIME | |
|
||||
|
||||
### `state_transitions` — 合法状态迁移
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | INTEGER PK | |
|
||||
| from_state | TEXT | 起始状态 |
|
||||
| to_state | TEXT | 目标状态 |
|
||||
| via_op | TEXT | 通过哪个操作 |
|
||||
| weight | INTEGER | 权重(优先级) |
|
||||
|
||||
### `action_logs` — 操作执行日志
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | INTEGER PK | |
|
||||
| execution_id | TEXT | 执行批次 |
|
||||
| identity | TEXT | 账号ID |
|
||||
| op_name | TEXT | 操作名 |
|
||||
| pre_state | TEXT | 执行前状态 |
|
||||
| post_state | TEXT | 执行后状态 |
|
||||
| success | BOOLEAN | |
|
||||
| duration_ms | INTEGER | |
|
||||
| error | TEXT | |
|
||||
| created_at | DATETIME | |
|
||||
|
||||
### `blueprints` — 蓝图定义
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | TEXT PK | 蓝图ID |
|
||||
| name | TEXT | 名称 |
|
||||
| version | TEXT | 版本 |
|
||||
| steps | JSON | 步骤序列 |
|
||||
| created_at | DATETIME | |
|
||||
|
||||
---
|
||||
|
||||
## 5. 关键选择器清单
|
||||
|
||||
### 5.1 页面检测
|
||||
|
||||
| 检测项 | 选择器/代码 | 说明 |
|
||||
|--------|-------------|------|
|
||||
| 视频播放页 | `document.querySelectorAll('video').length >= 2` + `[data-e2e="video-player-digg"]` | video≥2 + player按钮 |
|
||||
| 评论区打开 | `[data-e2e="comment-list"]` + `.public-DraftEditor-content` | 列表+编辑器都存在 |
|
||||
| 输入框聚焦 | `document.activeElement === document.querySelector('.public-DraftEditor-content')` | activeElement是编辑器 |
|
||||
| 输入框有内容 | `.public-DraftEditor-content.textContent.length > 0` | 编辑器内有文字 |
|
||||
| 验证码弹窗 | `.second-verify-panel` / `input[placeholder*="验证码"]` | |
|
||||
| 首页卡片 | `[data-e2e="alink-item"]` / `.discover-video-card-item` | |
|
||||
|
||||
### 5.2 操作目标
|
||||
|
||||
| 操作 | 方式 | 目标 |
|
||||
|------|------|------|
|
||||
| 进入视频 | Playwright locator双击 | `.discover-video-card-item` 或 `[data-e2e="alink-item"]` |
|
||||
| 打开评论 | 键盘x / DOM 点 | `[data-e2e="video-comment-count"]` 或 `[data-e2e="feed-comment-icon"]` |
|
||||
| 聚焦编辑器 | Playwright locator双击 | `.public-DraftEditor-content` |
|
||||
| 输入文字 | `page.keyboard.type(text)` | 已聚焦的activeElement |
|
||||
| 发送 | DOM找按钮点击 | 按钮含"发送"/上箭头 / Ctrl+Enter / Alt+Enter |
|
||||
|
||||
---
|
||||
|
||||
## 6. 已校准配置
|
||||
|
||||
| 参数 | 窗口 | 值 | 校准日期 |
|
||||
|------|------|-----|---------|
|
||||
| 输入框中心X | 702×783 | 479 | 2026-05-10 (实测算) |
|
||||
| 输入框中心Y | 702×783 | 687 | 2026-05-10 (实测算) |
|
||||
| 离右边缘 | 702 | 223px | 2026-05-10 |
|
||||
| 离底边缘 | 783 | 96px | 2026-05-10 |
|
||||
| 编辑器选择器 | - | `.public-DraftEditor-content` | 2026-05-10 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 已知问题与修复记录
|
||||
|
||||
| 问题 | 状态 | 根因 | 修复 |
|
||||
|------|------|------|------|
|
||||
| `a[href*="/video/"]` 不存在 | ✅ 已修 | 抖音用JS点击事件,不用a标签 | 改用 `[data-e2e="alink-item"]` |
|
||||
| `_detect_page_state` 太严格 | ✅ 已修 | 要求video≥2+playerUI才判player | 简化:有video就算player |
|
||||
| `KeyX` 不生效 | ✅ 已修 | 没先点视频区域获取焦点 | 加 `_ensure_video_focused()` 再按x |
|
||||
| 焦点检测在两快键之间 | ✅ 已修 | `page.evaluate` 干扰焦点 | 删除中间的detect调用 |
|
||||
| 评论验证假阳性 | ✅ 已修 | `body.innerText.includes` 命中input内容 | 改查 `[data-e2e="comment-list"]` |
|
||||
| execCommand不触发React | ⚠️ 待测 | Draft.js拦截DOM修改 | 改用 `page.keyboard.type()` |
|
||||
| Camoufox profile lock | ⚠️ 待修 | 强杀不释放 .parentlock | 每次启动前检测+清理 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 后续开发规范
|
||||
|
||||
1. **任何修改前先确认状态** — 读当前状态ID,只执行当前状态允许的操作
|
||||
2. **一次只改一个原子操作** — 不改整条链,改完就测
|
||||
3. **改完更新文档** — 状态机、蓝图、选择器、配置同步更新
|
||||
4. **所有坐标必须从配置读** — 不硬编码,`ui_layout.py` 统一管理
|
||||
5. **验证防假阳性** — 检查特定元素,不用 `body.innerText.includes()`
|
||||
6. **双击之间不插操作** — 不调用 `page.evaluate` 或其他可能干扰焦点的操作
|
||||
@@ -0,0 +1,366 @@
|
||||
# 抖音 Web 端任务接管 — 完整方案文档
|
||||
|
||||
> **版本**: 3.1 | **日期**: 2026-04-27 | **平台**: 抖音网页版
|
||||
> **前置条件**: Chrome + CDP 端口 9222 + Patchright
|
||||
> **阶段A状态**: ✅ 完成(原子操作库V2 + 账号切换器 + 指纹注入 + 双账号并行)
|
||||
|
||||
---
|
||||
|
||||
## 一、架构总览
|
||||
|
||||
```
|
||||
自然语言指令 / 蓝图 JSON
|
||||
↓
|
||||
蓝图引擎 (task_engine.py)
|
||||
↓
|
||||
原子操作库 (douyin_ops.py)
|
||||
↓
|
||||
账号切换器 (switch_account.py) ← V3 新增
|
||||
├── 方案A: Chrome Profile 切换 + 指纹注入
|
||||
└── 方案B: Cookie 注入(实验性)
|
||||
↓
|
||||
CDP 连接器 (cdp_connector.py)
|
||||
↓
|
||||
Chrome (端口 9222/9223/...) → 抖音网页
|
||||
↓
|
||||
代理 IP (静态住宅 IP) ← V3 新增
|
||||
```
|
||||
|
||||
### 核心设计原则
|
||||
|
||||
1. **原子化**:每个操作是最小不可分割单元,含前置检查+执行+后置验证
|
||||
2. **固定起点**:所有蓝图从推荐页 (`goto_home`) 出发,确保状态一致
|
||||
3. **选择器优先**:`data-e2e` > XPath > 键盘 > 鼠标坐标
|
||||
4. **频率安全**:内置操作频率上限(点赞<20/h,评论<5/h)
|
||||
5. **验证码降级**:评论触发验证码 → 取消 → 记录 → 继续
|
||||
6. **账号隔离**:每个账号独立 Profile + 独立端口 + 独立 IP(V3 新增)
|
||||
7. **指纹稳定**:同一账号永远同一指纹模板,不跨进程漂移(V3 新增)
|
||||
|
||||
---
|
||||
|
||||
## 二、原子操作清单
|
||||
|
||||
| 原子操作 | 方法名 | 选择器 | 键盘备选 | 后置验证 |
|
||||
|---------|--------|--------|---------|---------|
|
||||
| 回推荐页 | `goto_home()` | `[data-e2e="douyin-navigation"] a:has-text("推荐")` | - | video.duration > 0 |
|
||||
| 导航到URL | `goto_url(url)` | - | - | URL 变化 |
|
||||
| 后退 | `go_back()` | - | - | URL 变化 |
|
||||
| 点赞 | `like()` | `[data-e2e="video-player-digg"]` | Z | data-e2e-state 变化 |
|
||||
| 收藏 | `collect()` | `[data-e2e="video-player-collect"]` | - | - |
|
||||
| 关注 | `follow()` | `[data-e2e="feed-follow-icon"]` | F | - |
|
||||
| 下翻视频 | `next_video()` | `[data-e2e="video-switch-next-arrow"]` | ↓ | modal_id 变化 |
|
||||
| 上翻视频 | `prev_video()` | `[data-e2e="video-switch-prev-arrow"]` | ↑ | modal_id 变化 |
|
||||
| 播放/暂停 | `toggle_play()` | - | 空格 | video.paused 变化 |
|
||||
| 搜索 | `search(keyword)` | `[data-e2e="searchbar-input"]` | - | URL 含 search |
|
||||
| 点击搜索结果 | `click_search_result(idx)` | `.search-result-card` | - | URL 含 modal_id |
|
||||
| 打开评论 | `open_comments()` | `[data-e2e="feed-comment-icon"]` | X | comment_list 出现 |
|
||||
| 关闭评论 | `close_comments()` | - | X | comment_list 消失 |
|
||||
| 发评论 | `post_comment(text)` | `.public-DraftEditor-content` | Enter | verify_panel? |
|
||||
| 取消验证码 | `cancel_verify()` | `.uc-ui-verify_sms-verify_button.second` | - | 面板消失 |
|
||||
| 观看等待 | `wait_watch(secs)` | - | - | 时间到 |
|
||||
|
||||
---
|
||||
|
||||
## 三、键盘快捷键
|
||||
|
||||
| 键 | 功能 | 可靠性 | 建议 |
|
||||
|----|------|-------|------|
|
||||
| Z | 点赞 | ❌ 焦点问题 | 用点击选择器 |
|
||||
| X | 评论 | ✅ 基本可靠 | 推荐 |
|
||||
| F | 关注/进直播间 | ✅ | 推荐 |
|
||||
| B | 弹幕开关 | ✅ | |
|
||||
| 空格 | 播放/暂停 | ⚠️ 需焦点 | 点击视频先 |
|
||||
| ↑ | 上一个视频 | ⚠️ 需焦点 | 用点击箭头 |
|
||||
| ↓ | 下一个视频 | ⚠️ 需焦点 | 用点击箭头 |
|
||||
| Enter | 搜索确认/评论发送 | ✅ | |
|
||||
|
||||
---
|
||||
|
||||
## 四、蓝图清单
|
||||
|
||||
| 蓝图ID | 名称 | 步骤数 | 状态 |
|
||||
|--------|------|--------|------|
|
||||
| `douyin_browse_v2` | 日常浏览V2 | 11 | ✅ active |
|
||||
| `douyin_search_browse` | 搜索浏览 | 7 | ✅ active |
|
||||
| `douyin_comment_interact` | 评论互动 | 8 | ✅ active |
|
||||
| `douyin_browse` | 日常浏览V1 | 8 | ⛔ deprecated |
|
||||
|
||||
---
|
||||
|
||||
## 五、稳定链路设计
|
||||
|
||||
### 5.1 固定起点流程
|
||||
|
||||
```
|
||||
所有蓝图 → 第1步 goto_home() → 等视频加载 → 后续操作
|
||||
```
|
||||
|
||||
这确保每次执行从同一状态出发,不依赖上次操作的页面残留状态。
|
||||
|
||||
### 5.2 错误恢复策略
|
||||
|
||||
| 错误类型 | 恢复动作 |
|
||||
|---------|---------|
|
||||
| 元素未找到 | 等待1s重试 → 刷新页面重试 → 放弃当前步骤继续 |
|
||||
| 验证码弹出 | cancel_verify() → 记录 → 继续 |
|
||||
| 页面空白/加载超时 | goto_home() 重新开始 |
|
||||
| CDP 断连 | 报错退出,调度器30分钟后重试 |
|
||||
| 连续3步失败 | 熔断:暂停当前蓝图,跳到下一个 |
|
||||
|
||||
### 5.3 操作频率控制
|
||||
|
||||
```python
|
||||
RATE_LIMITS = {
|
||||
"likes_per_hour": 20,
|
||||
"comments_per_hour": 5,
|
||||
"follows_per_hour": 10,
|
||||
"collects_per_hour": 15,
|
||||
"searches_per_hour": 10,
|
||||
}
|
||||
```
|
||||
|
||||
超过频率的操作自动跳过,不报错。
|
||||
|
||||
---
|
||||
|
||||
## 六、选择器维护策略
|
||||
|
||||
### 6.1 三级定位
|
||||
|
||||
| 优先级 | 方式 | 覆盖率 | 失败处理 |
|
||||
|--------|------|--------|---------|
|
||||
| L1 | `data-e2e` 选择器 | 95% | 降级到 L2 |
|
||||
| L2 | XPath / class 选择器 | 4% | 降级到 L3 |
|
||||
| L3 | MLX 视觉定位 | 1% | 人工介入 |
|
||||
|
||||
### 6.2 变更检测
|
||||
|
||||
每次操作记录 `locator_used`,如果 L1 选择器连续失败 3 次:
|
||||
1. 自动写入 `ui_changes` 表
|
||||
2. 标记受影响蓝图状态为 `broken`
|
||||
3. 通知人工扫描页面更新选择器
|
||||
|
||||
---
|
||||
|
||||
## 七、账号切换 + 反检测方案
|
||||
|
||||
### 7.1 当前两套逻辑
|
||||
|
||||
| 方案 | 逻辑 | 优点 | 缺点 |
|
||||
|------|------|------|------|
|
||||
| **A: Chrome Profile 切换** | 每个账号独立 `--user-data-dir`,切换 = 重启 Chrome | Cookie 自然持久化,最简单 | 切换慢(需关闭重开Chrome),同时间只能1个账号 |
|
||||
| **B: Cookie 注入** | 1个浏览器实例,通过 CDP 注入不同 Cookie | 切换快(秒级),可同时多标签 | Cookie 格式复杂,部分平台有额外校验,反检测弱 |
|
||||
|
||||
### 7.2 推荐方案:A 为主,B 备用
|
||||
|
||||
**现阶段(2-5个账号)**:方案 A 足够
|
||||
- 每个账号一个 Chrome Profile 目录
|
||||
- 切换 = 关 Chrome → 重新 `launch_chrome.sh <账号ID> <端口>`
|
||||
- 间隔 10-30 分钟自然切换
|
||||
|
||||
**扩展阶段(5+账号)**:方案 B 补充
|
||||
- 提取 Cookie → JSON 存储 → 注入到新上下文
|
||||
- 需要 `cdp_connector.py` 增加 `inject_cookies()` 方法
|
||||
|
||||
### 7.3 反检测清单
|
||||
|
||||
| 检测维度 | 当前措施 | 下一步 |
|
||||
|---------|---------|--------|
|
||||
| **浏览器指纹** | 真实 Chrome(指纹原生) | 阶段B:Camoufox/Patchright 容器 |
|
||||
| **navigator.webdriver** | Patchright 自动处理 | ✅ 已覆盖 |
|
||||
| **IP地址** | 同一IP(风险中等) | 静态住宅IP(每账号独立) |
|
||||
| **行为模式** | 随机延迟+频率控制 | 增加鼠标轨迹仿真 |
|
||||
| **Cookie/Session** | Chrome Profile 自然持久 | ✅ 已覆盖 |
|
||||
| **操作时间** | 随机间隔 2-15s | 增加活跃时段控制(8:00-23:00) |
|
||||
| **账号关联** | 同一设备不同Profile | 独立代理IP + 不同的浏览习惯 |
|
||||
|
||||
### 7.4 账号切换操作流程
|
||||
|
||||
```
|
||||
1. 结束当前账号蓝图执行
|
||||
2. 记录执行日志到 operation_logs
|
||||
3. 关闭 Chrome(kill进程或关闭窗口)
|
||||
4. 等待 30-120 秒(模拟人工间隔)
|
||||
5. 启动新账号 Chrome:
|
||||
bash ~/matrix/scripts/launch_chrome.sh <新账号ID> <新端口>
|
||||
6. 等待 Chrome 就绪
|
||||
7. 验证 Cookie 是否有效(check_login)
|
||||
8. 开始新账号蓝图执行
|
||||
```
|
||||
|
||||
### 7.5 下一步实施优先级
|
||||
|
||||
| 优先级 | 任务 | 预计时间 | 状态 |
|
||||
|--------|------|---------|------|
|
||||
| **P0** | 账号切换脚本 `switch_account.py` | 2h | ✅ 已完成 |
|
||||
| **P0** | 指纹注入 + 双账号并行验证 | 2h | ✅ 已完成 |
|
||||
| **P1** | 鼠标轨迹仿真(贝塞尔曲线) | 4h | 待开发 |
|
||||
| **P1** | 语料库填充(评论/关键词) | 1h | 待开发 |
|
||||
| **P2** | Cookie 注入方案 B 完善 | 4h | 骨架已有 |
|
||||
| **P2** | 静态住宅IP接入 | 按服务商 | 待购买 |
|
||||
| **P3** | 阶段B:Docker + Camoufox | 2-3天 | 待规划 |
|
||||
|
||||
---
|
||||
|
||||
## 八、账号切换系统(V3 新增)
|
||||
|
||||
### 8.1 两种切换方案
|
||||
|
||||
| 方案 | 机制 | 切换速度 | 可靠性 | 适用场景 |
|
||||
|------|------|---------|--------|---------|
|
||||
| **A: Profile 切换** | 关闭 Chrome → 启动新 Profile → 注入指纹 | ~15秒 | ⭐⭐⭐⭐⭐ | 日常养号 |
|
||||
| **B: Cookie 注入** | 清除 Cookie → 注入新 Cookie → 刷新验证 | ~5秒 | ⭐⭐⭐ | 快速切换(实验性) |
|
||||
|
||||
### 8.2 switch_account.py 用法
|
||||
|
||||
```bash
|
||||
# 列出所有账号
|
||||
python scripts/switch_account.py --list
|
||||
|
||||
# 查看当前状态
|
||||
python scripts/switch_account.py --status
|
||||
|
||||
# 方案A: 切换到 douyin_01
|
||||
python scripts/switch_account.py --method profile --target douyin_01 --port 9222
|
||||
|
||||
# 方案B: Cookie 注入切换
|
||||
python scripts/switch_account.py --method cookie --target douyin_02 --port 9222
|
||||
|
||||
# 导出当前 Cookie(给方案B备用)
|
||||
python scripts/switch_account.py --target douyin_01 --export-cookies
|
||||
```
|
||||
|
||||
### 8.3 切换流程(方案A)
|
||||
|
||||
```
|
||||
1. 关闭当前 Chrome(SIGTERM → 等待 → SIGKILL)
|
||||
2. 启动新 Chrome(目标 Profile + CDP 端口 + 代理)
|
||||
3. 注入浏览器指纹:
|
||||
- 视口覆盖(桌面端 702x783,保持 Cookie 兼容)
|
||||
- 时区覆盖(Asia/Shanghai)
|
||||
- 语言覆盖(zh-CN)
|
||||
- WebGL Vendor/Renderer 注入(覆盖 GPU 指纹)
|
||||
- navigator.webdriver 隐藏
|
||||
- navigator.plugins/languages 伪装
|
||||
- App 跳转拦截(CDP Fetch)
|
||||
4. 验证登录状态
|
||||
5. 更新数据库
|
||||
```
|
||||
|
||||
### 8.4 指纹模板映射
|
||||
|
||||
每个账号 ID 稳定映射到一个指纹模板(同一账号永远同一指纹):
|
||||
|
||||
| 账号 | 指纹模板 | 视口 | 设备 |
|
||||
|------|---------|------|------|
|
||||
| douyin_01 | fp_iphone14pro | 393x852 | iPhone 14 Pro |
|
||||
| douyin_02 | fp_samsung24 | 412x915 | Samsung S24 |
|
||||
| xhs_01 | fp_iphone15pro | 393x852 | iPhone 15 Pro |
|
||||
| zhihu_01 | fp_huawei_p60 | 393x873 | Huawei P60 |
|
||||
|
||||
> ⚠️ 当前养号场景使用桌面端视口(702x783),移动端视口会破坏 Cookie 登录态。
|
||||
> 移动端伪装仅在特殊需要时通过 cdp_connector 单独开启。
|
||||
|
||||
### 8.5 双账号同时运行
|
||||
|
||||
每个账号使用不同的 CDP 端口和 Profile 目录:
|
||||
|
||||
```bash
|
||||
# 终端1: 启动账号1(端口 9222)
|
||||
python scripts/switch_account.py --method profile --target douyin_01 --port 9222
|
||||
|
||||
# 终端2: 启动账号2(端口 9223)
|
||||
python scripts/switch_account.py --method profile --target douyin_02 --port 9223
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、反检测策略(V3 新增)
|
||||
|
||||
### 9.1 当前已实现的反检测
|
||||
|
||||
| 维度 | 措施 | 实现方式 | 状态 |
|
||||
|------|------|---------|------|
|
||||
| **navigator.webdriver** | 隐藏自动化标记 | init_script `undefined` | ✅ |
|
||||
| **HeadlessChrome** | 移除 Headless 标记 | init_script | ✅ |
|
||||
| **WebGL 指纹** | 覆盖 GPU 信息 | init_script | ✅ |
|
||||
| **App 跳转** | 拦截 deeplink | CDP Fetch | ✅ |
|
||||
| **时区/语言** | 统一为中国 | CDP Emulation | ✅ |
|
||||
| **浏览器** | 真实 Chrome | 非 Headless | ✅ |
|
||||
| **plugins** | 伪装非空 | init_script | ✅ |
|
||||
| **Patchright** | 自动处理自动化检测 | 框架级 | ✅ |
|
||||
|
||||
### 9.2 待实现的反检测
|
||||
|
||||
| 维度 | 方案 | 优先级 |
|
||||
|------|------|--------|
|
||||
| **鼠标轨迹** | 贝塞尔曲线仿真(避免完美直线) | P1 |
|
||||
| **输入节奏** | press_sequentially + 随机延迟 | P1(已部分实现) |
|
||||
| **Canvas 指纹** | 噪声注入 | P2 |
|
||||
| **AudioContext 指纹** | 噪声注入 | P2 |
|
||||
| **字体指纹** | 覆盖字体列表 | P3 |
|
||||
| **IP 地址** | 静态住宅代理 | P1(见 IP 方案) |
|
||||
|
||||
### 9.3 鼠标轨迹仿真(下一步)
|
||||
|
||||
当前点击是"瞬移"到目标位置,这不符合人类行为。下一步实现:
|
||||
|
||||
```python
|
||||
# 贝塞尔曲线鼠标移动
|
||||
async def human_move_mouse(page, target_x, target_y, steps=20):
|
||||
"""模拟人类鼠标移动(贝塞尔曲线 + 加减速)"""
|
||||
current = await page.evaluate('() => ({x: window._mx || 0, y: window._my || 0})')
|
||||
start_x, start_y = current['x'], current['y']
|
||||
|
||||
# 随机控制点(贝塞尔曲线)
|
||||
ctrl_x = start_x + (target_x - start_x) * 0.5 + random.uniform(-50, 50)
|
||||
ctrl_y = start_y + (target_y - start_y) * 0.5 + random.uniform(-50, 50)
|
||||
|
||||
for i in range(steps):
|
||||
t = i / steps
|
||||
# ease-in-out 加速曲线
|
||||
t = t * t * (3 - 2 * t)
|
||||
x = (1-t)**2 * start_x + 2*(1-t)*t * ctrl_x + t**2 * target_x
|
||||
y = (1-t)**2 * start_y + 2*(1-t)*t * ctrl_y + t**2 * target_y
|
||||
await page.mouse.move(x, y)
|
||||
await asyncio.sleep(random.uniform(0.01, 0.03))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、IP 切换方案(V3 新增)
|
||||
|
||||
> 详见 `docs/IP_SWITCH_GUIDE.md`
|
||||
|
||||
### 10.1 核心结论
|
||||
|
||||
- **养号最佳选择**:静态住宅 IP(固定 IP + 真实住宅 + 无限流量)
|
||||
- **推荐服务商**:巨量HTTP(¥3-6/个/月)、IPFoxy(¥5-8/个/月)
|
||||
- **最低成本方案**:家里 WiFi + 手机热点(¥0,2-3 个账号)
|
||||
- **不推荐**:数据中心 IP(易识别)、免费代理(不稳定)
|
||||
|
||||
### 10.2 推荐方案(5-10 个账号)
|
||||
|
||||
```
|
||||
买 2-3 个中国静态住宅 IP → 每个 IP 绑 2-3 个账号
|
||||
成本:¥30-50/月
|
||||
```
|
||||
|
||||
### 10.3 技术集成
|
||||
|
||||
Chrome 启动时注入代理:
|
||||
```bash
|
||||
"$CHROME" \
|
||||
--proxy-server="http://user:[email protected]:8080" \
|
||||
--remote-debugging-port="$DEBUG_PORT" \
|
||||
--user-data-dir="$PROFILE_DIR"
|
||||
```
|
||||
|
||||
账号配置增加代理字段:
|
||||
```yaml
|
||||
accounts:
|
||||
- id: douyin_01
|
||||
proxy: "http://user:pass@cn-proxy1:8080"
|
||||
- id: douyin_02
|
||||
proxy: "socks5://user:pass@cn-proxy2:1080"
|
||||
```
|
||||
@@ -0,0 +1,657 @@
|
||||
# MC 系统框架设计方案 v1.1
|
||||
|
||||
> 最后更新: 2026-06-15
|
||||
> 设计目标: 三层分离 + 平台插件化 + 联邦多机协同 + 录制回放全链路 + 原子操作蓝图系统
|
||||
|
||||
---
|
||||
|
||||
## 一、核心设计原则
|
||||
|
||||
1. **CLI 优先** — 所有实操通过 `mc` 命令行执行, 稳定、可脚本化、可审计
|
||||
2. **三层分离** — CLI 做执行 / AI 做分析决策 / Dashboard 做展示, 各司其职
|
||||
3. **平台即插件** — 新增一个平台 = 新建一个目录, 标准接口自动发现
|
||||
4. **不重复造轮子** — 发布/搜索/评论等通用能力集成开源项目
|
||||
5. **联邦多机** — 每台机器独立运行, 通过 SSH/HTTP 远程调用, Gitee 同步状态
|
||||
6. **录制回放即技能** — 原子操作录制是核心差异化能力, 录制包 = 可分享的技能
|
||||
|
||||
---
|
||||
|
||||
## 二、整体架构
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ 第1层: CLI 命令行 (最稳定层, 所有实操的唯⼀入口) │
|
||||
│ ┌──────────────────────────────────────────────────────────┐│
|
||||
│ │ mc [platform] [action] --account <name> [options] ││
|
||||
│ │ mc [通用] [action] [options] ││
|
||||
│ │ mc remote <machine> <command> ← 远程执行 ││
|
||||
│ │ mc record [start|stop|list|replay] ← 录制回放 ││
|
||||
│ └──────────────────────────────────────────────────────────┘│
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ 第2层: MCP Server + AI 智能体 (分析决策, 不直接碰浏览器) │
|
||||
│ ┌──────────────────────────────────────────────────────────┐│
|
||||
│ │ 每个平台插件自动生成 MCP 工具 ││
|
||||
│ │ AI 智能体 → 调 MCP → 调 CLI → 读结果 → 出报告 ││
|
||||
│ └──────────────────────────────────────────────────────────┘│
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ 第3层: Dashboard 看板 (只展示 + 一键触发, 不执行复杂逻辑) │
|
||||
│ ┌──────────────────────────────────────────────────────────┐│
|
||||
│ │ 读 JSON 展示 / 点按钮调 CLI / 看历史趋势图表 ││
|
||||
│ │ 多机聚合: 一台 Dashboard 展示所有机器状态 ││
|
||||
│ └──────────────────────────────────────────────────────────┘│
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ 底座: 联邦多机同步 │
|
||||
│ ┌──────────────┬──────────────┬───────────────────────────┐ │
|
||||
│ │ Gitee 代码 │ SSH 远程执 │ guardd 心跳 + cross_ │ │
|
||||
│ │ 同步(已有) │ 行(新增) │ machine 数据(已有) │ │
|
||||
│ └──────────────┴──────────────┴───────────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、CLI 命令树 (完整版)
|
||||
|
||||
### 3.1 平台插件命令
|
||||
|
||||
```
|
||||
mc douyin|xiaohongshu|bilibili|kuaishou|weibo|wechat [action]
|
||||
login --account <name> 登录
|
||||
logout --account <name> 登出
|
||||
status --account <name> 状态检查
|
||||
collect --account <name> 采集主页信息
|
||||
publish --account <name> 发布视频/图文
|
||||
--file <path>
|
||||
--title <text>
|
||||
--desc <text>
|
||||
nurture --account <name> 养号
|
||||
--blueprint <name>
|
||||
interact --account <name> 互动
|
||||
--action like|comment|follow
|
||||
--target <url/id>
|
||||
search --keyword <text> 搜索
|
||||
--limit <n>
|
||||
live --room-id <id> 直播相关
|
||||
record 录制原子操作(平台专属)
|
||||
start 开始录制
|
||||
stop 停止录制
|
||||
list 列出录制包
|
||||
replay <name> 回放录制包
|
||||
```
|
||||
|
||||
### 3.2 通用管理命令
|
||||
|
||||
```
|
||||
mc account
|
||||
list [--json] 列出所有账号
|
||||
create --phone <num> 创建新身份
|
||||
--platform dy|xhs
|
||||
delete --account <id> 删除账号
|
||||
status [--json] 所有账号状态
|
||||
|
||||
mc sms
|
||||
check --phone <num> 查短信
|
||||
wait --phone <num> 等待新短信
|
||||
|
||||
mc config
|
||||
show [--json] 查看配置
|
||||
set <key> <value> 设置配置
|
||||
|
||||
mc record 原子操作录制(跨平台通用)
|
||||
list 列出所有录制包
|
||||
export <name> --output <p> 导出录制包
|
||||
import <file> 导入录制包
|
||||
analyze <name> 分析录制内容
|
||||
|
||||
mc remote 远程多机执行
|
||||
exec <machine> <cmd> 在远程机器执行命令
|
||||
status [--json] 所有机器状态
|
||||
sync 触发全机同步
|
||||
|
||||
mc agent
|
||||
"分析采集结果" 调 LLM 分析
|
||||
"检查账号健康度"
|
||||
"生成日报"
|
||||
```
|
||||
|
||||
### 3.3 输出规范
|
||||
|
||||
所有命令支持 `--json` 参数, 输出标准 JSON 供 Dashboard 和 AI Agent 消费:
|
||||
|
||||
```bash
|
||||
mc status --all --json
|
||||
# → {"machines": {...}, "accounts": [...], "collected_at": "..."}
|
||||
|
||||
mc douyin collect --account my_name --json
|
||||
# → {"status": "ok", "nickname": "...", "fans": 1303, ...}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、平台插件标准
|
||||
|
||||
### 4.1 目录结构
|
||||
|
||||
```
|
||||
platforms/
|
||||
├── __init__.py # 插件发现: 自动扫描所有子目录
|
||||
├── base.py # BasePlatform 基类
|
||||
│
|
||||
├── douyin/
|
||||
│ ├── __init__.py # 注册: name='douyin', actions=[...]
|
||||
│ ├── cli.py # mc douyin [action] 的命令实现
|
||||
│ ├── collector.py # 主页信息采集 (已有collect_batch_runner)
|
||||
│ ├── publisher.py # 发布 (集成social-auto-upload)
|
||||
│ ├── interactor.py # 互动 (点赞/评论/关注)
|
||||
│ ├── recorder.py # 录制原子操作 (平台专属)
|
||||
│ ├── SKILL.md # AI Agent 调用说明
|
||||
│ └── requirements.txt # 本平台额外依赖
|
||||
│
|
||||
├── xiaohongshu/ # 同上
|
||||
│
|
||||
├── bilibili/ # 发布复用 social-auto-upload
|
||||
│
|
||||
├── kuaishou/ # (TODO)
|
||||
│
|
||||
└── wechat/ # (TODO)
|
||||
```
|
||||
|
||||
### 4.2 插件基类接口
|
||||
|
||||
```python
|
||||
class BasePlatform:
|
||||
name: str # 平台名: 'douyin'
|
||||
display_name: str # '抖音'
|
||||
actions: list[str] # 支持的动作列表
|
||||
|
||||
def login(account_name, headless=False) -> bool
|
||||
def logout(account_name) -> bool
|
||||
def status(account_name) -> dict
|
||||
def collect(account_name) -> dict # 主页信息 → 写 homepage_info.json
|
||||
def publish(account_name, file, title, desc) -> bool
|
||||
def nurture(account_name, blueprint) -> bool
|
||||
def interact(account_name, action, target) -> bool
|
||||
def search(keyword, limit) -> list
|
||||
```
|
||||
|
||||
### 4.3 新增平台流程
|
||||
|
||||
```bash
|
||||
# 1. 创建插件目录
|
||||
mkdir platforms/kuaishou/
|
||||
|
||||
# 2. 实现 base.py 中的接口
|
||||
# - 最简单的: 只实现 status(), 其他返回 "暂不支持"
|
||||
# - 完整版: 逐步实现 login/collect/publish ...
|
||||
|
||||
# 3. 注册插件
|
||||
# platforms/kuaishou/__init__.py:
|
||||
# register_platform(KuaishouPlatform())
|
||||
|
||||
# 4. 完成。mc 自动发现:
|
||||
# mc kuaishou status --account my_account
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、录制回放系统 (核心差异化能力)
|
||||
|
||||
### 5.1 定位
|
||||
|
||||
录制回放是 MC 系统区别于纯开源方案的核心能力。通过录制鼠标/键盘操作, 将人的操作经验转化为可复用的"技能包", 在同平台的不同账号间共享。
|
||||
|
||||
### 5.2 架构
|
||||
|
||||
```
|
||||
录制阶段:
|
||||
人操作浏览器 → mc record start → 记录鼠标/键盘事件 → mc record stop
|
||||
→ 保存为 platforms/douyin/recordings/login.skill (JSON)
|
||||
|
||||
回放阶段:
|
||||
mc douyin record replay login.skill --account my_name
|
||||
→ 按时间轴回放鼠标/键盘事件 → 完成登录
|
||||
|
||||
分享阶段:
|
||||
mc record export login.skill → 得到 .skill 文件
|
||||
→ 提交到 Gitee → 其他机器 mc record import → 直接可用
|
||||
```
|
||||
|
||||
### 5.3 与三层架构的融合
|
||||
|
||||
- **CLI 层**: `mc record list|start|stop|replay|export|import`
|
||||
- **平台插件**: 每个平台可以有专属的录制包 (抖音的登录流程 vs 小红书的登录流程不同)
|
||||
- **跨平台**: 通用的录制包 (如"通用浏览") 放在 `recordings/` 根目录
|
||||
- **Dashboard**: 录制管理界面保留, 但改为调 CLI 执行
|
||||
|
||||
### 5.4 录制包格式规范 (JSON)
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "douyin_login_20260614",
|
||||
"platform": "douyin",
|
||||
"created_at": "2026-06-14T22:00:00",
|
||||
"steps": [
|
||||
{"time": 0, "action": "navigate", "url": "https://www.douyin.com/"},
|
||||
{"time": 3000, "action": "click", "selector": ".login-btn", "x": 350, "y": 680},
|
||||
{"time": 5000, "action": "wait", "duration": 30000},
|
||||
{"time": 35000, "action": "check_login", "expected": true}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、原子操作 + 蓝图系统
|
||||
|
||||
### 6.1 三层模型
|
||||
|
||||
```
|
||||
录制 (record)
|
||||
↓ 捕捉用户在浏览器上的操作
|
||||
原子操作 (atom) = {前置状态锚点, 操作步骤, 后置状态验证}
|
||||
↓ 组合串联成工作流
|
||||
蓝图 (blueprint) = 有向无环图 (DAG) 的原子序列
|
||||
↓ 打包发布为 CLI 命令
|
||||
CLI 命令 = mc [platform] [blueprint_name] --account <name>
|
||||
```
|
||||
|
||||
### 6.2 原子操作的数据结构
|
||||
|
||||
每个原子操作是一个自包含的"操作单元":
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "douyin_like_video",
|
||||
"category": "interact",
|
||||
"platform": "douyin",
|
||||
"version": 1,
|
||||
"description": "点赞当前播放的视频",
|
||||
"before": {
|
||||
"url_pattern": "https://www.douyin.com/**",
|
||||
"dom_anchor": ".video-player",
|
||||
"logged_in": true
|
||||
},
|
||||
"steps": [
|
||||
{"type": "wait", "target": ".like-btn", "timeout": 5000},
|
||||
{"type": "click", "target": ".like-btn", "xpath": "//div[contains(@class, 'like')]"},
|
||||
{"type": "verify", "check": ".like-btn.active"}
|
||||
],
|
||||
"after": {
|
||||
"dom_check": ".like-btn.active"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 蓝图的 DAG 结构
|
||||
|
||||
蓝图 = 多个原子操作按顺序或条件连接成有向无环图:
|
||||
|
||||
```
|
||||
┌─────────┐
|
||||
│ 登录检测 │
|
||||
└────┬────┘
|
||||
│ 未登录
|
||||
┌────▼────┐
|
||||
│ 扫码登录 │
|
||||
└────┬────┘
|
||||
│ 已登录
|
||||
┌────▼────┐
|
||||
│ 打开首页 │
|
||||
└────┬────┘
|
||||
┌────▼────┐
|
||||
│ 浏览推荐 │ ← 循环 5 次
|
||||
└────┬────┘
|
||||
┌────▼────┐
|
||||
│ 随机点赞 │ ← 30% 概率
|
||||
└────┬────┘
|
||||
┌────▼────┐
|
||||
│ 等待 8秒 │
|
||||
└────┬────┘
|
||||
┌────▼────┐
|
||||
│ 滚动加载 │
|
||||
└─────────┘
|
||||
```
|
||||
|
||||
蓝图 JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "douyin_daily_browse",
|
||||
"platform": "douyin",
|
||||
"description": "日常浏览推荐页, 随机点赞",
|
||||
"version": 2,
|
||||
"nodes": [
|
||||
{"id": "check_login", "atom": "check_login", "position": {"x": 100, "y": 0}},
|
||||
{"id": "goto_home", "atom": "goto_home", "position": {"x": 100, "y": 80}},
|
||||
{"id": "browse", "atom": "wait_watch", "position": {"x": 100, "y": 160}},
|
||||
{"id": "like", "atom": "like", "position": {"x": 100, "y": 240}, "probability": 0.3},
|
||||
{"id": "scroll", "atom": "scroll_feed", "position": {"x": 100, "y": 320}}
|
||||
],
|
||||
"edges": [
|
||||
{"from": "check_login", "to": "goto_home"},
|
||||
{"from": "goto_home", "to": "browse"},
|
||||
{"from": "browse", "to": "like"},
|
||||
{"from": "like", "to": "scroll"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 6.4 与 Dashboard 可视化编辑器的关系
|
||||
|
||||
Dashboard 的 **矩阵管理页 (matrix_mgmt.html) 已有 SVG DAG 节点编辑器**。
|
||||
|
||||
蓝图编排流程:
|
||||
|
||||
```
|
||||
打开 Dashboard → 矩阵管理 → 蓝图编排 tab
|
||||
│
|
||||
├─ 左侧节点面板: 列出所有可用原子操作 (按平台/分类)
|
||||
│ 登录类 | 浏览类 | 互动类 | 工具类
|
||||
│
|
||||
├─ 中间画布: 拖拽原子到画布, 连线编排
|
||||
│ 支持: 顺序 / 条件分支 / 循环 / 概率
|
||||
│
|
||||
└─ 右侧属性面板: 配置选中节点的参数
|
||||
等待时间 | 点击概率 | 目标选择器
|
||||
|
||||
|
||||
编辑完成后:
|
||||
→ 保存为 blueprint.json → 存入 blueprints/ 目录
|
||||
→ CLI 直接调用: mc douyin nurture --blueprint douyin_daily --account my_name
|
||||
→ 或用录制功能生成新原子: mc record start → 操作 → mc record stop → 自动生成原子
|
||||
```
|
||||
|
||||
### 6.5 录制 → 原子 → 蓝图 → CLI 全链路
|
||||
|
||||
```
|
||||
步骤1: 录制
|
||||
mc record start ← 打开浏览器, 开始录制
|
||||
→ 人在浏览器上操作 (点赞/评论/浏览...)
|
||||
mc record stop ← 停止录制
|
||||
→ 生成 raw_recording.json (时间轴事件序列)
|
||||
|
||||
步骤2: 提炼原子
|
||||
mc record refine raw_recording.json ← AI 辅助提炼
|
||||
→ 生成 atom.json (结构化原子操作, 含前后状态)
|
||||
|
||||
步骤3: 组合蓝图
|
||||
Dashboard DAG 编辑器 ← 拖拽编排
|
||||
或 CLI: mc blueprint compose --atoms a1,a2,a3
|
||||
→ 生成 blueprint.json
|
||||
|
||||
步骤4: 打包发布
|
||||
mc blueprint publish douyin_daily_v3 ← 注入 blueprints/
|
||||
→ 自动生成 CLI 入口
|
||||
mc douyin nurture --blueprint douyin_daily_v3 --account my_name
|
||||
```
|
||||
|
||||
### 6.6 适配界面版本更新
|
||||
|
||||
当平台改版 (DOM 结构变化), 旧原子可能失效。方案:
|
||||
|
||||
1. **录制新操作**: `mc record start` → 在新版界面上操作 → `mc record stop`
|
||||
2. **对比旧原子**: `mc record diff old_atom.json new_recording.json`
|
||||
3. **自动修补**: AI 分析差异, 更新选择器/css/xpath
|
||||
4. **版本管理**: 原子带 `version` 字段, 旧版蓝图可指定使用旧版原子
|
||||
|
||||
---
|
||||
|
||||
## 七、联邦多机协同方案
|
||||
|
||||
### 6.1 现状评估
|
||||
|
||||
| 能力 | 当前状态 | 评价 |
|
||||
|------|:-------:|:----:|
|
||||
| 代码同步 | Gitee push/pull | ✅ 够用 |
|
||||
| 数据同步 | cross_machine 目录 | ✅ 够用 |
|
||||
| 心跳检测 | guardd (300s 周期) | ⚠️ 基本够用, 但不够实时 |
|
||||
| 远程执行 | ❌ 无 | 需开发 |
|
||||
| 中央调度 | ❌ 无 | 按需 |
|
||||
|
||||
### 6.2 远程执行方案
|
||||
|
||||
最简单的方案: **SSH 包装 + 各机器 HTTP API**
|
||||
|
||||
```bash
|
||||
# 方案A: SSH 远程执行 (简单可靠)
|
||||
mc remote exec chengzigedeAir "mc douyin collect --account my_name"
|
||||
# → ssh chengzigedeAir "cd ~/agent-os/... && python mc collect ..."
|
||||
|
||||
# 方案B: HTTP API 远程执行 (无需 SSH 配置)
|
||||
mc remote exec chengzigedeAir "mc douyin collect"
|
||||
# → curl http://chengzigedeAir:9988/api/cli/run
|
||||
# (每台机器 Dashboard 新增 /api/cli/run 端点)
|
||||
|
||||
# 方案C: 集群广播
|
||||
mc remote exec --all "mc collect --all"
|
||||
# → 同时在所有机器上执行采集
|
||||
```
|
||||
|
||||
推荐方案: **B + A 双通道**。默认走 HTTP API (配置了 SSH 的机器可选 SSH)。
|
||||
|
||||
### 6.3 机器注册与管理
|
||||
|
||||
每台机器在首次部署时, 在 cross_machine/machines/ 下注册:
|
||||
|
||||
```yaml
|
||||
# cross_machine/machines/7kecheng.yaml
|
||||
hostname: 7kecheng
|
||||
ip: 192.168.31.96
|
||||
port: 9988
|
||||
ssh_user: 7kecheng
|
||||
capabilities: [douyin, xiaohongshu] # 这台机器能操作哪些平台
|
||||
local_accounts: 11 # 本机账号数
|
||||
```
|
||||
|
||||
### 6.4 guardd 替换方案: 从 Gitee 迁移到 Tailscale
|
||||
|
||||
#### 当前 guardd 的问题
|
||||
|
||||
guardd 每 300s 往 Gitee 仓库的 `04_memory/cross_machine/` 写心跳文件:
|
||||
|
||||
```
|
||||
问题1: 每次 git status 都有 10 个文件被修改, 分不清是心跳还是真改动
|
||||
问题2: 多机同时写 Gitee 导致 push/pull 冲突
|
||||
问题3: 心跳延迟 (Gitee push 不是实时的)
|
||||
问题4: 仓库里混入大量无意义的自动生成文件
|
||||
```
|
||||
|
||||
**核心矛盾: Git 是版本管理工具, 不是实时状态同步工具。把心跳数据放 Gitee 是架构错误。**
|
||||
|
||||
#### 替换方案: 本地状态 + Tailscale 即时查询
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────┐
|
||||
│ 部署前: guardd → Gitee (10个json频繁更新, 冲突不断) │
|
||||
│ │
|
||||
│ 部署后: 各机本地存状态 + 需查询时走 Tailscale HTTP API │
|
||||
│ │
|
||||
│ Gitee 仓库只保留: │
|
||||
│ 代码 + 配置 + cross_machine/machines/ (机器注册, │
|
||||
│ 几乎不变) │
|
||||
│ │
|
||||
│ 各机本地保留: │
|
||||
│ agent-local/tools/matrix/data/status.json │
|
||||
│ (心跳数据, 不参与 Gitee 同步) │
|
||||
│ │
|
||||
│ 实时查询: │
|
||||
│ mc remote status → 通过 Tailscale 查各机 API │
|
||||
│ 实时返回, 无冲突, 无延迟 │
|
||||
└────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 具体实施
|
||||
|
||||
```
|
||||
步骤1: guardd 停止写 Gitee 的 cross_machine/data/
|
||||
→ 改为写本机 agent-local/tools/matrix/data/guardd_status.json
|
||||
→ 文件格式不变, 只是换了个目录
|
||||
|
||||
步骤2: guardd 不再提交 git
|
||||
→ 从 guardd.py 中去掉 git add/commit/push 步骤
|
||||
→ cross_machine/data/*.json 文件不再被更新
|
||||
|
||||
步骤3: Gitee 仓库清理
|
||||
→ 把 04_memory/cross_machine/data/ 加入 .gitignore
|
||||
→ 一次性提交删除历史心跳文件
|
||||
→ 以后 git status 不再被心跳文件污染
|
||||
|
||||
步骤4: 即时状态替代
|
||||
→ 每台机器 Dashboard 提供 /api/machine/status 端点
|
||||
→ mc remote status 通过 Tailscale 查各机
|
||||
→ 实时, 无冲突, 零延迟
|
||||
```
|
||||
|
||||
#### 对比
|
||||
|
||||
| 维度 | guardd (当前) | guardd (改造后) | mc remote |
|
||||
|------|:------------:|:---------------:|:---------:|
|
||||
| 存储位置 | Gitee 仓库 | 本机 local 目录 | 内存 + API |
|
||||
| 更新频率 | 300s | 300s 或更长 | 即时查询 |
|
||||
| Git 冲突 | ⚠️ 频繁 | ✅ 完全没有 | ✅ 不涉及 Git |
|
||||
| 实时性 | ❌ 有延迟 | ❌ 有延迟 | ✅ 实时 |
|
||||
| 历史记录 | ✅ 有 | ✅ 仍保留 | ❌ 无 (可加日志) |
|
||||
|
||||
**结论: guardd 保留, 但停止写 Gitee。改为写本机 + `mc remote` 做即时查询。** (2026-06-14 已实施)
|
||||
|
||||
### 6.5 `mc remote` 命令(已实现)
|
||||
|
||||
```bash
|
||||
mc remote list # 列出已注册机器(来源: 本机machines.json + cross_machine/machines/)
|
||||
mc remote ping [host] # 连通性测试 (调用 /api/health)
|
||||
mc remote status [host] # 获取所有/指定机器完整状态 (调用 /api/machine/status)
|
||||
mc remote exec <host> <cmd> # 在远程机器执行 mc 命令 (调用 /api/machine/exec)
|
||||
```
|
||||
|
||||
**通信方式 (--via):**
|
||||
- `auto` (默认): 先试 HTTP API (Tailscale IP:9988), 失败自动回退 SSH
|
||||
- `http`: 强制走 HTTP API (Dashboard 端点)
|
||||
- `ssh`: 强制走 SSH 通道
|
||||
|
||||
**Dashboard 新增端点 (均已在 app.py 实现):**
|
||||
```python
|
||||
GET /api/machine/status # 本机完整状态 (系统/矩阵/采集/磁盘/guardd)
|
||||
POST /api/machine/exec # 远程执行 mc 命令 (白名单安全限制)
|
||||
```
|
||||
|
||||
**Tailscale 安装 (可选, 但强烈推荐):**
|
||||
```bash
|
||||
brew install tailscale # 每台机器都安装
|
||||
tailscale up # 登录同一账号, 获得 100.x.x.x IP
|
||||
# 之后 mc remote 通过该加密 IP 通信, 跨网络、跨子网、端到端加密
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、与开源项目的集成边界
|
||||
|
||||
| 功能 | 策略 | 具体方案 |
|
||||
|------|:----:|----------|
|
||||
| **抖音采集主页** | 🏗️ 自研 | 已有的 collect_batch_runner, 优势是联邦多机+批量错峰 |
|
||||
| **小红书采集主页** | 🏗️ 自研 | Camoufox 方式, 修"我"按钮断点 |
|
||||
| **录制回放** | 🏗️ 自研 | ⭐ 核心差异化能力, 开源项目没有 |
|
||||
| **抖音发布视频** | 📦 集成 | social-auto-upload 的 douyin_uploader |
|
||||
| **小红书发布笔记** | 📦 集成 | social-auto-upload 的 xiaohongshu_uploader |
|
||||
| **B站发布** | 📦 集成 | social-auto-upload 的 bilibili uploader (本身用的 biliup) |
|
||||
| **小红书搜索/评论** | 📦 集成 | xiaohongshu-mcp (12.4k stars) |
|
||||
| **抖音搜索/下载** | 📦 参考 | 参考 dy-cli 的设计, 自己实现 |
|
||||
| **抖音互动** | 🏗️ 自研 | 已有原子操作库, 集成到插件 |
|
||||
| **反检测** | 📦 融合 | 引入 dy-cli 的高斯抖动 + 指数退避 |
|
||||
| **联邦多机** | 🏗️ 自研 | ⭐ 核心差异化能力, 开源项目没有 |
|
||||
| **多账号矩阵管理** | 🏗️ 自研 | ⭐ 核心差异化能力, 开源项目没有 |
|
||||
|
||||
---
|
||||
|
||||
## 八、四阶段落地路线
|
||||
|
||||
### 第一阶段: 命令行统一 (已完成 ✓)
|
||||
**目标: 所有操作能通过 mc 完成, 底层不改。**
|
||||
|
||||
- [x] 清理 41 个遗留脚本 → 归档到 `scripts/archive/` + `LEGACY_INDEX.md`
|
||||
- [x] 规范 `mc collect` 命令 (包装 collect_batch_runner)
|
||||
- [x] 规范 `mc login` / `mc status` / `mc sms` / `mc proxy`
|
||||
- [x] 所有命令支持 `--json` 输出
|
||||
- [x] `mc status --all --json` 整合系统+采集+账号列表
|
||||
- [x] 平台插件路由: `mc douyin|xiaohongshu [action]`
|
||||
- [x] `mc remote` 远程多机: list/ping/status/exec (HTTP + SSH 双通道)
|
||||
- [x] `mc task` 智能任务: comment/search/collect/reply
|
||||
- [x] `mc record` 原子操作录制: start/analyze/export/list/delete
|
||||
- [x] `mc op` 原子操作注册/删除/列表
|
||||
- [x] `mc schedule` 定时任务: list/add/remove/start/history
|
||||
|
||||
### 第二阶段: 平台插件化 (已完成 ✓)
|
||||
**目标: 插件架子搭好, 扩展零成本。**
|
||||
|
||||
- [x] 建 `platforms/` 目录 + `BasePlatform` 基类 + 自动发现
|
||||
- [x] 抖音插件: 实现 login/collect/publish/nurture (plugin.py)
|
||||
- [x] 小红书插件: 实现 login/collect/publish/nurture (plugin.py)
|
||||
- [x] mc 自动发现 `platforms/` 下的插件
|
||||
- [x] 录制系统整合: `mc record` 通用 + 平台专属
|
||||
- [x] 各插件附带 SKILL.md (AI Agent 调用说明)
|
||||
|
||||
### 第三阶段: 接入开源生态 (大部分完成)
|
||||
**目标: 白嫖开源项目的能力。**
|
||||
|
||||
- [x] `mc douyin publish` / `mc xhs publish` → publish_video.py (Camoufox)
|
||||
- [x] 反检测: 高斯抖动 + 指数退避 + 拟人化操作 (anti_detection.py)
|
||||
- [x] social-auto-upload 已 clone (`~/workbuddy-agent-os/social-auto-upload/`)
|
||||
- [ ] `mc douyin publish --sau` → 调 social-auto-upload 的 douyin_uploader
|
||||
- [ ] `mc xhs publish --sau` → 调 social-auto-upload 的 xiaohongshu_uploader
|
||||
- [ ] `mc bilibili publish` → 调 biliup
|
||||
- [ ] `mc xhs search` → 调 xiaohongshu-mcp
|
||||
|
||||
### 第四阶段: 联邦多机 + 持续扩展 (已完成 ✓)
|
||||
**目标: 万物皆可接, 多机协作。**
|
||||
|
||||
- [x] `mc remote exec` 远程执行 (HTTP + SSH 双通道)
|
||||
- [x] `mc remote status` 多机状态
|
||||
- [x] `mc remote list` / `mc remote ping` 机器管理
|
||||
- [x] Dashboard 合并 (统一迁移到 index.html, 301 重定向)
|
||||
- [x] 采集历史版本化 (时间戳快照 + timeline.json)
|
||||
- [x] Tailscale 已安装 (brew install tailscale)
|
||||
- [ ] `tailscale up` 配置 Tailscale 网络
|
||||
- [ ] MCP Server: 每个插件自动生成 MCP 工具
|
||||
|
||||
### 第五阶段: 模板统一 + 采集稳定化 (新增)
|
||||
**目标: 跨机模板一致, 采集结果可靠, 禁用 Chrome 引擎。**
|
||||
|
||||
- [x] 决策记录: Chrome CDP 禁用 (养号/采集只能用 Camoufox)
|
||||
- [x] 决策记录: 采集改为导航到个人中心页 (/user/self)
|
||||
- [x] 决策记录: 配置模板统一存入仓库
|
||||
- [ ] config_template/ 全面审核: accounts.yaml / ai.yaml / schedule.yaml / profiles.json / screen_layout.yaml / sms.yaml / tasks.yaml
|
||||
- [ ] 采集脚本: xiaohongshu 增加重试逻辑 (最多 3 次, 指数退避)
|
||||
- [ ] 采集脚本: 抖音改为导航到 /user/self 个人页提取准确数据
|
||||
- [ ] 展示层统一: mc account list 合并 display_name + 采集昵称/粉丝
|
||||
- [ ] Dashboard 合并: 身份账号 tab 和采集信息 tab 统一为一个数据源
|
||||
- [ ] 新机部署: install.sh 从 config_template 初始化本地配置
|
||||
|
||||
---
|
||||
|
||||
## 九、决策记录
|
||||
|
||||
| 决策 | 选项 | 选择 | 原因 |
|
||||
|------|------|:----:|------|
|
||||
| 浏览器窗口 | 显示/隐藏 | **显示** | 防封号+能看到进度+需要模拟鼠标 |
|
||||
| 首发发布平台 | 抖音/小红书 | **抖音** | 用户量大 |
|
||||
| Dashboard | 合并/保留 | **合并** | 减少混乱 |
|
||||
| 遗留脚本 | 删除/归档 | **归档** | 万一需要还能找回 |
|
||||
| 采集历史 | 快照/新覆盖 | **快照** | 看得出变化趋势 |
|
||||
| 改造范围 | 先本机/全改 | **先本机** | 跑通再同步 |
|
||||
| 仓库策略 | 同仓库/单独仓库 | **同仓库** | 矩阵系统嵌入 agent-sync 仓库内, 与 agent-os 共享工具链和同步机制; 降低管理成本, 避免双仓库冲突 |
|
||||
| 浏览器引擎 | Chrome CDP / Camoufox | **Camoufox** | Chrome CDP 经实测会触发平台反爬封号, 所有养号/采集/发布操作统一使用 Camoufox (Firefox 内核) ; **Chrome 仅限调试**, 禁止用于生产操作 |
|
||||
| 采集方式 | 个人页/首页 | **个人页** | 首页 DOM 扫描提取的粉丝数/关注数不可靠, 改为导航到 `/user/self` 个人中心页提取准确数据 |
|
||||
| 跨机模板 | 独立管理/仓库统一 | **仓库统一** | 所有配置模板 (config_template/)、蓝图 (blueprints/)、平台插件 (platforms/) 统一存放在 agent-sync 仓库, 各机器 git pull 同步, 避免机器间模板不一致导致的运行差异 |
|
||||
|
||||
---
|
||||
|
||||
## 十、风险管理
|
||||
|
||||
| 风险 | 概率 | 影响 | 应对 |
|
||||
|:----|:----:|:----:|------|
|
||||
| 开源项目停更 | 中 | 发布功能断 | 插件架构可换底层 |
|
||||
| 平台反爬升级 | 高 | 采集/发布失效 | 反检测独立层, 单独升级 |
|
||||
| 多机 SSH 配置复杂 | 低 | 远程执行用不了 | HTTP API 兜底, 不强制 SSH |
|
||||
| 录制回放兼容性 | 中 | 跨版本录制包失效 | 录制包带版本号, 向前兼容 |
|
||||
| Dashboard 合并工作量 | 中 | 阶段投入多 | 最后阶段再做, 先用两个 |
|
||||
| Chrome CDP 封号 | 已发生 | 账号被封 | **全面禁止 Chrome CDP** 用于生产操作, 所有养号/采集/发布统一使用 Camoufox (Firefox) ; Chrome 仅限开发调试 |
|
||||
| 跨机模板不一致 | 中 | 行为差异/配置错误 | 模板统一存入 agent-sync 仓库, 新机 deploy 从模板初始化, install.sh 自动复制 |
|
||||
@@ -0,0 +1,237 @@
|
||||
# Matrix 养号系统 — 全面测试报告
|
||||
|
||||
> **生成时间**:2026-05-01 16:30
|
||||
> **测试范围**:环境 → Chrome 方案(2账号)→ Camoufox 方案 → 蓝图执行 → 数据库
|
||||
> **版本**:v2.0.0
|
||||
> **最后修复**:`cdp_connector.py` 添加 `os='windows'` 参数固定 Camoufox 操作系统指纹
|
||||
|
||||
---
|
||||
|
||||
## 总览
|
||||
|
||||
| 账号 | 浏览器方案 | 启动 | 登录 | 蓝图 | 持久化 | 自动可控 |
|
||||
|------|-----------|------|------|------|--------|---------|
|
||||
| **douyin_01** | Chrome CDP | ✅ | ✅ | ✅ 3/3 | ✅ | ✅ |
|
||||
| **douyin_02** | Chrome CDP | ✅ | ✅ | ✅ 3/3 | ✅ | ✅ |
|
||||
| **douyin_camo01** | Camoufox + Cookie注入 | ✅ | ✅ | ✅ 3/3 | ✅ (Cookie文件) | ✅ |
|
||||
| douyin_camo02 | Camoufox + Cookie注入 | — | — | — | — | 需同流程测试 |
|
||||
| xhs_01 | — | — | — | — | — | 已禁用 |
|
||||
| zhihu_01 | — | — | — | — | — | 已禁用 |
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: 环境预检 ✅ 18/18 全部通过
|
||||
|
||||
| # | 检查项 | 结果 | 详情 |
|
||||
|---|--------|------|------|
|
||||
| 1 | Python 3.13.12 | ✅ | venv 正常 |
|
||||
| 2 | patchright | ✅ | 可 import |
|
||||
| 3 | camoufox 包 | ✅ | 可 import |
|
||||
| 4 | PyYAML | ✅ | 配置解析正常 |
|
||||
| 5 | Chrome 147.0.7727.138 | ✅ | 可执行文件正常 |
|
||||
| 6 | Camoufox 二进制 | ✅ | 54416 bytes |
|
||||
| 7 | accounts.yaml | ✅ | 6个账号,语法正确 |
|
||||
| 8 | local.yaml | ✅ | 指向正确路径 |
|
||||
| 9 | local_paths.py | ✅ | 路径模块正常 |
|
||||
| 10 | matrix.db (90KB) | ✅ | 7张表,数据完整 |
|
||||
| 11 | 4个Profile目录 | ✅ | 全部存在 |
|
||||
| 12 | 6个蓝图文件 | ✅ | 全部存在 |
|
||||
| 13 | 8个核心脚本 | ✅ | 全部存在 |
|
||||
| 14 | task_blueprints表 | ✅ | 4条注册记录 |
|
||||
| 15 | executions表 | ✅ | 9条执行历史 |
|
||||
| 16 | operation_logs表 | ✅ | 64条操作记录 |
|
||||
| 17 | ui_changes表 | ✅ | 18条选择器快照 |
|
||||
| 18 | accounts表 | ✅ | 6条账号记录 |
|
||||
|
||||
---
|
||||
|
||||
## Phase 2a: Chrome douyin_01(主号) ✅ 全部通过
|
||||
|
||||
### 测试流程与结果
|
||||
|
||||
| # | 步骤 | 结果 | 耗时 | 说明 |
|
||||
|---|------|------|------|------|
|
||||
| 1 | 启动 Chrome (port 9222, profile: account_01) | ✅ | — | CDP 就绪 |
|
||||
| 2 | 注入浏览器指纹 (fp_iphone14pro) | ✅ | — | 视口/时区/语言/WebGL |
|
||||
| 3 | 登录验证 (Cookie检测) | ✅ | — | sessionid ✅, 57 Cookie |
|
||||
| 4 | 导出 Cookie | ✅ | — | → douyin_01_cookies.json (57个) |
|
||||
| 5 | DB状态更新 | ✅ | — | cookie_expired → active |
|
||||
| 6 | 蓝图测试: goto_home | ✅ | 6.5s | 正常加载首页 |
|
||||
| 7 | 蓝图测试: wait_watch (8s) | ✅ | 8.0s | — |
|
||||
| 8 | 蓝图测试: like (prob=0.4) | ✅ | 1.2s | 点赞成功,probability 参数正常 |
|
||||
| 9 | **关闭浏览器** | ✅ | — | osascript 优雅退出 |
|
||||
| 10 | **重启 Chrome** | ✅ | — | 重新启动 |
|
||||
| 11 | **重启后登录验证** | ✅ | — | sessionid ✅, **60 Cookie** 🔥 |
|
||||
|
||||
### 结论
|
||||
|
||||
**✅ Chrome Profile 持久化完全正常。** 关闭浏览器 → 重新启动后,所有登录 Cookie 均保留(57→60个,sessionid 有效)。可以安全地每天关闭/启动浏览器而不丢失登录态。
|
||||
|
||||
---
|
||||
|
||||
## Phase 2b: Chrome douyin_02(副号) ✅ 全部通过
|
||||
|
||||
### 测试流程与结果
|
||||
|
||||
| # | 步骤 | 结果 | 耗时 | 说明 |
|
||||
|---|------|------|------|------|
|
||||
| 1 | 启动 Chrome (port 9223, profile: douyin_02) | ✅ | — | CDP 就绪 |
|
||||
| 2 | 注入浏览器指纹 (fp_iphone15pro) | ✅ | — | — |
|
||||
| 3 | 登录验证 (Cookie检测) | ✅ | — | sessionid ✅, 57 Cookie |
|
||||
| 4 | 导出 Cookie | ✅ | — | → douyin_02_cookies.json (58个) |
|
||||
| 5 | DB状态更新 | ✅ | — | needs_login → active |
|
||||
| 6 | 蓝图测试: goto_home | ✅ | 5.9s | 正常 |
|
||||
| 7 | 蓝图测试: wait_watch (5s) | ✅ | 5.0s | — |
|
||||
| 8 | 蓝图测试: next_video | ✅ | 3.2s | 翻页正常 |
|
||||
| 9 | **关闭并重启** | ✅ | — | switch_account.py 自动关闭+重启 |
|
||||
| 10 | **重启后登录验证** | ✅ | — | sessionid ✅, **60 Cookie** 🔥 |
|
||||
|
||||
### 结论
|
||||
|
||||
**✅ 与 douyin_01 结论完全一致:持久化正常。**
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Camoufox douyin_camo01 ✅ 全部通过(正确方式)
|
||||
|
||||
### ⚠️ 重要说明
|
||||
|
||||
之前测试使用 `camoufox_manager.py --launch` 和 `camoufox_server.py --launch` 均失败。
|
||||
**Camoufox 的正确使用方式是 `CDPConnector(browser_type="camoufox")` 原生 API + Cookie 注入。**
|
||||
|
||||
工作流:
|
||||
```
|
||||
CDPConnector(browser_type="camoufox") # AsyncCamoufox 原生 API 启动
|
||||
↓
|
||||
Cookie 注入 ← 从 Chrome 导出的 cookies/douyin_01_cookies.json
|
||||
↓
|
||||
conn.page.goto("https://www.douyin.com/") # 登录态自动生效
|
||||
↓
|
||||
DouyinOps(page) → 蓝图执行
|
||||
```
|
||||
|
||||
**Camoufox 不依赖 CDP 端口,不依赖浏览器 Profile 持久化。** 登录态通过 Cookie 文件注入实现,
|
||||
只要 Chrome 导出的 Cookie 文件有效,每次都可以注入并登录。
|
||||
|
||||
### 测试流程与结果
|
||||
|
||||
| # | 步骤 | 结果 | 耗时 | 说明 |
|
||||
|---|------|------|------|------|
|
||||
| 1 | CDPConnector(browser_type="camoufox") | ✅ | — | AsyncCamoufox 原生 API 启动 |
|
||||
| 2 | Cookie 注入 (从 douyin_01_cookies.json) | ✅ | — | 56 个 douyin Cookie |
|
||||
| 3 | 导航 douyin.com | ✅ | — | 登录态自动生效 |
|
||||
| 4 | 登录验证 (Cookie检测) | ✅ | — | sessionid ✅, 57 Cookie |
|
||||
| 5 | 蓝图: goto_home | ✅ | — | — |
|
||||
| 6 | 蓝图: wait_watch (5s) | ✅ | — | — |
|
||||
| 7 | 蓝图: like (probability=0.5) | ✅ | — | 点赞正常 |
|
||||
| **重测验证** | 关闭→重新启动→再次注入 | ✅ | — | **两轮完全一致,流程可复现** |
|
||||
|
||||
### 结论
|
||||
|
||||
**✅ Camoufox + Cookie 注入方案完全可用。** 流程可复现,两次测试结果完全一致(3/3 通过)。
|
||||
|
||||
### 与 Chrome 方案的区别
|
||||
|
||||
| 维度 | Chrome CDP | Camoufox + Cookie注入 |
|
||||
|------|-----------|----------------------|
|
||||
| 启动方式 | 手动启动 Chrome (switch_account.py) | CDPConnector 自动启动 |
|
||||
| 登录态 | Chrome Profile 持久化 | 从导出 Cookie 文件注入 |
|
||||
| 浏览器 Profile | 持久化目录 (profiles/account_01) | 临时目录(每次重新注入 Cookie) |
|
||||
| 反检测能力 | 指纹注入 + CDP | Camoufox 内置反检测(os=windows 固定) |
|
||||
| 浏览器内核 | Chromium | Firefox 135 |
|
||||
|
||||
### 🔧 修复记录
|
||||
|
||||
| 问题 | 修复 | 文件 |
|
||||
|------|------|------|
|
||||
| Camoufox 登录后手机提示 macOS | 添加 `os='windows'` 固定 Windows 指纹 | `cdp_connector.py:73` |
|
||||
| Camoufox 随机显示 macOS/Windows | 默认从 `[windows,macos,linux]` 随机,改为固定值 | `cdp_connector.py:76` |
|
||||
| 用户确认 | 扫码登录时手机显示 "登录 Windows" ✅ | 2026-05-01 16:25 实测 |
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: 蓝图执行 ✅ Chrome 方案通过
|
||||
|
||||
| 操作 | douyin_01 | douyin_02 | 说明 |
|
||||
|------|-----------|-----------|------|
|
||||
| goto_home | ✅ 6.5s | ✅ 5.9s | 首页加载正常 |
|
||||
| wait_watch | ✅ | ✅ | 等待正常 |
|
||||
| like (probability=0.4) | ✅ 1.2s | — | 点赞按钮可正常工作 |
|
||||
| next_video | — | ✅ 3.2s | 翻页正常 |
|
||||
|
||||
### 已知 Blueprint 文件状态
|
||||
|
||||
| 蓝图文件 | DB 注册 | 状态 | 说明 |
|
||||
|---------|---------|------|------|
|
||||
| `douyin_browse_v2.json` | ✅ | active | 11步,首页浏览+点赞+收藏 |
|
||||
| `douyin_search_browse.json` | ✅ | active | 7步,搜索→浏览→互动 |
|
||||
| `douyin_comment_interact.json` | ✅ | active | 8步,评论互动 |
|
||||
| `douyin_browse.json` | ✅ | deprecated | 被 v2 替代 |
|
||||
| `douyin_browse_v3.json` | ✅ | active | 12步,带验证锚点 |
|
||||
| `douyin_nurture_v1.json` | ✅ | active | 8步,手机模式养号 |
|
||||
|
||||
---
|
||||
|
||||
## 发现的问题总结
|
||||
|
||||
### 🔴 已修复问题(全部已完成)
|
||||
|
||||
| 优先级 | 问题 | 修复方式 | 涉及文件 |
|
||||
|--------|------|---------|---------|
|
||||
| **P0** | `switch_account.py` DOM 登录检测在桌面端误报"未登录" | 改用 `auth_manager` 模块的 Cookie 检测(sessionid 主方案 + DOM 备选),不再只依赖 `[data-e2e="user-avatar"]` | `auth_manager.py`(新建)、`switch_account.py:396-406`、`cdp_connector.py:290-304` |
|
||||
| **P1** | Camoufox 操作系统显示 macOS(应显示 Windows) | 添加 `os='windows'` 固定 Windows 指纹 | `cdp_connector.py:73` |
|
||||
| **P1** | Camoufox 中文乱码 | 添加 `fonts=['STHeiti','Heiti SC','PingFang SC','Noto Sans CJK SC']` 和 `humanize=1.5` | `cdp_connector.py:76-80` |
|
||||
| **P2** | `douyin_browse_v3.json` 和 `douyin_nurture_v1.json` 未注册到 DB | ✅ 已注册 active | 2026-05-01 |
|
||||
| **P3** | 冗余 profile 目录 `profiles/douyin_01/` | ✅ 已删除 (11MB) | 2026-05-01 |
|
||||
|
||||
### ❌ 已明确否定的功能/方式
|
||||
|
||||
| 功能/方式 | 结论 | 理由 |
|
||||
|-----------|------|------|
|
||||
| `camoufox_manager.py --launch` | ❌ 错误入口 | 缺少 persistent_context + 上下文管理问题,不应使用 |
|
||||
| `camoufox_server.py --launch` | ❌ 错误入口 | 实际浏览器使用临时 Profile,不应直接使用 |
|
||||
| DOM 单一检测(桌面端) | ❌ 不可靠 | `mobile=False` 时抖音不渲染头像元素,必须结合 Cookie 检测 |
|
||||
| Cookie 注入切换(Chrome 方案B) | ⏸️ 未完全验证 | 依赖 Cookie 文件有效性 |
|
||||
|
||||
### ✅ 已验证通过的功能
|
||||
|
||||
| 功能 | 结论 | 验证方式 |
|
||||
|------|------|---------|
|
||||
| Chrome Profile 切换(方案A) | ✅ | 双账号测试通过 |
|
||||
| Chrome 指纹注入 | ✅ | 视口/时区/语言/WebGL/App跳转拦截 |
|
||||
| Chrome 登录持久化 | ✅ | 关闭→重启后 Cookie 保留 |
|
||||
| Chrome Cookie 导出 + 自动保存 | ✅ | switch_account.py 切换后自动导出 |
|
||||
| Chrome 蓝图执行 | ✅ | goto_home/wait_watch/like/next_video |
|
||||
| Chrome like() probability 参数 | ✅ | 已修复,正常工作 |
|
||||
| **Camoufox 原生 API 启动** | ✅ | CDPConnector(browser_type="camoufox") |
|
||||
| **Camoufox Cookie 注入** | ✅ | Cookie 文件→浏览器注入有效 |
|
||||
| **Camoufox 蓝图执行** | ✅ | goto_home/wait_watch/like 全部通过 |
|
||||
| **Camoufox 流程可复现** | ✅ | 多次测试结果一致(Cookie 注入方式) |
|
||||
| **auth_manager 原子化登录** | ✅ | check_login_by_cookie, get_login_status, export_cookies, inject_cookies, wait_for_login |
|
||||
| **Cookie + DOM 多维检测** | ✅ | 主方案 Cookie,备选 DOM,不再误报 |
|
||||
| DB 状态管理 | ✅ | 读写正常 |
|
||||
| 账号配置解析 | ✅ | accounts.yaml / local.yaml 正常 |
|
||||
|
||||
---
|
||||
|
||||
## 当前账号状态(测试后基准线)
|
||||
|
||||
| 账号 | DB 状态 | 浏览器 | 上次活跃 |
|
||||
|------|---------|--------|---------|
|
||||
| **douyin_01** | **active** | ✅ 运行中 (9222) | 2026-05-01 16:08 |
|
||||
| **douyin_02** | **active** | ✅ 运行中 (9223) | 2026-05-01 16:08 |
|
||||
| douyin_camo01 | active (缓存) | ⏹ 已停止 | — |
|
||||
| douyin_camo02 | active (缓存) | ⏹ 未运行 | — |
|
||||
| xhs_01 / zhihu_01 | inactive | ⏹ | — |
|
||||
|
||||
> 两个 Chrome 浏览器窗口当前均保持在前台打开状态,登录有效。
|
||||
|
||||
---
|
||||
|
||||
## 最终结论
|
||||
|
||||
**Chrome CDP 方案**:✅ **生产就绪**。双账号 Profile 切换、指纹注入、登录持久化、蓝图执行全部正常。
|
||||
**Camoufox + Cookie 注入方案**:✅ **生产就绪**。通过 `CDPConnector(browser_type="camoufox")` 原生 API + Cookie 注入。已修复 Windows 指纹和中文乱码。
|
||||
**正确入口**:使用 `yanghao_runner.py` 或 `cdp_connector.CDPConnector`(`camoufox_manager.py` / `camoufox_server.py` 非标准入口)。
|
||||
**登录检测**:已原子化为 `auth_manager.py` 模块,Cookie 主方案 + DOM 备选,不再误报。
|
||||
**文档状态**:所有修复、测试结果、原子化模块均已记录在本报告中。
|
||||
@@ -0,0 +1,894 @@
|
||||
# 全自动矩阵养号运维系统 - 完整落地实施手册
|
||||
|
||||
**版本**:v2.0
|
||||
**适用平台**:抖音、小红书、快手、知乎
|
||||
**运行环境**:macOS (Apple Silicon), Colima, Docker
|
||||
**最后更新**:2026-04-27
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [项目概述与目标](#一项目概述与目标)
|
||||
2. [第一部分:隐身登录系统](#二第一部分隐身登录系统)
|
||||
3. [第二部分:智能养号自动化系统](#三第二部分智能养号自动化系统)
|
||||
4. [第三部分:系统完整工作流](#四第三部分系统完整工作流)
|
||||
5. [第四部分:落地实施具体步骤](#五第四部分落地实施具体步骤)
|
||||
6. [第五部分:关键技术栈](#六第五部分关键技术栈)
|
||||
7. [第六部分:成本估算](#七第六部分成本估算)
|
||||
8. [附录:常见问题与踩坑记录](#八附录常见问题与踩坑记录)
|
||||
|
||||
---
|
||||
|
||||
## 一、项目概述与目标
|
||||
|
||||
### 1.1 项目定义
|
||||
|
||||
在 Mac (Apple Silicon) 上构建一套覆盖**抖音、小红书、快手、知乎**的全自动矩阵养号系统。实现从安全登录、拟人化浏览、智能互动到回复评论的全链路自动化。
|
||||
|
||||
### 1.2 核心设计原则
|
||||
|
||||
- **高隐蔽性**:从浏览器指纹、网络出口、行为特征三个维度做到不被平台风控识别
|
||||
- **低成本启动**:核心依赖开源工具,初期月成本控制在 ¥135-600
|
||||
- **自我进化**:采用"人工示教 → AI学习 → 自动回放"模式,适应平台UI变化
|
||||
- **人机协同**:登录/验证码环节人工介入,重复性操作用自动化完成
|
||||
|
||||
### 1.3 前置条件
|
||||
|
||||
- 一台专用 Mac (Apple Silicon),仅用于养号
|
||||
- 浏览器前台运行,不使用无头模式 (headless: false)
|
||||
- 登录、验证码环节人工配合
|
||||
- 5-6 个初始账号,使用 2-3 套反检测框架轮换
|
||||
- 每个账号绑定独立静态住宅IP
|
||||
|
||||
---
|
||||
|
||||
## 二、第一部分:隐身登录系统
|
||||
|
||||
### 2.1 架构总览
|
||||
|
||||
```
|
||||
🧠 AI 总调度器 (OpenClaw / Python asyncio)
|
||||
│
|
||||
├── Docker 容器 1: Camoufox (Firefox) → 账号A → 独立IP_1
|
||||
├── Docker 容器 2: Camoufox (Firefox) → 账号B → 独立IP_2
|
||||
├── Docker 容器 3: Patchright (Chromium) → 账号C → 独立IP_3
|
||||
├── Docker 容器 4: Patchright (Chromium) → 账号D → 独立IP_4
|
||||
└── Docker 容器 5: Camoufox (Firefox) → 账号E → 独立IP_5
|
||||
```
|
||||
|
||||
**轮换策略**:
|
||||
- 3个账号使用 Camoufox (Firefox内核)
|
||||
- 2个账号使用 Patchright (Chromium内核)
|
||||
- 避免所有账号使用同一框架,降低群体特征关联风险
|
||||
|
||||
### 2.2 容器运行时选型:Colima
|
||||
|
||||
**为什么用 Colima 而不是 Docker Desktop**:
|
||||
- Colima 是 macOS 上最轻量的容器运行时,基于 Lima
|
||||
- 默认行为更接近原生 Linux 环境,不挂载 `/.dockerenv` 标志文件
|
||||
- 资源占用小,适合长时间运行
|
||||
- 开源免费,无 Docker Desktop 的商用限制
|
||||
|
||||
**安装命令**:
|
||||
```bash
|
||||
brew install colima docker docker-compose
|
||||
colima start --cpu 4 --memory 8 --disk 50
|
||||
```
|
||||
|
||||
**验证安装**:
|
||||
```bash
|
||||
docker ps
|
||||
# 应显示空的容器列表,无报错
|
||||
```
|
||||
|
||||
### 2.3 Docker 环境反检测技术清单
|
||||
|
||||
以下每一项都是经过验证的对抗手段,**必须全部配置**,缺一不可。
|
||||
|
||||
| 序号 | 平台检测手段 | 具体表现 | 风险等级 | 我们的对抗方法 | 具体实现 |
|
||||
|:---|:---|:---|:---|:---|:---|
|
||||
| 1 | `/.dockerenv` 文件 | 检查根目录是否存在该标志文件 | ⚠️ 高 | 删除该文件 | Dockerfile: `RUN rm -f /.dockerenv` |
|
||||
| 2 | `/proc/1/cgroup` 关键词 | 检查cgroup是否包含 "docker" 字符串 | ⚠️ 高 | 挂载伪造的cgroup文件 | `-v /host/proc/1/cgroup:/proc/1/cgroup:ro` |
|
||||
| 3 | 环境变量 `container=docker` | 检测环境变量中是否包含docker标识 | ⚠️ 中 | 清除环境变量 | Dockerfile: `ENV container=""` |
|
||||
| 4 | `/etc/machine-id` | 系统唯一标识,虚拟机/Docker有固定值 | ⚠️ 中 | 挂载宿主机真实文件 | `-v /etc/machine-id:/etc/machine-id:ro` |
|
||||
| 5 | D-Bus 服务缺失 | 真实桌面系统必有的进程间通信服务 | ⚠️ 中 | 安装并启动dbus | `RUN apt-get install -y dbus` |
|
||||
| 6 | 显卡/WebGL 指纹 | 检查是否含 "llvmpipe" 等软件渲染标识 | ⚠️ 高 | Camoufox自动伪造真实GPU信息 | 由Camoufox在编译层处理 |
|
||||
| 7 | MAC地址虚拟化 | Docker默认生成 `02:42:xx:xx:xx:xx` 段虚拟MAC | ⚠️ 中 | 挂载宿主机网卡或指定固定MAC | `--mac-address 00:1B:63:84:45:E6` |
|
||||
| 8 | CPU信息 | `/proc/cpuinfo` 显示虚拟化标识 | ⚠️ 低 | 不做特殊处理,Colima默认较干净 | - |
|
||||
| 9 | 内存/磁盘大小 | 异常小的内存或磁盘容量 | ⚠️ 低 | 分配合理资源(8G内存,50G磁盘) | colima配置参数 |
|
||||
|
||||
**Dockerfile 完整模板**:
|
||||
|
||||
```dockerfile
|
||||
# Camoufox 基础镜像
|
||||
FROM ubuntu:22.04
|
||||
|
||||
# 清除Docker标志文件
|
||||
RUN rm -f /.dockerenv
|
||||
|
||||
# 清除环境变量
|
||||
ENV container=""
|
||||
|
||||
# 安装桌面依赖
|
||||
RUN apt-get update && apt-get install -y \
|
||||
dbus \
|
||||
libgtk-3-0 \
|
||||
libnotify4 \
|
||||
libnss3 \
|
||||
libxss1 \
|
||||
libxtst6 \
|
||||
xdg-utils \
|
||||
libatspi2.0-0 \
|
||||
libdrm2 \
|
||||
libgbm1 \
|
||||
libxcb1 \
|
||||
libxkbcommon0 \
|
||||
libasound2 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 启动dbus服务
|
||||
RUN mkdir -p /var/run/dbus && dbus-daemon --system
|
||||
|
||||
# 创建非root用户(真实用户不会用root跑浏览器)
|
||||
RUN useradd -m -s /bin/bash browser
|
||||
USER browser
|
||||
WORKDIR /home/browser
|
||||
|
||||
# 安装Camoufox(具体步骤见Camoufox官方文档)
|
||||
# ...
|
||||
```
|
||||
|
||||
**docker-compose.yml 完整模板**:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
account_01:
|
||||
build:
|
||||
context: ./docker/camoufox
|
||||
dockerfile: Dockerfile
|
||||
container_name: matrix_account_01
|
||||
volumes:
|
||||
- ./profiles/account_01:/home/browser/.mozilla # Cookie持久化
|
||||
- ./scripts:/home/browser/scripts
|
||||
- /etc/machine-id:/etc/machine-id:ro # 宿主机machine-id
|
||||
environment:
|
||||
- PROXY_SERVER=socks5://your-proxy-ip-1:1080 # 独立代理IP
|
||||
- PROXY_USER=your_username
|
||||
- PROXY_PASS=your_password
|
||||
- DISPLAY=:99
|
||||
mac_address: 00:1B:63:84:45:E1 # 固定MAC
|
||||
ports:
|
||||
- "9221:9222" # CDP调试端口,每个容器映射到宿主机不同端口
|
||||
shm_size: '2gb'
|
||||
restart: unless-stopped
|
||||
|
||||
account_02:
|
||||
image: patchright-browser:latest
|
||||
container_name: matrix_account_02
|
||||
volumes:
|
||||
- ./profiles/account_02:/home/browser/.config/chromium
|
||||
- ./scripts:/home/browser/scripts
|
||||
- /etc/machine-id:/etc/machine-id:ro
|
||||
environment:
|
||||
- PROXY_SERVER=socks5://your-proxy-ip-2:1080
|
||||
- DISPLAY=:99
|
||||
mac_address: 00:1B:63:84:45:E2
|
||||
ports:
|
||||
- "9222:9222"
|
||||
shm_size: '2gb'
|
||||
restart: unless-stopped
|
||||
|
||||
# account_03, account_04, account_05 类推
|
||||
```
|
||||
|
||||
### 2.4 浏览器层反检测框架详解
|
||||
|
||||
#### 2.4.1 Camoufox (Firefox内核)
|
||||
|
||||
**为什么选择Camoufox**:
|
||||
- 在**编译阶段**修改Firefox源码,不是运行时打补丁
|
||||
- 从根源消除 `navigator.webdriver` 等自动化特征
|
||||
- WebGL/Canvas/字体指纹均做真实化随机处理
|
||||
- 对国际主流平台(TikTok, Instagram等)兼容性好
|
||||
|
||||
**Camoufox 编译级修改点**:
|
||||
|
||||
| 修改点 | 解决的问题 | 技术细节 |
|
||||
|:---|:---|:---|
|
||||
| `navigator.webdriver` | 强制返回 `false` | 在Navigator接口实现层硬编码,JS无法检测 |
|
||||
| CDP Runtime 泄漏 | 移除调试管道痕迹 | 删除 `--remote-debugging-pipe` 参数 |
|
||||
| WebGL 指纹 | 伪造真实GPU型号 | 注入Apple M系列GPU指纹 |
|
||||
| Canvas 指纹 | 每次渲染添加微噪声 | 噪声可配置,默认人类无法察觉 |
|
||||
| 字体指纹 | 模拟真实系统字体列表 | 内置macOS/Windows字体清单 |
|
||||
| 时区一致性 | IP代理对应时区自动同步 | 启动时检测IP Geo位置自动设置 |
|
||||
|
||||
**使用示例**:
|
||||
```python
|
||||
from camoufox import AsyncCamoufox
|
||||
|
||||
async with AsyncCamoufox(
|
||||
headless=False,
|
||||
proxy="socks5://ip:port",
|
||||
user_data_dir="./profiles/acc01",
|
||||
screen={"width": 390, "height": 844},
|
||||
geo={"timezone": "Asia/Shanghai"}
|
||||
) as browser:
|
||||
page = await browser.new_page()
|
||||
await page.goto("https://www.douyin.com")
|
||||
```
|
||||
|
||||
#### 2.4.2 Patchright (Chromium内核)
|
||||
|
||||
**为什么需要Patchright**:
|
||||
- 基于Chromium内核,对国内Webkit平台(抖音/小红书)兼容性更好
|
||||
- 修补CDP协议和JS运行时泄漏
|
||||
- 与Playwright API兼容,学习成本低
|
||||
|
||||
**与Camoufox配合使用**:
|
||||
- 账号A、B、E → Camoufox (Firefox)
|
||||
- 账号C、D → Patchright (Chromium)
|
||||
- **关键**:不要让所有账号使用同一浏览器内核
|
||||
|
||||
#### 2.4.3 CDP协议连接方式
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from patchright.async_api import async_playwright
|
||||
|
||||
async def connect_to_browser(cdp_port: int):
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.connect_over_cdp(
|
||||
f"http://localhost:{cdp_port}"
|
||||
)
|
||||
context = browser.contexts[0]
|
||||
page = context.pages[0] if context.pages else await context.new_page()
|
||||
return page
|
||||
```
|
||||
|
||||
### 2.5 移动端伪装与强制跳转拦截
|
||||
|
||||
#### 2.5.1 三层对抗策略
|
||||
|
||||
##### 第一层:伪装成"无App环境的普通移动浏览器"
|
||||
|
||||
| 参数 | 设置值 | 目的 |
|
||||
|:---|:---|:---|
|
||||
| User-Agent | `Mozilla/5.0 (Linux; Android 10; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36` | 伪装成Android手机Chrome |
|
||||
| UA关键注意 | **绝对不能**包含 `MicroMessenger`、`douyin`、`xiaohongshu`、`kuaishou` 等App标识 | 避免被识别为App内嵌浏览器 |
|
||||
| `navigator.standalone` | 通过CDP注入强制返回 `false` | 告诉页面"没有安装PWA" |
|
||||
| `navigator.platform` | `Linux armv8l` | 与UA保持一致性 |
|
||||
|
||||
**注意**:UA中的 `Android` 字样不能省略,部分平台对 `iPhone` UA的跳转更激进。
|
||||
|
||||
##### 第二层:CDP拦截URL Scheme跳转(最关键防线)
|
||||
|
||||
```python
|
||||
async def setup_app_jump_interception(cdp_session):
|
||||
"""拦截所有主流平台的App跳转协议"""
|
||||
blocked_schemes = [
|
||||
"xhdsdiscover://*", # 小红书
|
||||
"snssdk1128://*", # 抖音
|
||||
"snssdk1233://*", # TikTok
|
||||
"kuaishou://*", # 快手
|
||||
"zhihu://*", # 知乎
|
||||
"weixin://*", # 微信
|
||||
"alipays://*", # 支付宝
|
||||
"taobao://*", # 淘宝
|
||||
"openapp.jdmobile://*", # 京东
|
||||
"intent://*", # Android Intent
|
||||
]
|
||||
|
||||
await cdp_session.send("Fetch.enable", {
|
||||
"patterns": [
|
||||
{"urlPattern": scheme, "requestStage": "Request"}
|
||||
for scheme in blocked_schemes
|
||||
]
|
||||
})
|
||||
|
||||
def handle_interception(event):
|
||||
asyncio.ensure_future(
|
||||
cdp_session.send("Fetch.failRequest", {
|
||||
"requestId": event["requestId"],
|
||||
"errorReason": "Aborted"
|
||||
})
|
||||
)
|
||||
|
||||
cdp_session.on("Fetch.requestPaused", handle_interception)
|
||||
return cdp_session
|
||||
```
|
||||
|
||||
##### 第三层:DOM弹窗清理(兜底方案)
|
||||
|
||||
```python
|
||||
REMOVE_OVERLAY_SCRIPT = """
|
||||
() => {
|
||||
const overlay_selectors = [
|
||||
'[class*="download"]', '[class*="open-app"]', '[class*="app-guide"]',
|
||||
'[class*="launch-app"]', '[class*="open-in-app"]',
|
||||
'.open-in-app', '.app-launch-mask', '.download-tip', '.bottom-bar',
|
||||
'.download-banner', '.open-app-btn', '.app-download-tip',
|
||||
'.open-app-layer', '.download-guide-mask',
|
||||
'.open-in-app-bar', '.app-open-button',
|
||||
'#app-launch-dialog', '#open-app-modal', '#download-modal',
|
||||
];
|
||||
|
||||
let removed_count = 0;
|
||||
overlay_selectors.forEach(selector => {
|
||||
document.querySelectorAll(selector).forEach(el => {
|
||||
el.remove();
|
||||
removed_count++;
|
||||
});
|
||||
});
|
||||
|
||||
document.body.style.overflow = '';
|
||||
document.body.style.position = '';
|
||||
document.body.style.overflowY = 'auto';
|
||||
|
||||
return removed_count;
|
||||
}
|
||||
"""
|
||||
```
|
||||
|
||||
#### 2.5.2 移动端视口配置
|
||||
|
||||
```python
|
||||
MOBILE_VIEWPORT_CONFIG = {
|
||||
"width": 390,
|
||||
"height": 844,
|
||||
"deviceScaleFactor": 3,
|
||||
"isMobile": True,
|
||||
"hasTouch": True,
|
||||
"screenOrientation": "portrait"
|
||||
}
|
||||
|
||||
async def apply_mobile_viewport(cdp_session):
|
||||
await cdp_session.send("Emulation.setDeviceMetricsOverride", {
|
||||
"width": 390,
|
||||
"height": 844,
|
||||
"deviceScaleFactor": 3,
|
||||
"mobile": True,
|
||||
"screenOrientation": {"type": "portrait", "angle": 0}
|
||||
})
|
||||
await cdp_session.send("Emulation.setTouchEmulationOverride", {
|
||||
"enabled": True,
|
||||
"maxTouchPoints": 5
|
||||
})
|
||||
```
|
||||
|
||||
### 2.6 IP代理配置
|
||||
|
||||
| 代理类型 | 月成本/个 | 稳定度 | 适用场景 |
|
||||
|:---|:---|:---|:---|
|
||||
| **静态住宅IP** (推荐) | ¥25-110 | ⭐⭐⭐⭐ | 长期养号,被识别风险最低 |
|
||||
| 动态住宅IP | ¥15-50 | ⭐⭐⭐ | 批量操作,但IP变化可能触发验证 |
|
||||
| 数据中心代理 | ¥5-20 | ⭐⭐ | 初期测试,但易被风控识别 |
|
||||
|
||||
### 2.7 人工登录与Cookie持久化
|
||||
|
||||
```
|
||||
步骤1:启动容器 + 应用代理
|
||||
步骤2:浏览器弹出(前台,390x844手机比例)
|
||||
步骤3:人工输入账号密码 + 验证码 + 勾选"记住我"
|
||||
步骤4:确认登录成功 → Cookie自动写入挂载卷
|
||||
步骤5:关闭浏览器 → Cookie持久化保留
|
||||
步骤6:重启容器,验证持久化是否正常
|
||||
```
|
||||
|
||||
```python
|
||||
async def check_login_status(page, platform: str):
|
||||
"""检查账号是否仍处于登录状态"""
|
||||
login_indicators = {
|
||||
"douyin": "document.querySelector('[data-e2e=\"user-avatar\"]') !== null",
|
||||
"xiaohongshu": "document.querySelector('.user-avatar') !== null",
|
||||
"kuaishou": "document.querySelector('.user-avatar') !== null",
|
||||
"zhihu": "document.querySelector('.AppHeader-profile') !== null",
|
||||
}
|
||||
js_code = login_indicators.get(platform)
|
||||
if not js_code:
|
||||
return False
|
||||
try:
|
||||
return await page.evaluate(js_code)
|
||||
except:
|
||||
return False
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、第二部分:智能养号自动化系统
|
||||
|
||||
### 3.1 核心设计:人工示教 → 任务蓝图 → AI回放
|
||||
|
||||
**设计理念**:
|
||||
- 不编写死板的点击坐标脚本
|
||||
- 人工操作一次,系统自动学习
|
||||
- 生成结构化"任务蓝图",AI据此回放
|
||||
- 平台UI变化时自我修复,失败时降级处理
|
||||
|
||||
### 3.2 原子操作定义
|
||||
|
||||
| 原子操作ID | 操作名称 | 描述 | 完成确认 |
|
||||
|:---|:---|:---|:---|
|
||||
| `AO_NAV` | 页面导航 | 跳转到指定URL | 目标页面关键元素出现 |
|
||||
| `AO_CLICK` | 点击元素 | 点击指定按钮/链接 | 期望的页面变化发生 |
|
||||
| `AO_INPUT` | 输入文本 | 在输入框输入内容 | 输入框内容与预期一致 |
|
||||
| `AO_SCROLL` | 滑动/滚动 | 上下滑动页面 | 滚动位置发生变化 |
|
||||
| `AO_SWIPE` | 触摸滑动 | 模拟手指滑动(视频切换) | 内容切换到下一条 |
|
||||
| `AO_WAIT` | 等待 | 停留浏览一段时间 | 等待时间达标 |
|
||||
| `AO_SEARCH` | 搜索 | 搜索关键词 | 搜索结果加载 |
|
||||
| `AO_LIKE` | 点赞 | 点亮爱心/拇指 | 按钮状态变为"已赞" |
|
||||
| `AO_COLLECT` | 收藏 | 收藏内容 | 按钮状态变为"已收藏" |
|
||||
| `AO_COMMENT` | 评论 | 发表评论 | 评论出现在评论区 |
|
||||
| `AO_REPLY` | 回复评论 | 回复他人评论 | 回复内容发送成功 |
|
||||
| `AO_FOLLOW` | 关注 | 关注用户 | 按钮变为"已关注" |
|
||||
|
||||
### 3.3 养号任务清单
|
||||
|
||||
#### 抖音任务
|
||||
|
||||
| 任务ID | 任务名称 | 涉及原子操作 | 预估耗时 |
|
||||
|:---|:---|:---|:---|
|
||||
| `DY_001` | 浏览推荐页 | AO_SWIPE, AO_WAIT | 5-15分钟 |
|
||||
| `DY_002` | 搜索并浏览 | AO_SEARCH, AO_CLICK, AO_WAIT | 3-8分钟 |
|
||||
| `DY_003` | 点赞视频 | AO_LIKE | 30秒 |
|
||||
| `DY_004` | 评论视频 | AO_COMMENT, AO_INPUT | 1-2分钟 |
|
||||
| `DY_005` | 回复评论 | AO_NAV, AO_CLICK, AO_REPLY | 2分钟 |
|
||||
| `DY_006` | 关注用户 | AO_FOLLOW | 30秒 |
|
||||
| `DY_007` | 收藏视频 | AO_COLLECT | 30秒 |
|
||||
| `DY_008` | 浏览同城 | AO_NAV, AO_SWIPE, AO_WAIT | 5分钟 |
|
||||
| `DY_009` | 查看主页 | AO_NAV, AO_SCROLL | 2分钟 |
|
||||
|
||||
#### 小红书任务
|
||||
|
||||
| 任务ID | 任务名称 | 涉及原子操作 | 预估耗时 |
|
||||
|:---|:---|:---|:---|
|
||||
| `XHS_001` | 浏览首页推荐 | AO_SCROLL, AO_CLICK, AO_WAIT | 5-15分钟 |
|
||||
| `XHS_002` | 搜索浏览 | AO_SEARCH, AO_SCROLL, AO_CLICK | 5分钟 |
|
||||
| `XHS_003` | 点赞笔记 | AO_LIKE | 30秒 |
|
||||
| `XHS_004` | 收藏笔记 | AO_COLLECT | 30秒 |
|
||||
| `XHS_005` | 评论笔记 | AO_COMMENT, AO_INPUT | 1-2分钟 |
|
||||
| `XHS_006` | 关注博主 | AO_FOLLOW | 30秒 |
|
||||
|
||||
#### 快手任务
|
||||
|
||||
| 任务ID | 任务名称 | 涉及原子操作 |
|
||||
|:---|:---|:---|
|
||||
| `KS_001` | 刷推荐视频 | AO_SWIPE, AO_WAIT |
|
||||
| `KS_002` | 点赞视频 | AO_LIKE |
|
||||
| `KS_003` | 评论视频 | AO_COMMENT, AO_INPUT |
|
||||
|
||||
#### 知乎任务
|
||||
|
||||
| 任务ID | 任务名称 | 涉及原子操作 |
|
||||
|:---|:---|:---|
|
||||
| `ZH_001` | 浏览推荐 | AO_SCROLL, AO_CLICK, AO_WAIT |
|
||||
| `ZH_002` | 赞同回答 | AO_LIKE |
|
||||
| `ZH_003` | 评论问题 | AO_COMMENT, AO_INPUT |
|
||||
| `ZH_004` | 关注话题 | AO_FOLLOW |
|
||||
|
||||
### 3.4 任务蓝图完整数据结构
|
||||
|
||||
```json
|
||||
{
|
||||
"task_id": "DY_005",
|
||||
"task_name": "抖音_回复评论",
|
||||
"platform": "douyin",
|
||||
"version": "1.0.0",
|
||||
"created_at": "2026-04-27T10:00:00Z",
|
||||
"created_by": "human_demo",
|
||||
"description": "从抖音个人主页进入消息页,找到评论Tab,回复第一条未回复的评论",
|
||||
"estimated_duration_ms": 45000,
|
||||
|
||||
"execution_environment": {
|
||||
"viewport": {"width": 390, "height": 844},
|
||||
"user_agent": "Mozilla/5.0 (Linux; Android 10; Pixel 5)...",
|
||||
"touch_enabled": true,
|
||||
"blocked_schemes": ["xhdsdiscover://*", "snssdk1128://*"],
|
||||
"overlay_removal": true
|
||||
},
|
||||
|
||||
"steps": [
|
||||
{
|
||||
"step_id": 1,
|
||||
"step_name": "点击消息Tab进入通知页",
|
||||
"atomic_operation": "AO_CLICK",
|
||||
|
||||
"locator": {
|
||||
"primary": "[data-e2e='message-tab']",
|
||||
"fallback_xpath": "//div[contains(@class,'tab')]//span[contains(text(),'消息')]",
|
||||
"fallback_visual": {
|
||||
"text": "消息",
|
||||
"description": "底部导航栏的消息图标按钮"
|
||||
}
|
||||
},
|
||||
|
||||
"behavior": {
|
||||
"click_mode": "touch",
|
||||
"pre_delay_ms": [500, 1200],
|
||||
"touch_duration_ms": [50, 100],
|
||||
"post_delay_ms": [1500, 2500]
|
||||
},
|
||||
|
||||
"post_checks": [
|
||||
{"type": "url_changed", "expected_pattern": "/notice/*"},
|
||||
{"type": "element_appeared", "selector": "[data-e2e='comment-tab']"}
|
||||
],
|
||||
|
||||
"on_failure": {"max_retries": 2, "fallback_action": "retry_with_visual"}
|
||||
}
|
||||
],
|
||||
|
||||
"completion_verification": {
|
||||
"success_indicators": [
|
||||
{"type": "element_appeared", "selector": "[data-e2e='reply-sent-success']"}
|
||||
],
|
||||
"timeout_ms": 60000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5 任务蓝图数据库设计
|
||||
|
||||
```sql
|
||||
-- 任务蓝图主表
|
||||
CREATE TABLE task_blueprints (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_id TEXT NOT NULL,
|
||||
task_name TEXT NOT NULL,
|
||||
platform TEXT NOT NULL,
|
||||
version TEXT NOT NULL,
|
||||
status TEXT DEFAULT 'active', -- 'active', 'deprecated', 'broken'
|
||||
browser_framework TEXT,
|
||||
viewport_config TEXT,
|
||||
entry_conditions TEXT,
|
||||
steps_json TEXT,
|
||||
completion_check_json TEXT,
|
||||
created_at TEXT DEFAULT (datetime('now')),
|
||||
updated_at TEXT DEFAULT (datetime('now')),
|
||||
deprecation_reason TEXT,
|
||||
replaced_by_version TEXT
|
||||
);
|
||||
|
||||
-- 任务执行记录表
|
||||
CREATE TABLE task_executions (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_id TEXT NOT NULL,
|
||||
blueprint_version TEXT NOT NULL,
|
||||
account_id TEXT NOT NULL,
|
||||
browser_framework TEXT,
|
||||
container_id TEXT,
|
||||
proxy_ip TEXT,
|
||||
status TEXT, -- 'running', 'success', 'failed', 'timeout'
|
||||
started_at TEXT,
|
||||
completed_at TEXT,
|
||||
duration_ms INTEGER,
|
||||
error_message TEXT,
|
||||
screenshots TEXT,
|
||||
logs TEXT
|
||||
);
|
||||
|
||||
-- 原子操作执行记录
|
||||
CREATE TABLE operation_logs (
|
||||
id TEXT PRIMARY KEY,
|
||||
execution_id TEXT NOT NULL,
|
||||
step_id INTEGER,
|
||||
atomic_operation TEXT,
|
||||
pre_checks_passed BOOLEAN,
|
||||
execution_success BOOLEAN,
|
||||
post_checks_passed BOOLEAN,
|
||||
locator_used TEXT,
|
||||
duration_ms INTEGER,
|
||||
error_detail TEXT,
|
||||
screenshot_path TEXT,
|
||||
created_at TEXT DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
-- UI变更记录
|
||||
CREATE TABLE ui_changes (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_id TEXT,
|
||||
platform TEXT,
|
||||
detected_at TEXT,
|
||||
element_changed TEXT,
|
||||
old_selector TEXT,
|
||||
new_selector TEXT,
|
||||
affected_blueprint_versions TEXT,
|
||||
resolution TEXT,
|
||||
notes TEXT
|
||||
);
|
||||
```
|
||||
|
||||
### 3.6 三级元素定位策略
|
||||
|
||||
```python
|
||||
class SmartLocator:
|
||||
"""
|
||||
智能元素定位器
|
||||
Level 1: 录制的CSS选择器(90%场景)
|
||||
Level 2: 备选XPath(8%场景)
|
||||
Level 3: 本地MLX视觉定位(2%场景,兜底)
|
||||
"""
|
||||
async def locate_element(self, page, step: dict):
|
||||
# Level 1: 首选CSS选择器
|
||||
primary = step["locator"]["primary"]
|
||||
try:
|
||||
element = await page.wait_for_selector(primary, timeout=3000)
|
||||
if element:
|
||||
return {"level": 1, "element": element}
|
||||
except:
|
||||
pass
|
||||
|
||||
# Level 2: 备选XPath
|
||||
fallback_xpath = step["locator"].get("fallback_xpath")
|
||||
if fallback_xpath:
|
||||
try:
|
||||
element = await page.wait_for_selector(f"xpath={fallback_xpath}", timeout=3000)
|
||||
if element:
|
||||
return {"level": 2, "element": element}
|
||||
except:
|
||||
pass
|
||||
|
||||
# Level 3: MLX视觉定位
|
||||
return await self._visual_locate(page, step)
|
||||
```
|
||||
|
||||
### 3.7 本地MLX多模态后备
|
||||
|
||||
```bash
|
||||
# 安装MLX和视觉模型
|
||||
pip install mlx mlx-vlm
|
||||
|
||||
# 下载量化版视觉模型(Qwen2-VL-7B-4bit,内存占用<5GB)
|
||||
python -c "
|
||||
from mlx_vlm import load
|
||||
model, processor = load('mlx-community/Qwen2-VL-7B-4bit')
|
||||
"
|
||||
```
|
||||
|
||||
```python
|
||||
async def mlx_vision_locate(image_bytes: bytes, target_description: str, target_text: str = ""):
|
||||
"""使用本地MLX模型在截图中定位目标元素"""
|
||||
model, processor = get_mlx_model()
|
||||
image = Image.open(io.BytesIO(image_bytes))
|
||||
|
||||
prompt = f"""在这张手机截图中,找到"{target_description}"的位置。
|
||||
该元素的文字可能是"{target_text}"。
|
||||
请返回该元素的外接矩形坐标,格式为:x1,y1,x2,y2
|
||||
只返回坐标数字,不要包含其他内容。"""
|
||||
|
||||
response = generate(model, processor, image=image, prompt=prompt, max_tokens=50)
|
||||
|
||||
try:
|
||||
parts = response.strip().split(",")
|
||||
if len(parts) == 4:
|
||||
x1, y1, x2, y2 = map(int, parts)
|
||||
return {"x": (x1+x2)//2, "y": (y1+y2)//2, "x1":x1, "y1":y1, "x2":x2, "y2":y2}
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
```
|
||||
|
||||
**MLX方案的优势**:零网络延迟(200-500ms)、零API费用、数据不离本机。
|
||||
|
||||
### 3.8 养号行为拟人化参数
|
||||
|
||||
```python
|
||||
class BehaviorProfile:
|
||||
def __init__(self, account_id: str, persona: str = "normal"):
|
||||
self.params = {
|
||||
"action_delay": [200, 5000], # 动作间隔(毫秒)
|
||||
"view_duration": [5000, 60000], # 浏览停留(毫秒)
|
||||
"move_duration": [100, 800], # 鼠标/触摸移动时间
|
||||
"typing_speed": [50, 200], # 每字符毫秒
|
||||
"typo_probability": [0, 0.05], # 打字错误概率
|
||||
"active_hours": [8, 23], # 每日活跃时段
|
||||
"max_likes_per_hour": 20,
|
||||
"max_comments_per_hour": 5,
|
||||
"max_follows_per_hour": 10,
|
||||
"max_total_actions_per_day": 200,
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、第三部分:系统完整工作流
|
||||
|
||||
### 4.1 日常运行全景
|
||||
|
||||
```
|
||||
每日启动(定时/手动)
|
||||
│
|
||||
调度器加载排班表,确定今日任务序列
|
||||
│
|
||||
├── 启动容器1 + 加载代理
|
||||
├── 启动容器2 + 加载代理
|
||||
└── 启动容器3 + 加载代理
|
||||
│
|
||||
检查Cookie登录状态
|
||||
有效 → 直接执行 | 过期 → 通知人工
|
||||
│
|
||||
各账号执行任务序列(浏览/点赞/评论/关注)
|
||||
│
|
||||
每个步骤:前置校验 → 执行 → 后置校验
|
||||
成功 → 记录日志 → 下一步
|
||||
失败 → 降级定位 → 重试 → 人工介入
|
||||
│
|
||||
冷却10-30分钟
|
||||
│
|
||||
释放容器,生成今日执行报告
|
||||
```
|
||||
|
||||
### 4.2 账号熔断机制
|
||||
|
||||
```python
|
||||
class CircuitBreaker:
|
||||
def __init__(self, account_id: str):
|
||||
self.failure_count = 0
|
||||
self.max_failures = 3
|
||||
self.cooldown_minutes = 30
|
||||
self.is_open = False
|
||||
|
||||
async def record_failure(self):
|
||||
self.failure_count += 1
|
||||
if self.failure_count >= self.max_failures:
|
||||
self.is_open = True
|
||||
await notify_admin(f"账号 {self.account_id} 连续失败已熔断")
|
||||
|
||||
def can_execute(self) -> bool:
|
||||
if not self.is_open:
|
||||
return True
|
||||
if time.time() - self.opened_at > self.cooldown_minutes * 60:
|
||||
self.is_open = False
|
||||
self.failure_count = 0
|
||||
return True
|
||||
return False
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、第四部分:落地实施具体步骤
|
||||
|
||||
### 阶段0:环境准备(预计1-2天)
|
||||
|
||||
```bash
|
||||
brew install colima docker docker-compose
|
||||
colima start --cpu 4 --memory 8 --disk 50
|
||||
docker ps # 验证
|
||||
|
||||
pip install asyncio aiohttp playwright patchright camoufox
|
||||
mkdir -p ~/matrix/{docker/{camoufox,patchright},profiles,scripts,data,logs,screenshots}
|
||||
```
|
||||
|
||||
### 阶段1:隐身容器跑通 + 人工登录(预计2-3天)
|
||||
|
||||
- [ ] 编写 Camoufox Dockerfile(含所有反检测配置)
|
||||
- [ ] 编写 Patchright Dockerfile
|
||||
- [ ] 编写 docker-compose.yml(5个容器)
|
||||
- [ ] 准备2个静态住宅IP
|
||||
- [ ] `docker-compose up account_01` 启动容器,人工登录抖音
|
||||
- [ ] 验证跳转拦截:小红书网页版是否有弹窗
|
||||
- [ ] 验证Cookie持久化
|
||||
|
||||
**里程碑**:2账号 × 2框架 × 独立IP,同时在线,无跳转弹窗。
|
||||
|
||||
### 阶段2:示教录制与蓝图生成(预计3-5天)
|
||||
|
||||
- [ ] 编写CDP监听脚本
|
||||
- [ ] 连接容器,启动示教模式
|
||||
- [ ] 人工演示"抖音_浏览推荐页 + 点赞"完整流程
|
||||
- [ ] 验证生成的蓝图JSON结构是否合理
|
||||
- [ ] 录制3-5个基础任务蓝图,入库SQLite
|
||||
|
||||
### 阶段3:蓝图回放验证(预计3-5天)
|
||||
|
||||
- [ ] 编写蓝图回放引擎
|
||||
- [ ] 验证自我修复:故意损坏选择器,观察降级定位
|
||||
- [ ] 连续3天存活率测试
|
||||
|
||||
**里程碑**:AI完成完整浏览+点赞+关注序列,无人工干预,3天内未被风控。
|
||||
|
||||
### 阶段4:集成调度器(预计2-3天)
|
||||
|
||||
- [ ] asyncio调度器 + 排班表
|
||||
- [ ] 每日执行报告
|
||||
- [ ] crontab 定时启动
|
||||
|
||||
### 阶段5:扩展任务库与多平台(持续)
|
||||
|
||||
- [ ] 小红书/快手/知乎核心蓝图录制
|
||||
- [ ] 接入 DeepSeek 评论生成
|
||||
- [ ] 5账号全量跑通,观察1周稳定性
|
||||
|
||||
### 阶段6:MLX本地视觉后备(预计1-2天)
|
||||
|
||||
- [ ] 安装MLX + 下载 Qwen2-VL-7B-4bit
|
||||
- [ ] 集成视觉定位为第三级降级
|
||||
- [ ] 压测定位延迟(目标 < 500ms)
|
||||
|
||||
---
|
||||
|
||||
## 六、第五部分:关键技术栈总览
|
||||
|
||||
| 层级 | 工具 | 用途 | 是否免费 |
|
||||
|:---|:---|:---|:---|
|
||||
| 容器运行时 | Colima | 轻量Docker替代 | ✅ |
|
||||
| 反检测浏览器 | Camoufox | Firefox内核,编译级反检测 | ✅ |
|
||||
| 反检测浏览器 | Patchright | Chromium内核,修补CDP泄漏 | ✅ |
|
||||
| CDP通信 | nodriver / patchright | 驱动浏览器 | ✅ |
|
||||
| 行为模拟 | 自定义触摸模拟 | 拟人化触摸操作 | ✅ |
|
||||
| IP代理 | 静态住宅代理 | 独立IP出口 | ❌ |
|
||||
| 任务调度 | Python asyncio | 编排多账号并发 | ✅ |
|
||||
| AI编排 | OpenClaw (可选) | 自然语言转任务指令 | ✅ |
|
||||
| 数据库 | SQLite | 存储蓝图和日志 | ✅ |
|
||||
| 多模态AI | MLX + Qwen2-VL | 本地视觉定位 | ✅ |
|
||||
| 评论生成 | DeepSeek API | 智能评论内容 | ❌(极低) |
|
||||
|
||||
---
|
||||
|
||||
## 七、第六部分:成本估算
|
||||
|
||||
### 初期5账号方案
|
||||
|
||||
| 项目 | 月成本 | 年成本 | 备注 |
|
||||
|:---|:---|:---|:---|
|
||||
| 静态住宅IP ×5 | ¥125-550 | ¥1500-6600 | ¥25-110/个/月 |
|
||||
| 反检测框架 | ¥0 | ¥0 | 开源 |
|
||||
| MLX本地模型 | ¥0 | ¥0 | 仅消耗电费 |
|
||||
| 评论API | ¥10-50 | ¥120-600 | DeepSeek按量付费 |
|
||||
| **月总成本** | **¥135-600** | | |
|
||||
|
||||
### 与商业方案对比
|
||||
|
||||
| 方案 | 月成本 (5账号) | 灵活性 | 技术门槛 |
|
||||
|:---|:---|:---|:---|
|
||||
| **本方案 (开源自建)** | ¥135-600 | ⭐⭐⭐⭐⭐ | 中高 |
|
||||
| AdsPower + RPA | ¥300-1000+ | ⭐⭐⭐ | 中 |
|
||||
| 商业群控系统 | ¥1000-5000 | ⭐⭐ | 低 |
|
||||
|
||||
---
|
||||
|
||||
## 八、附录:常见问题与踩坑记录
|
||||
|
||||
### 容器相关
|
||||
|
||||
**Q: Docker ps 报错 "permission denied"**
|
||||
```bash
|
||||
sudo usermod -aG docker $USER
|
||||
# 重新登录终端
|
||||
```
|
||||
|
||||
**Q: 容器内浏览器无法启动,报错 "no display"**
|
||||
```yaml
|
||||
environment:
|
||||
- DISPLAY=host.docker.internal:0
|
||||
```
|
||||
|
||||
### 反检测相关
|
||||
|
||||
**Q: 平台仍然检测到WebDriver**
|
||||
- 确认Camoufox使用最新版本
|
||||
- 确认没有传入 `--enable-automation` 参数
|
||||
- 通过CDP覆写 `navigator.webdriver`
|
||||
|
||||
**Q: 小红书仍然强制跳转App**
|
||||
- 检查UA中是否包含小红书App标识
|
||||
- 确认URL Scheme拦截是否生效
|
||||
- 尝试增加 `navigator.standalone = false` 覆写
|
||||
|
||||
### 蓝图相关
|
||||
|
||||
**Q: 录制时选择器不稳定**
|
||||
- 优先选择 `data-e2e` 等平台埋点属性
|
||||
- 避免依赖动态生成的class名
|
||||
- 使用相对位置关系作为备选定位
|
||||
|
||||
**Q: MLX视觉定位速度慢**
|
||||
- 确保使用4bit量化版模型
|
||||
- 降低截图分辨率(1920→960)
|
||||
- 先用OCR预筛选,再调用VL模型
|
||||
|
||||
---
|
||||
|
||||
*此手册整合了完整讨论内容,后续开发过程中如有新问题,随时补充到附录。*
|
||||
@@ -0,0 +1,185 @@
|
||||
# Matrix IP 切换方案 — 完整指南
|
||||
|
||||
> 更新:2026-04-27 | 针对抖音养号场景的 IP 策略
|
||||
|
||||
---
|
||||
|
||||
## 一、为什么需要切换 IP?
|
||||
|
||||
| 场景 | 不切 IP 的风险 |
|
||||
|------|----------------|
|
||||
| 多账号同设备 | 同 IP 登录 3+ 账号 → 关联封号 |
|
||||
| 高频操作 | 同 IP 点赞/评论 > 阈值 → 触发验证码 |
|
||||
| 跨地域 | IP 归属地与注册地不一致 → 风控 |
|
||||
|
||||
---
|
||||
|
||||
## 二、IP 类型对比
|
||||
|
||||
| 类型 | 原理 | 检测难度 | 价格 | 适用场景 |
|
||||
|------|------|---------|------|---------|
|
||||
| **数据中心 IP** | 服务器出口 IP | ❌ 极易被识别 | ¥0.5-2/个 | 不推荐 |
|
||||
| **轮转住宅 IP** | 真实家庭宽带,每次请求换 IP | ✅ 难识别 | ¥10-30/GB | 数据采集 |
|
||||
| **静态住宅 IP** | 真实家庭宽带,IP 固定不变 | ✅✅ 最难识别 | ¥5-15/个/月 | **养号(推荐)** |
|
||||
| **免费代理** | 公开代理列表 | ❌ 不可靠 | 免费 | ❌ 不推荐 |
|
||||
|
||||
### 养号场景的最佳选择:**静态住宅 IP**
|
||||
|
||||
原因:
|
||||
1. **IP 固定** → 同一账号始终同一 IP,不会被抖音识别为"频繁换设备"
|
||||
2. **真实住宅** → 不会被代理检测库标记
|
||||
3. **按月付费** → 成本可控,不像流量计费那么贵
|
||||
|
||||
---
|
||||
|
||||
## 三、服务商对比(2026 年价格)
|
||||
|
||||
### 🏆 性价比 TOP 3
|
||||
|
||||
| 服务商 | 静态住宅 IP | 最低月费 | 流量限制 | 中国 IP | 推荐指数 |
|
||||
|--------|-----------|---------|---------|---------|---------|
|
||||
| **IPFoxy** | ¥5-8/个/月 | ¥30/月起 | 无限流量 | ✅ | ⭐⭐⭐⭐⭐ |
|
||||
| **巨量HTTP** | ¥3-6/个/月 | ¥20/月起 | 无限流量 | ✅ | ⭐⭐⭐⭐ |
|
||||
| **Bright Data** | $1.3/个起 | ~¥60/月起 | 按流量 | ✅ | ⭐⭐⭐ |
|
||||
|
||||
### 国内服务商(推荐——延迟低、中国 IP 充足)
|
||||
|
||||
| 服务商 | 静态住宅 IP | 特点 |
|
||||
|--------|-----------|------|
|
||||
| **巨量HTTP** (jlhttp.com) | ¥3-6/个/月 | 国内老牌,IP池大,中文客服 |
|
||||
| **青果代理** (qg.net) | ¥5-8/个/月 | 专注社交账号,有养号套餐 |
|
||||
| **站大爷** (zdaye.com) | ¥4-7/个/月 | 支持城市级定位 |
|
||||
| **IPFoxy** (ipfoxy.io) | ¥5-8/个/月 | 全球覆盖,支持 SOCKS5 |
|
||||
|
||||
### 国际服务商(适合海外平台)
|
||||
|
||||
| 服务商 | 静态住宅 IP | 特点 |
|
||||
|--------|-----------|------|
|
||||
| **Bright Data** | $1.3/个起 | 全球最大 IP 池,4亿+ |
|
||||
| **Smartproxy** | $2/个起 | 性价比不错 |
|
||||
| **Oxylabs** | $1.8/个起 | 企业级,稳定性最好 |
|
||||
|
||||
### 🆓 免费/低成本方案
|
||||
|
||||
| 方案 | 限制 | 可行性 |
|
||||
|------|------|--------|
|
||||
| **自建 VPS + 代理** | 需技术,IP 可能被标记 | ⚠️ 中等 |
|
||||
| **Cloudflare WARP** | 共享 IP,非住宅 | ⚠️ 中等 |
|
||||
| **公开代理列表** | 极不稳定,秒断 | ❌ 不可行 |
|
||||
| **手机 4G/5G 热点** | 真实住宅级,但只有 1 个 IP | ✅ 单账号可用 |
|
||||
|
||||
---
|
||||
|
||||
## 四、推荐方案
|
||||
|
||||
### 方案一:最低成本(¥0-30/月)
|
||||
|
||||
```
|
||||
适用:2-3 个账号
|
||||
方案:手机热点 + 家里宽带
|
||||
|
||||
1. 账号1 → 家里 WiFi(固定 IP)
|
||||
2. 账号2 → 手机 4G 热点(固定 IP)
|
||||
3. 账号3 → 手机 5G 热点(换 SIM/飞行模式换 IP)
|
||||
|
||||
成本:¥0(已有手机卡)
|
||||
```
|
||||
|
||||
### 方案二:性价比(¥30-100/月)⭐ 推荐
|
||||
|
||||
```
|
||||
适用:5-10 个账号
|
||||
方案:2-3 个静态住宅 IP + Profile 切换
|
||||
|
||||
1. 买 2-3 个中国静态住宅 IP(巨量HTTP/IPFoxy)
|
||||
- 每个 IP 绑定 2-3 个账号
|
||||
- 通过 Chrome Profile 切换账号
|
||||
2. 代理配置写在 launch_chrome.sh 里
|
||||
|
||||
成本:¥30-50/月(5个IP × ¥6-10)
|
||||
```
|
||||
|
||||
### 方案三:专业级(¥200+/月)
|
||||
|
||||
```
|
||||
适用:10-30 个账号
|
||||
方案:每个账号独立 IP + 自动化调度
|
||||
|
||||
1. 每个账号 1 个静态住宅 IP
|
||||
2. task_scheduler 自动轮换
|
||||
3. 不同账号不同时段执行
|
||||
|
||||
成本:¥150-300/月
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、技术集成方案
|
||||
|
||||
### 1. Chrome 启动时注入代理
|
||||
|
||||
`launch_chrome.sh` 已支持,只需添加代理参数:
|
||||
|
||||
```bash
|
||||
# HTTP 代理
|
||||
"$CHROME" \
|
||||
--proxy-server="http://user:[email protected]:8080" \
|
||||
--remote-debugging-port="$DEBUG_PORT" \
|
||||
--user-data-dir="$PROFILE_DIR"
|
||||
|
||||
# SOCKS5 代理
|
||||
"$CHROME" \
|
||||
--proxy-server="socks5://user:[email protected]:1080" \
|
||||
--remote-debugging-port="$DEBUG_PORT" \
|
||||
--user-data-dir="$PROFILE_DIR"
|
||||
```
|
||||
|
||||
### 2. switch_account.py 集成
|
||||
|
||||
账号配置增加 `proxy` 字段:
|
||||
|
||||
```yaml
|
||||
accounts:
|
||||
- id: douyin_01
|
||||
proxy: "http://user:[email protected]:8080"
|
||||
- id: douyin_02
|
||||
proxy: "socks5://user:[email protected]:1080"
|
||||
```
|
||||
|
||||
### 3. CDP 代理验证
|
||||
|
||||
```python
|
||||
# 通过 CDP 检查当前出口 IP
|
||||
import json, urllib.request
|
||||
|
||||
opener = urllib.request.build_opener(urllib.request.ProxyHandler({}))
|
||||
# 通过浏览器请求 IP 检测
|
||||
result = await page.evaluate('fetch("https://httpbin.org/ip").then(r=>r.json())')
|
||||
print(f"当前出口 IP: {result['origin']}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、反检测策略矩阵
|
||||
|
||||
| 检测维度 | 方案A(Profile 切换) | 方案B(Cookie 注入) |
|
||||
|---------|---------------------|---------------------|
|
||||
| **IP** | 每个 Profile 用不同代理 | 切换时换代理 |
|
||||
| **浏览器指纹** | 真实 Chrome(原生) | 真实 Chrome(原生) |
|
||||
| **Cookie** | Profile 自带 | 手动注入 |
|
||||
| **Canvas 指纹** | 每个 Profile 不同(GPU 渲染差异) | 同一 Canvas |
|
||||
| **WebGL 指纹** | init_script 注入 | init_script 注入 |
|
||||
| **Audio 指纹** | 每个 Profile 不同 | 同一 |
|
||||
| **navigator** | webdriver=undefined | webdriver=undefined |
|
||||
| **时区/语言** | CDP 覆盖 | CDP 覆盖 |
|
||||
|
||||
---
|
||||
|
||||
## 七、下一步行动
|
||||
|
||||
1. ✅ `switch_account.py` 已实现(方案A+B)
|
||||
2. 📋 买 2-3 个中国静态住宅 IP(推荐 巨量HTTP 或 IPFoxy)
|
||||
3. 📋 在 `accounts.yaml` 配置代理
|
||||
4. 📋 `launch_chrome.sh` 增加代理参数
|
||||
5. 📋 自动化调度:不同账号+不同IP+不同时段
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
# 阶段A 完成总结 — CDP 直连 + 原子操作 + 账号切换
|
||||
|
||||
> **完成日期**: 2026-04-27 | **阶段**: A | **状态**: ✅ 全部完成
|
||||
|
||||
---
|
||||
|
||||
## 一、阶段A 目标回顾
|
||||
|
||||
| 目标 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| CDP 直连本机 Chrome | ✅ | 通过 Patchright `connect_over_cdp` 连接 |
|
||||
| 原子操作库 V2 | ✅ | 18 个原子操作,基于 `data-e2e` 选择器 |
|
||||
| 蓝图执行引擎 | ✅ | `task_engine.py` 支持 JSON 蓝图顺序执行 |
|
||||
| 定时调度器 | ✅ | `task_scheduler.py` 支持 cron 表达式 |
|
||||
| 账号切换器 | ✅ | `switch_account.py` 双方案(Profile/Cookie) |
|
||||
| 指纹注入 | ✅ | 视口+时区+语言+WebGL+webdriver+plugins+App拦截 |
|
||||
| 双账号并行 | ✅ | 端口 9222 + 9223 同时运行 |
|
||||
|
||||
---
|
||||
|
||||
## 二、核心文件清单
|
||||
|
||||
| 文件 | 路径 | 用途 |
|
||||
|------|------|------|
|
||||
| 原子操作库 | `scripts/douyin_ops.py` | 18 个原子操作(基于 data-e2e) |
|
||||
| CDP 连接器 | `scripts/cdp_connector.py` | CDP 连接管理 |
|
||||
| 蓝图引擎 | `scripts/task_engine.py` | 读取蓝图→顺序执行 |
|
||||
| 定时调度 | `scripts/task_scheduler.py` | cron 调度 |
|
||||
| 蓝图入库 | `scripts/seed_db.py` | 初始化蓝图到数据库 |
|
||||
| 账号切换器 | `scripts/switch_account.py` | Profile切换+指纹注入+Cookie注入 |
|
||||
| 账号配置 | `config/accounts.yaml` | 4 个账号 + 全局视口 |
|
||||
| 数据库 | `data/matrix.db` | 6 表 + 4 蓝图 + 4 账号 |
|
||||
| 选择器手册 | `docs/DOUYIN_SELECTORS.md` | data-e2e 选择器对照 |
|
||||
| 完整方案 | `docs/DOUYIN_FULL_PLAN.md` | V3.1 架构+蓝图+反检测+IP方案 |
|
||||
| IP 切换指南 | `docs/IP_SWITCH_GUIDE.md` | 免费方案+付费推荐+技术集成 |
|
||||
| 本总结 | `docs/PHASE_A_SUMMARY.md` | 阶段A 完成归档 |
|
||||
|
||||
---
|
||||
|
||||
## 三、账号配置详情
|
||||
|
||||
| 账号ID | 平台 | 端口 | Profile | 状态 |
|
||||
|--------|------|------|---------|------|
|
||||
| douyin_01 | 抖音 | 9222 | account_01 | ✅ 已登录(主号) |
|
||||
| douyin_02 | 抖音 | 9223 | douyin_02 | ⏹ 待登录(副号) |
|
||||
| xhs_01 | 小红书 | 9224 | xhs_01 | ⏹ 待注册 |
|
||||
| zhihu_01 | 知乎 | 9225 | zhihu_01 | ⏹ 待注册 |
|
||||
|
||||
### 视口配置(全局默认)
|
||||
|
||||
```yaml
|
||||
viewport:
|
||||
width: 702
|
||||
height: 783
|
||||
mobile: false # 桌面端模式
|
||||
```
|
||||
|
||||
> 实测来源:ghai 手动调整两个 Chrome 窗口至满意尺寸后,通过 AppleScript 读取确认。
|
||||
|
||||
---
|
||||
|
||||
## 四、蓝图清单
|
||||
|
||||
| 蓝图ID | 名称 | 步骤数 | 状态 |
|
||||
|--------|------|--------|------|
|
||||
| `douyin_browse_v2` | 日常浏览V2 | 11 | ✅ active |
|
||||
| `douyin_search_browse` | 搜索浏览 | 7 | ✅ active |
|
||||
| `douyin_comment_interact` | 评论互动 | 8 | ✅ active |
|
||||
| `douyin_browse` | 日常浏览V1 | 8 | ⛔ deprecated |
|
||||
|
||||
---
|
||||
|
||||
## 五、踩坑记录(重要经验)
|
||||
|
||||
| 问题 | 原因 | 解决方案 |
|
||||
|------|------|---------|
|
||||
| `hash()` 跨进程不一致 | Python `hash()` 随机种子 | 改用 `sum(ord(c))` 确定性哈希 |
|
||||
| 移动端 UA 覆盖破坏登录 | Android UA 导致 Cookie 校验失败 | 不覆盖 UA,保持浏览器原生 UA |
|
||||
| 移动端视口破坏登录 | `mobile: True` 改变渲染模式 | `mobile: False`,桌面端模式 |
|
||||
| 视口过窄(480px) | 初始参数不当 | 实测确认 702x783 为最佳 |
|
||||
| PyYAML 未安装 | 简易解析器不含 viewport | 更新 `_parse_yaml_simple()` 支持 viewport 块 |
|
||||
| Profile 目录名错误 | 配置写 douyin_01 实际是 account_01 | 修正 accounts.yaml |
|
||||
|
||||
---
|
||||
|
||||
## 六、反检测现状
|
||||
|
||||
### ✅ 已实现
|
||||
|
||||
- Patchright 自动处理 `navigator.webdriver`
|
||||
- WebGL Vendor/Renderer 注入(NVIDIA GTX 1660 SUPER)
|
||||
- HeadlessChrome 标记移除
|
||||
- navigator.plugins/languages 伪装
|
||||
- App deeplink 拦截(CDP Fetch)
|
||||
- 时区/语言统一中国
|
||||
- 真实 Chrome 浏览器(非 Headless)
|
||||
- 每账号独立 Profile + 端口
|
||||
- 同账号指纹模板稳定映射
|
||||
|
||||
### ⏹ 待实现
|
||||
|
||||
- 鼠标轨迹仿真(贝塞尔曲线)
|
||||
- Canvas/AudioContext 指纹噪声
|
||||
- 静态住宅 IP 接入
|
||||
- 活跃时段控制
|
||||
|
||||
---
|
||||
|
||||
## 七、IP 方案结论
|
||||
|
||||
| 方案 | 成本 | 适用场景 |
|
||||
|------|------|---------|
|
||||
| 家里 WiFi + 手机热点 | ¥0 | 2-3 账号 |
|
||||
| 巨量HTTP 静态住宅 | ¥3-6/个/月 | 养号首选 |
|
||||
| IPFoxy 静态住宅 | ¥5-8/个/月 | 备选 |
|
||||
|
||||
> 技术集成:Chrome 启动时 `--proxy-server=http://user:pass@proxy:port`
|
||||
|
||||
---
|
||||
|
||||
## 八、下一步:阶段B 规划
|
||||
|
||||
| 优先级 | 任务 | 说明 |
|
||||
|--------|------|------|
|
||||
| P0 | douyin_02 登录并导出 Cookie | 手动登录一次后 export-cookies |
|
||||
| P1 | 鼠标轨迹仿真 | 贝塞尔曲线 + 加减速 |
|
||||
| P1 | 语料库填充 | 评论模板/搜索关键词 |
|
||||
| P2 | 静态住宅 IP 接入 | 购买后集成到 launch_chrome |
|
||||
| P2 | Cookie 方案B 完善 | 当前骨架可用,需更多测试 |
|
||||
| P3 | Docker + Camoufox | 多账号容器化部署 |
|
||||
|
||||
---
|
||||
|
||||
## 九、关键命令速查
|
||||
|
||||
```bash
|
||||
# 切换账号
|
||||
python scripts/switch_account.py --method profile --target douyin_01 --port 9222
|
||||
|
||||
# 双账号并行
|
||||
# 终端1:
|
||||
python scripts/switch_account.py --method profile --target douyin_01 --port 9222
|
||||
# 终端2:
|
||||
python scripts/switch_account.py --method profile --target douyin_02 --port 9223
|
||||
|
||||
# 导出 Cookie
|
||||
python scripts/switch_account.py --target douyin_01 --export-cookies
|
||||
|
||||
# 查看状态
|
||||
python scripts/switch_account.py --status
|
||||
|
||||
# 列出账号
|
||||
python scripts/switch_account.py --list
|
||||
```
|
||||
@@ -0,0 +1,542 @@
|
||||
# 矩阵养号系统 Matrix — 完整项目说明
|
||||
|
||||
> **项目版本**: v3.0(2026-04-28)
|
||||
> **负责人**: ghai
|
||||
> **最后更新**: 2026-04-28
|
||||
|
||||
---
|
||||
|
||||
## 一、项目概述
|
||||
|
||||
### 1.1 什么是矩阵养号系统
|
||||
|
||||
矩阵养号系统是一个**自动化社交账号运营工具**,通过程序化控制浏览器完成抖音、小红书、知乎等平台的日常养号任务。目标是让多个账号模拟真实用户行为,提升账号权重和活跃度。
|
||||
|
||||
### 1.2 核心价值
|
||||
|
||||
| 价值点 | 说明 |
|
||||
|--------|------|
|
||||
| **自动化** | 告别手动操作,自动执行浏览、点赞、评论、收藏等任务 |
|
||||
| **多账号** | 支持同时管理多个账号,每个账号独立隔离 |
|
||||
| **反检测** | 内置多种反检测措施,降低被平台识别为机器人的风险 |
|
||||
| **可扩展** | 支持多平台、蓝图化任务、灵活配置 |
|
||||
| **可迁移** | 完整的环境配置和迁移方案 |
|
||||
|
||||
### 1.3 支持平台
|
||||
|
||||
| 平台 | 状态 | 核心功能 |
|
||||
|------|------|---------|
|
||||
| 抖音 | ✅ 已实现 | 推荐浏览、搜索、点赞、收藏、评论、关注 |
|
||||
| 小红书 | 🔄 框架完成 | 需登录账号 |
|
||||
| 知乎 | 🔄 框架完成 | 需登录账号 |
|
||||
| 快手 | 📋 规划中 | 待开发 |
|
||||
|
||||
---
|
||||
|
||||
## 二、宏伟蓝图与目标
|
||||
|
||||
### 2.1 最终愿景
|
||||
|
||||
> **打造一个全平台、智能化、可持续的社交账号矩阵运营系统**
|
||||
|
||||
### 2.2 发展阶段规划
|
||||
|
||||
```
|
||||
阶段A ✅ 已完成(2026-04-27)
|
||||
├── Chrome CDP 直连
|
||||
├── 抖音原子操作库 V2(18个操作)
|
||||
├── 蓝图执行引擎
|
||||
├── 定时调度器
|
||||
├── 账号切换器(双方案)
|
||||
├── 指纹注入
|
||||
└── 双账号并行
|
||||
|
||||
阶段B 🔄 进行中
|
||||
├── Camoufox(Firefox内核)集成 ← 当前卡点
|
||||
├── 多浏览器内核支持
|
||||
├── 提升反检测能力
|
||||
└── 第二个账号登录
|
||||
|
||||
阶段C 📋 规划中
|
||||
├── 鼠标轨迹仿真
|
||||
├── 语料库完善
|
||||
├── Canvas/AudioContext 指纹噪声
|
||||
└── 静态住宅IP接入
|
||||
|
||||
阶段D 📋 规划中
|
||||
├── 小红书完整支持
|
||||
├── 知乎完整支持
|
||||
├── 多平台联动
|
||||
└── 智能行为决策
|
||||
```
|
||||
|
||||
### 2.3 里程碑目标
|
||||
|
||||
| 阶段 | 目标账号数 | 反检测等级 | 自动化程度 |
|
||||
|------|-----------|-----------|-----------|
|
||||
| A | 1-2个 | ⭐⭐ | 半自动(需手动登录) |
|
||||
| B | 2-4个 | ⭐⭐⭐ | 半自动(Camoufox) |
|
||||
| C | 4-8个 | ⭐⭐⭐⭐ | 全自动 |
|
||||
| D | 10+个 | ⭐⭐⭐⭐⭐ | 全自动+智能决策 |
|
||||
|
||||
---
|
||||
|
||||
## 三、项目架构
|
||||
|
||||
### 3.1 整体架构图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 用户指令 / 定时触发 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 蓝图引擎 (task_engine.py) │
|
||||
│ 定时调度 (task_scheduler.py) │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 原子操作库 (douyin_ops.py) │
|
||||
│ 18个最小操作单元,含前置检查+执行+后置验证 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 账号切换器 (switch_account.py) │
|
||||
│ 方案A: Chrome Profile切换 方案B: Cookie注入 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ┌──────────────────┐ ┌──────────────────┐ │
|
||||
│ │ Chrome CDP │ │ Camoufox │ │
|
||||
│ │ 端口 9222/9223 │ │ 端口 9301/9302 │ │
|
||||
│ │ ✅ 已完成 │ │ 🔄 进行中 │ │
|
||||
│ └──────────────────┘ └──────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 抖音网页 / 小红书 / 知乎 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.2 核心组件
|
||||
|
||||
| 组件 | 文件 | 职责 |
|
||||
|------|------|------|
|
||||
| 原子操作库 | `scripts/douyin_ops.py` | 封装18个浏览器操作 |
|
||||
| CDP连接器 | `scripts/cdp_connector.py` | 管理Chrome CDP连接 |
|
||||
| 账号切换器 | `scripts/switch_account.py` | 多账号Profile切换 |
|
||||
| Camoufox管理 | `scripts/camoufox_manager.py` | Firefox内核管理 |
|
||||
| 蓝图引擎 | `scripts/task_engine.py` | 读取执行JSON蓝图 |
|
||||
| 定时调度 | `scripts/task_scheduler.py` | Cron定时任务 |
|
||||
| 数据库 | `data/matrix.db` | 账号、蓝图、日志存储 |
|
||||
|
||||
### 3.3 数据流
|
||||
|
||||
```
|
||||
蓝图JSON → 引擎解析 → 操作序列 → CDP执行 → 页面响应 → 日志记录
|
||||
↓
|
||||
频率控制(防封)
|
||||
↓
|
||||
错误恢复(自动重试)
|
||||
↓
|
||||
结果统计(数据库)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、环境依赖
|
||||
|
||||
### 4.1 系统要求
|
||||
|
||||
| 项目 | 要求 | 当前环境 |
|
||||
|------|------|---------|
|
||||
| 操作系统 | macOS (Apple Silicon) | ✅ macOS |
|
||||
| Python | 3.13+ | ✅ 3.13.12 |
|
||||
| Chrome | 最新版 | ✅ 已安装 |
|
||||
| 磁盘空间 | 10GB+ | ✅ 充足 |
|
||||
|
||||
### 4.2 Python环境
|
||||
|
||||
```bash
|
||||
# 使用的Python路径
|
||||
/Users/7kecheng/.workbuddy/binaries/python/versions/3.13.12/bin/python3
|
||||
```
|
||||
|
||||
**必须安装的包**:
|
||||
```bash
|
||||
pip install patchright camoufox pyyaml aiosqlite
|
||||
```
|
||||
|
||||
### 4.3 浏览器
|
||||
|
||||
| 浏览器 | 用途 | 状态 | 端口 |
|
||||
|--------|------|------|------|
|
||||
| Chrome | 主要浏览器 | ✅ 已配置 | 9222/9223 |
|
||||
| Camoufox | Firefox内核(反检测更强) | 🔄 配置中 | 9301/9302 |
|
||||
|
||||
### 4.4 目录结构
|
||||
|
||||
```
|
||||
~/matrix/
|
||||
├── docs/ # 项目文档
|
||||
│ ├── PROJECT_OVERVIEW.md # 本文件(项目总览)
|
||||
│ ├── DOUYIN_FULL_PLAN.md # 抖音完整方案
|
||||
│ ├── DOUYIN_SELECTORS.md # 选择器手册
|
||||
│ ├── PHASE_A_SUMMARY.md # 阶段A完成总结
|
||||
│ ├── CAMOUFOX_LOGIN_MANAGEMENT.md # Camoufox集成方案
|
||||
│ ├── IP_SWITCH_GUIDE.md # IP切换指南
|
||||
│ ├── IMPLEMENTATION_GUIDE.md # 落地手册
|
||||
│ └── LOCAL_ADAPTATION.md # 本地适配说明
|
||||
├── scripts/ # 核心脚本
|
||||
│ ├── douyin_ops.py # 原子操作库(18操作)
|
||||
│ ├── cdp_connector.py # CDP连接器
|
||||
│ ├── switch_account.py # 账号切换器
|
||||
│ ├── camoufox_manager.py # Camoufox管理器
|
||||
│ ├── task_engine.py # 蓝图引擎
|
||||
│ ├── task_scheduler.py # 定时调度
|
||||
│ ├── seed_db.py # 数据库初始化
|
||||
│ ├── init_db.py # 数据库初始化
|
||||
│ └── launch_chrome.sh # Chrome启动脚本
|
||||
├── blueprints/ # 任务蓝图
|
||||
│ ├── douyin_browse_v2.json # 日常浏览V2(11步)
|
||||
│ ├── douyin_search_browse.json # 搜索浏览(7步)
|
||||
│ ├── douyin_comment_interact.json # 评论互动(8步)
|
||||
│ └── douyin_browse.json # 日常浏览V1(已废弃)
|
||||
├── config/ # 配置文件
|
||||
│ └── accounts.yaml # 账号配置
|
||||
├── data/ # 数据存储
|
||||
│ ├── matrix.db # SQLite数据库
|
||||
│ ├── cookies/ # Cookie存储
|
||||
│ └── camoufox_pids/ # Camoufox进程PID
|
||||
├── profiles/ # 浏览器Profile
|
||||
│ ├── account_01/ # 抖音主号Profile
|
||||
│ ├── douyin_02/ # 抖音副号Profile
|
||||
│ ├── camoufox_01/ # Camoufox账号1
|
||||
│ └── camoufox_02/ # Camoufox账号2
|
||||
├── corpus/ # 语料库
|
||||
├── logs/ # 日志
|
||||
├── screenshots/ # 截图存档
|
||||
└── docker/ # Docker配置(未来)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、当前状态
|
||||
|
||||
### 5.1 已完成功能
|
||||
|
||||
#### ✅ 阶段A:Chrome CDP 方案
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| CDP直连Chrome | ✅ 完成 | Patchright connect_over_cdp |
|
||||
| 原子操作库V2 | ✅ 完成 | 18个操作,含前置检查+后置验证 |
|
||||
| 蓝图引擎 | ✅ 完成 | JSON蓝图顺序执行 |
|
||||
| 定时调度 | ✅ 完成 | Cron表达式调度 |
|
||||
| 账号切换器 | ✅ 完成 | Profile切换+Cookie注入 |
|
||||
| 指纹注入 | ✅ 完成 | 视口+时区+语言+WebGL |
|
||||
| 双账号并行 | ✅ 完成 | 端口9222+9223 |
|
||||
|
||||
#### 🔄 阶段B:Camoufox 集成(进行中)
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| Camoufox包安装 | ✅ 完成 | v3.0.0 |
|
||||
| Camoufox浏览器下载 | ✅ 完成 | v135.0.1-beta.24 |
|
||||
| Profile目录创建 | ✅ 完成 | camoufox_01, camoufox_02 |
|
||||
| Camoufox启动 | 🔄 卡住 | executable_path配置问题 |
|
||||
| Camoufox登录 | ⏸ 待开始 | 需启动后才能登录 |
|
||||
| Camoufox CDP连接 | ⏸ 待开始 | 需登录后验证 |
|
||||
|
||||
### 5.2 账号状态
|
||||
|
||||
| 账号ID | 平台 | 端口 | 浏览器 | 状态 |
|
||||
|--------|------|------|--------|------|
|
||||
| douyin_01 | 抖音 | 9222 | Chrome | ✅ 已登录 |
|
||||
| douyin_02 | 抖音 | 9223 | Chrome | ⏸ 待登录 |
|
||||
| xhs_01 | 小红书 | 9224 | Chrome | ⏸ 待注册 |
|
||||
| zhihu_01 | 知乎 | 9225 | Chrome | ⏸ 待注册 |
|
||||
| douyin_camo01 | 抖音 | 9301 | Camoufox | 🔄 配置中 |
|
||||
| douyin_camo02 | 抖音 | 9302 | Camoufox | 🔄 配置中 |
|
||||
|
||||
### 5.3 蓝图状态
|
||||
|
||||
| 蓝图ID | 名称 | 步骤数 | 状态 | 备注 |
|
||||
|--------|------|--------|------|------|
|
||||
| douyin_browse_v2 | 日常浏览V2 | 11步 | ✅ 活跃 | 推荐使用 |
|
||||
| douyin_search_browse | 搜索浏览 | 7步 | ✅ 活跃 | - |
|
||||
| douyin_comment_interact | 评论互动 | 8步 | ✅ 活跃 | - |
|
||||
| douyin_browse | 日常浏览V1 | 8步 | ⛔ 废弃 | 不再使用 |
|
||||
|
||||
---
|
||||
|
||||
## 六、遇到的问题
|
||||
|
||||
### 6.1 Camoufox 启动问题(当前卡点)
|
||||
|
||||
**问题描述**:
|
||||
```
|
||||
FileNotFoundError: [Errno 2] No such file or directory:
|
||||
'/Users/7kecheng/Library/Caches/camoufox/Camoufox.app/Contents/MacOS/properties.json'
|
||||
```
|
||||
|
||||
**原因分析**:
|
||||
- Camoufox 浏览器缓存文件不完整
|
||||
- `camoufox_manager.py` 中显式指定的 `executable_path` 导致路径查找错误
|
||||
- `properties.json` 文件实际位于 `Resources` 目录,而非 `MacOS` 目录
|
||||
|
||||
**已尝试的解决**:
|
||||
1. ✅ 清理缓存 `rm -rf ~/Library/Caches/camoufox`
|
||||
2. ✅ 重新下载 `camoufox fetch`
|
||||
3. ✅ 修改脚本移除显式 `executable_path` 路径
|
||||
|
||||
**当前状态**:
|
||||
- 已修改 `camoufox_manager.py` 第148-154行
|
||||
- 等待下次启动验证
|
||||
|
||||
### 6.2 踩坑记录(历史问题,已解决)
|
||||
|
||||
| 问题 | 日期 | 原因 | 解决方案 |
|
||||
|------|------|------|---------|
|
||||
| `hash()` 跨进程不一致 | 2026-04-27 | Python随机种子 | 改用 `sum(ord(c))` |
|
||||
| 移动端UA覆盖破坏登录 | 2026-04-27 | Android UA导致Cookie校验失败 | 不覆盖UA |
|
||||
| 移动端视口破坏登录 | 2026-04-27 | `mobile: True`改变渲染 | `mobile: False` |
|
||||
| 视口过窄 | 2026-04-27 | 初始参数480px | 实测702x783最佳 |
|
||||
| Profile目录名错误 | 2026-04-27 | 配置与实际不符 | 修正accounts.yaml |
|
||||
|
||||
---
|
||||
|
||||
## 七、下一步计划
|
||||
|
||||
### 7.1 立即任务(今天)
|
||||
|
||||
| 优先级 | 任务 | 状态 | 操作 |
|
||||
|--------|------|------|------|
|
||||
| P0 | Camoufox启动验证 | 🔄 进行中 | 移除executable_path后重新启动 |
|
||||
| P0 | douyin_camo01登录 | ⏸ 等待 | 启动后手动扫码登录 |
|
||||
| P0 | 导出Cookie | ⏸ 等待 | 登录后导出备份 |
|
||||
|
||||
### 7.2 短期任务(本周)
|
||||
|
||||
| 优先级 | 任务 | 预计时间 |
|
||||
|--------|------|---------|
|
||||
| P0 | Camoufox CDP连接验证 | 1小时 |
|
||||
| P1 | 鼠标轨迹仿真 | 4小时 |
|
||||
| P1 | 语料库填充 | 1小时 |
|
||||
| P2 | douyin_02登录 | 1小时 |
|
||||
|
||||
### 7.3 中期任务(本月)
|
||||
|
||||
| 优先级 | 任务 | 预计时间 |
|
||||
|--------|------|---------|
|
||||
| P1 | 静态住宅IP接入 | 按服务商 |
|
||||
| P2 | Cookie方案B完善 | 4小时 |
|
||||
| P3 | 小红书支持 | 1天 |
|
||||
| P3 | 知乎支持 | 1天 |
|
||||
|
||||
### 7.4 长期任务(未来)
|
||||
|
||||
| 任务 | 说明 |
|
||||
|------|------|
|
||||
| 多平台联动 | 抖音→小红书→知乎互动联动 |
|
||||
| 智能决策 | AI驱动的行为决策 |
|
||||
| Docker容器化 | 完全隔离的多容器部署 |
|
||||
|
||||
---
|
||||
|
||||
## 八、如何执行
|
||||
|
||||
### 8.1 快速开始
|
||||
|
||||
```bash
|
||||
# 1. 进入项目目录
|
||||
cd ~/matrix
|
||||
|
||||
# 2. 查看帮助
|
||||
/Users/7kecheng/.workbuddy/binaries/python/versions/3.13.12/bin/python3 scripts/switch_account.py --help
|
||||
|
||||
# 3. 启动Chrome账号(方案A)
|
||||
/Users/7kecheng/.workbuddy/binaries/python/versions/3.13.12/bin/python3 scripts/switch_account.py --method profile --target douyin_01 --port 9222
|
||||
|
||||
# 4. 查看状态
|
||||
/Users/7kecheng/.workbuddy/binaries/python/versions/3.13.12/bin/python3 scripts/switch_account.py --status
|
||||
```
|
||||
|
||||
### 8.2 执行蓝图
|
||||
|
||||
```bash
|
||||
# 执行日常浏览蓝图
|
||||
/Users/7kecheng/.workbuddy/binaries/python/versions/3.13.12/bin/python3 scripts/task_engine.py --blueprint douyin_browse_v2 --account douyin_01
|
||||
|
||||
# 执行搜索浏览蓝图
|
||||
/Users/7kecheng/.workbuddy/binaries/python/versions/3.13.12/bin/python3 scripts/task_engine.py --blueprint douyin_search_browse --account douyin_01
|
||||
```
|
||||
|
||||
### 8.3 Camoufox操作(待修复后)
|
||||
|
||||
```bash
|
||||
# 启动Camoufox
|
||||
/Users/7kecheng/.workbuddy/binaries/python/versions/3.13.12/bin/python3 scripts/camoufox_manager.py --launch douyin_camo01
|
||||
|
||||
# 验证登录
|
||||
/Users/7kecheng/.workbuddy/binaries/python/versions/3.13.12/bin/python3 scripts/camoufox_manager.py --verify douyin_camo01
|
||||
|
||||
# 导出Cookie
|
||||
/Users/7kecheng/.workbuddy/binaries/python/versions/3.13.12/bin/python3 scripts/camoufox_manager.py --export douyin_camo01
|
||||
```
|
||||
|
||||
### 8.4 定时调度
|
||||
|
||||
```bash
|
||||
# 添加每日任务(每天9点执行)
|
||||
/Users/7kecheng/.workbuddy/binaries/python/versions/3.13.12/bin/python3 scripts/task_scheduler.py --add "douyin_browse_v2" --cron "0 9 * * *"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、迁移方案
|
||||
|
||||
### 9.1 迁移准备清单
|
||||
|
||||
迁移前需要准备以下内容:
|
||||
|
||||
```
|
||||
□ 源码目录 ~/matrix/
|
||||
□ Profile目录 ~/matrix/profiles/
|
||||
□ Cookie备份 ~/matrix/data/cookies/
|
||||
□ 配置文件 config/accounts.yaml
|
||||
□ 浏览器安装(Chrome / Camoufox)
|
||||
□ Python 3.13+ 环境
|
||||
□ pip 包(patchright, camoufox, pyyaml)
|
||||
```
|
||||
|
||||
### 9.2 完整迁移步骤
|
||||
|
||||
```bash
|
||||
# 1. 打包源码(排除大文件和缓存)
|
||||
rsync -av --exclude='profiles/*/Cache' \
|
||||
--exclude='logs/*.log' \
|
||||
--exclude='.DS_Store' \
|
||||
~/matrix/ /path/to/backup/matrix/
|
||||
|
||||
# 2. 打包Profile(选择性迁移登录状态)
|
||||
rsync -av ~/matrix/profiles/account_01/ /path/to/backup/profiles/account_01/
|
||||
|
||||
# 3. 打包Cookie
|
||||
rsync -av ~/matrix/data/cookies/ /path/to/backup/cookies/
|
||||
|
||||
# 4. 在新机器安装依赖
|
||||
pip install patchright camoufox pyyaml aiosqlite
|
||||
|
||||
# 5. 下载Camoufox浏览器
|
||||
python3 -m camoufox fetch
|
||||
|
||||
# 6. 启动Chrome并验证
|
||||
python3 scripts/switch_account.py --status
|
||||
```
|
||||
|
||||
### 9.3 迁移后检查
|
||||
|
||||
```bash
|
||||
# 检查Python环境
|
||||
python3 --version # 应为3.13+
|
||||
|
||||
# 检查pip包
|
||||
pip list | grep -E "patchright|camoufox|pyyaml"
|
||||
|
||||
# 检查Chrome
|
||||
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version
|
||||
|
||||
# 检查Camoufox
|
||||
python3 -m camoufox path
|
||||
|
||||
# 初始化数据库
|
||||
python3 scripts/init_db.py
|
||||
|
||||
# 测试CDP连接
|
||||
python3 scripts/switch_account.py --status
|
||||
```
|
||||
|
||||
### 9.4 注意事项
|
||||
|
||||
1. **Profile迁移**:Cookie和登录状态在Profile中,整体迁移最简单
|
||||
2. **Camoufox**:每个平台需要单独下载浏览器
|
||||
3. **代理配置**:如果使用代理,迁移后需更新账号配置
|
||||
4. **端口占用**:确保9222-9322端口未被占用
|
||||
|
||||
---
|
||||
|
||||
## 十、常见问题
|
||||
|
||||
### Q1: Chrome无法启动?
|
||||
|
||||
```bash
|
||||
# 检查Chrome是否安装
|
||||
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version
|
||||
|
||||
# 检查端口是否被占用
|
||||
lsof -i :9222
|
||||
```
|
||||
|
||||
### Q2: CDP连接失败?
|
||||
|
||||
```bash
|
||||
# 启动Chrome时添加CDP端口
|
||||
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
|
||||
--remote-debugging-port=9222 \
|
||||
--user-data-dir=~/matrix/profiles/account_01
|
||||
```
|
||||
|
||||
### Q3: Camoufox下载失败?
|
||||
|
||||
```bash
|
||||
# 设置代理后重试
|
||||
export https_proxy=http://127.0.0.1:7890
|
||||
python3 -m camoufox fetch
|
||||
```
|
||||
|
||||
### Q4: 账号被封禁?
|
||||
|
||||
- 降低操作频率
|
||||
- 使用静态住宅IP
|
||||
- 增加随机延迟
|
||||
- 模拟真实用户行为
|
||||
|
||||
---
|
||||
|
||||
## 十一、联系方式
|
||||
|
||||
- **项目负责人**: ghai
|
||||
- **项目目录**: ~/matrix/
|
||||
- **文档目录**: ~/matrix/docs/
|
||||
|
||||
---
|
||||
|
||||
## 附录A:关键文件路径速查
|
||||
|
||||
| 文件 | 路径 |
|
||||
|------|------|
|
||||
| 项目根目录 | ~/matrix/ |
|
||||
| 账号配置 | ~/matrix/config/accounts.yaml |
|
||||
| 原子操作库 | ~/matrix/scripts/douyin_ops.py |
|
||||
| CDP连接器 | ~/matrix/scripts/cdp_connector.py |
|
||||
| 账号切换器 | ~/matrix/scripts/switch_account.py |
|
||||
| Camoufox管理 | ~/matrix/scripts/camoufox_manager.py |
|
||||
| 数据库 | ~/matrix/data/matrix.db |
|
||||
| Cookie存储 | ~/matrix/data/cookies/ |
|
||||
| Profile存储 | ~/matrix/profiles/ |
|
||||
|
||||
## 附录B:环境变量速查
|
||||
|
||||
| 变量 | 值 |
|
||||
|------|---|
|
||||
| PYTHON | /Users/7kecheng/.workbuddy/binaries/python/versions/3.13.12/bin/python3 |
|
||||
| CHROME | /Applications/Google Chrome.app/Contents/MacOS/Google Chrome |
|
||||
| CAMOUFOX_CACHE | ~/Library/Caches/camoufox/ |
|
||||
| PROJECT_DIR | ~/matrix/ |
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0
|
||||
**创建日期**: 2026-04-28
|
||||
**更新日期**: 2026-04-28
|
||||
@@ -0,0 +1,190 @@
|
||||
# Matrix 养号系统 — 重构设计方案 v2.2
|
||||
|
||||
> 最后更新:2026-05-01
|
||||
> 版本:2.2.0 (草案)
|
||||
|
||||
> 本文件为设计方案,待确认后再实施。
|
||||
|
||||
## 一、当前问题诊断
|
||||
|
||||
| # | 问题 | 根因 | 影响 |
|
||||
|---|------|------|------|
|
||||
| 1 | 退出时 Chrome 崩溃/恢复弹窗 | `os.kill(pid, 9)` 强行杀进程,未走正常关闭 | 下次启动弹恢复确认框 |
|
||||
| 2 | 点赞/收藏永远失败 | 操作前未验证当前页面状态,直接在首页点按钮 | 操作无效果 |
|
||||
| 3 | "11/11 完成"但什么都没做 | 没有操作后的锚点验证,异常也被吞了 | 误报成功 |
|
||||
| 4 | 不知道当前在什么页面 | 没有页面状态跟踪器 | 操作错位 |
|
||||
| 5 | 登录验证不可靠 | 只查了一个 `data-e2e` 选择器,页面不同状态结果不同 | 误判未登录 |
|
||||
| 6 | 脚本散乱不可组合 | 每个测试脚本都重复写类似逻辑 | 维护成本高 |
|
||||
|
||||
## 二、架构设计
|
||||
|
||||
### 2.1 三层架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────┐
|
||||
│ WorkBuddy 技能层 │ ← 对话触发
|
||||
│ (SKILL.md + 养号指令) │
|
||||
├─────────────────────────────┤
|
||||
│ orchestrator 调度层 │ ← 智能选账号/蓝图/状态机
|
||||
│ (yanghao_orchestrator.py) │
|
||||
├─────────────────────────────┤
|
||||
│ 原子操作层 (21个原子操作) │ ← 可组合、可验证
|
||||
│ (AtomOps + 校验器) │
|
||||
├─────────────────────────────┤
|
||||
│ CDP连接器 + 浏览器管理 │ ← 优雅启停
|
||||
│ (cdp_connector + browser) │
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 原子操作定义 (每个操作带前置校验 + 后置锚点)
|
||||
|
||||
```
|
||||
每个原子操作 = (名称, 执行函数, 前置校验, 后置锚点, 超时, 重试次数)
|
||||
|
||||
例子:
|
||||
"like" =
|
||||
pre_check: 当前在视频播放器页, 点赞按钮存在
|
||||
execute: 点击 [data-e2e="video-player-digg"]
|
||||
post_check: 点赞数+1 或 按钮状态变化
|
||||
timeout: 10s
|
||||
retry: 2次
|
||||
```
|
||||
|
||||
### 2.3 页面状态机
|
||||
|
||||
```
|
||||
[首页 grid] ──点击视频──→ [视频播放器]
|
||||
↑ │
|
||||
│ ↓
|
||||
│ [下滑/下一条]
|
||||
│ │
|
||||
│ ↓
|
||||
│ [新视频播放器]
|
||||
│ │
|
||||
└─────── 返回首页 ──────┘
|
||||
|
||||
页面锚点:
|
||||
grid 模式: 有 [data-e2e="alink-item"],无 video-player-digg
|
||||
播放器模式: 有 [data-e2e="video-player-digg"]
|
||||
搜索页: 有 [data-e2e="searchbar-input"]
|
||||
登录态: 有 sessionid cookie + 特定 DOM 元素
|
||||
```
|
||||
|
||||
### 2.4 浏览器优雅管理
|
||||
|
||||
```python
|
||||
# 不要 kill -9,用正常关闭
|
||||
browser_manager = BrowserManager()
|
||||
await browser_manager.launch(account='douyin_01') # 启动
|
||||
await browser_manager.close() # 正常关闭,不走 kill
|
||||
await browser_manager.graceful_shutdown() # 先 SIGTERM,等待,再 SIGKILL
|
||||
```
|
||||
|
||||
### 2.5 蓝图新格式 (带验证锚点)
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "douyin_browse_v2",
|
||||
"version": "3.0.0",
|
||||
"steps": [
|
||||
{
|
||||
"step_id": 1,
|
||||
"op": "goto_and_verify",
|
||||
"args": {"url": "https://www.douyin.com/"},
|
||||
"verify": {"mode": "page", "anchor": "alink-item"},
|
||||
"on_fail": "retry(2)"
|
||||
},
|
||||
{
|
||||
"step_id": 2,
|
||||
"op": "open_video",
|
||||
"args": {},
|
||||
"verify": {"mode": "element", "selector": "[data-e2e='video-player-digg']"},
|
||||
"on_fail": "try_search"
|
||||
},
|
||||
{
|
||||
"step_id": 3,
|
||||
"op": "wait_watch",
|
||||
"args": {"seconds": 8},
|
||||
"verify": {"mode": "state", "field": "video_playing", "expect": true},
|
||||
"on_fail": "skip"
|
||||
},
|
||||
{
|
||||
"step_id": 4,
|
||||
"op": "like",
|
||||
"args": {},
|
||||
"verify": {"mode": "change", "selector": "[data-e2e='video-player-digg']", "attr": "class"},
|
||||
"on_fail": "log_warn"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2.6 调度器设计
|
||||
|
||||
```python
|
||||
class YanghaoOrchestrator:
|
||||
"""养号调度器"""
|
||||
|
||||
async def run(self, account_id, blueprint_id):
|
||||
"""执行一次养号"""
|
||||
# 1. 校验账号配置
|
||||
# 2. 校验蓝图
|
||||
# 3. 启动浏览器 (优雅)
|
||||
# 4. 登录校验
|
||||
# 5. 逐步骤执行 (带验证锚点)
|
||||
# 6. 生成报告
|
||||
# 7. 关闭浏览器 (优雅)
|
||||
|
||||
async def verify_login(self):
|
||||
"""多维度验证登录态"""
|
||||
# cookie: sessionid 存在
|
||||
# DOM: user-avatar 或 user-detail 可见
|
||||
# 请求: 能获取推荐内容
|
||||
```
|
||||
|
||||
### 2.7 接入 WorkBuddy 技能
|
||||
|
||||
在 `matrix/SKILL.md` 中新增触发词:
|
||||
|
||||
```yaml
|
||||
triggers:
|
||||
- 养号
|
||||
- 运行养号
|
||||
- 南方小马铃薯
|
||||
- 次元时空的桃子
|
||||
- 橙子哥
|
||||
```
|
||||
|
||||
WorkBuddy 通过 Skill 工具加载后,**由我在对话中根据你的指令自动编排执行**,而不是写死脚本。
|
||||
|
||||
### 2.8 接入 agentos CLI
|
||||
|
||||
```bash
|
||||
agentos yanghao # 交互选账号+蓝图
|
||||
agentos yanghao --account douyin_01 # 指定账号
|
||||
agentos yanghao --account douyin_01 --blueprint douyin_browse_v2 # 全指定
|
||||
agentos yanghao --list # 列出账号和蓝图
|
||||
agentos yanghao --status # 查看当前运行状态
|
||||
```
|
||||
|
||||
### 2.9 跨机恢复
|
||||
|
||||
```
|
||||
agent-sync/02_skills/matrix/ → 包含所有脚本和蓝图
|
||||
agent-local/tools/matrix/ → 账号登录态、Cookies、Profiles
|
||||
|
||||
换机流程:
|
||||
agentos init → 安装技能+目录
|
||||
agentos restore backup.tar.gz → 还原登录态
|
||||
agentos yanghao --status → 验证可用
|
||||
```
|
||||
|
||||
## 三、实施计划(建议)
|
||||
|
||||
1. **阶段1**: 设计并实现 `AtomOps` 原子操作层(含前置校验+后置锚点)
|
||||
2. **阶段2**: 实现 `BrowserManager` 优雅启停
|
||||
3. **阶段3**: 实现 `PageState` 页面状态机
|
||||
4. **阶段4**: 重写蓝图格式(v3.0.0),加入验证锚点
|
||||
5. **阶段5**: 实现 `YanghaoOrchestrator` 调度器
|
||||
6. **阶段6**: 接入 agentos CLI 和 WorkBuddy 技能
|
||||
7. **阶段7**: 全面测试三账号 + 跨机恢复
|
||||
@@ -0,0 +1,233 @@
|
||||
# Matrix 重构方案 v5 — 执行可靠性 + 智能体可调用
|
||||
|
||||
> 版本: v5.0 | 日期: 2026-06-09 | 状态: 方案阶段
|
||||
> 基于: 全项目代码审查 + AgentOS 联邦架构理解
|
||||
|
||||
---
|
||||
|
||||
## 一、目标
|
||||
|
||||
让 Matrix 养号系统达到三个标准:
|
||||
|
||||
1. **执行可靠性** — 每个操作有前后验证,结果可追踪,不误报成功
|
||||
2. **智能体可稳定调用** — 统一的 CLI + 清晰的文档,智能体不需要读源码就能用
|
||||
3. **自动化任务** — 通过 guardd 或 cron 定时执行,不依赖人工盯日志
|
||||
|
||||
---
|
||||
|
||||
## 二、当前问题根因
|
||||
|
||||
```
|
||||
核心矛盾:engine.py 的 run_single() (773行) 是一艘"独木舟"——
|
||||
自己解析蓝图、自己连浏览器、自己写 page.evaluate 执行操作、自己汇总报告。
|
||||
它绕过了系统里已有的 DouyinOps (563行) 和 AtomOps (517行),
|
||||
把调度层和操作层糊在一起,导致:
|
||||
|
||||
→ 操作执行后无验证 (like 按钮真的变色了吗?)
|
||||
→ 小红书操作零抽象 (10个 xhs_* 全是内联 evaluate)
|
||||
→ 新增平台/操作需要修改 engine.py 本身
|
||||
→ 测试一个操作 = 启动整个引擎
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、目标架构
|
||||
|
||||
```
|
||||
mc (唯一 CLI 入口)
|
||||
│
|
||||
├─ mc run → mc/engine.py (纯调度层, ~200行)
|
||||
│ │
|
||||
│ ├─ 解析参数 (accounts, blueprints, rounds)
|
||||
│ ├─ 并行调度 (asyncio.gather, 每账号一个持久浏览器)
|
||||
│ ├─ 蓝图选择 (_pick_blueprint)
|
||||
│ └─ 报告汇总 (BatchReport)
|
||||
│ │
|
||||
│ └──→ platform_ops/ (平台操作层, 每平台一个类)
|
||||
│ ├── DouyinOps — 已有 (douyin_ops.py)
|
||||
│ ├── XhsOps — 新建 (从 engine.py 提取)
|
||||
│ ├── ProfileReader — 新建 (dy_read_* 系列)
|
||||
│ └── AtomOps — 已有, 集成 pre_check/post_check
|
||||
│
|
||||
├─ mc account → matrix_mgmt.py (账号管理)
|
||||
├─ mc blueprint → matrix_mgmt.py (蓝图管理)
|
||||
├─ mc corpus → mc/corpus.py (语料库)
|
||||
└─ mc status → mc/status.py (状态查询)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、执行链路重构
|
||||
|
||||
### 现状 (engine.py run_single)
|
||||
|
||||
```python
|
||||
if op == "goto_home": ... conn.page.goto("https://www.douyin.com/") ...
|
||||
elif op == "like": ... conn.page.evaluate("querySelector...click()") ...
|
||||
elif op == "xhs_like": ... conn.page.evaluate("querySelector...click()") ... # 又写一遍
|
||||
elif op == "post_comment": ... pbcopy + evaluate + keyboard.press ...
|
||||
# 28 个 elif...
|
||||
```
|
||||
|
||||
### 目标 (调度器调用平台Ops)
|
||||
|
||||
```python
|
||||
async def run_single(self, account_id, blueprint_name, round_idx, conn=None):
|
||||
ops = PlatformOps.for_account(account_id, conn.page)
|
||||
|
||||
for step in blueprint.steps:
|
||||
result = await ops.execute(
|
||||
op=step.op,
|
||||
args=step.args,
|
||||
validate=True # ← 新增:执行后验证
|
||||
)
|
||||
report.add_step(result)
|
||||
```
|
||||
|
||||
### 平台Ops 接口
|
||||
|
||||
```python
|
||||
class PlatformOps(ABC):
|
||||
"""平台操作基类 — 智能体通过 mc 调用,不直接操作此类"""
|
||||
|
||||
async def execute(self, op: str, args: dict, validate: bool = True) -> OpResult:
|
||||
"""执行一个操作,可选验证"""
|
||||
|
||||
def supported_ops(self) -> list[str]:
|
||||
"""返回支持的操作列表"""
|
||||
```
|
||||
|
||||
每个平台类(DouyinOps, XhsOps)实现此接口。对于已验证的操作(like, collect, comment等),内部委托给 AtomOps 以复用 pre_check/post_check。
|
||||
|
||||
---
|
||||
|
||||
## 五、操作验证机制
|
||||
|
||||
复用 `atom_ops.py` 中已有的 `_execute()` 模式:
|
||||
|
||||
```
|
||||
操作执行流程 (每个步骤):
|
||||
1. pre_check() — 确认页面状态允许此操作
|
||||
├─ like: 在视频播放器页? → check "video_player" 锚点
|
||||
├─ comment: 评论区已打开? → check "comment_input" 锚点
|
||||
└─ goto_home: 总是允许
|
||||
|
||||
2. execute() — 执行操作
|
||||
|
||||
3. post_check() — 确认操作生效
|
||||
├─ like: 按钮 class 变化?
|
||||
├─ collect: 按钮状态切换?
|
||||
└─ goto_home: 页面加载完成?
|
||||
|
||||
4. 失败重试 (默认1次)
|
||||
|
||||
5. 返回结构化 OpResult { success, op, detail, elapsed, retries }
|
||||
```
|
||||
|
||||
### 验证结果的存储
|
||||
|
||||
操作结果不在 print log 中散落,而是写入结构化记录:
|
||||
|
||||
```python
|
||||
# engine.py 回调 → 写 RunLog
|
||||
class RunLog:
|
||||
account_id: str
|
||||
blueprint: str
|
||||
round: int
|
||||
steps: list[OpResult]
|
||||
started_at: datetime
|
||||
ended_at: datetime
|
||||
summary: {"success": 8, "failed": 2, "skipped": 1}
|
||||
```
|
||||
|
||||
存储位置:`agent-local/tools/matrix/logs/run_{date}_{account}.jsonl`
|
||||
|
||||
---
|
||||
|
||||
## 六、新增文件清单
|
||||
|
||||
| 文件 | 来源 | 说明 |
|
||||
|------|------|------|
|
||||
| `scripts/ops/xhs_ops.py` | **新建** | 小红书操作(从 engine.py 提取 10 个 xhs_* 操作) |
|
||||
| `scripts/ops/profile_reader.py` | **新建** | 主页信息采集(dy_read_* / xhs_read_* 系列) |
|
||||
| `scripts/ops/_base.py` | **新建** | PlatformOps 基类 + OpResult 定义 |
|
||||
| `scripts/mc/runlog.py` | **新建** | 结构化运行日志 |
|
||||
| `scripts/mc/nurture_daily.py` | **新建** | Python版每日养号编排(替代 nurture_daily.sh 对 mc 的命令行调用) |
|
||||
|
||||
## 七、修改文件清单
|
||||
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `scripts/mc/engine.py` | 从 773行 缩至 ~250行,去除全部内联 page.evaluate,改为调用 PlatformOps |
|
||||
| `scripts/mc/cli.py` | 补全子命令(account create, status accounts),支持 `--validate` flag |
|
||||
| `scripts/mc/run.py` | 简化,委托 engine.BatchEngine |
|
||||
| `scripts/douyin_ops.py` | 实现 PlatformOps 接口,集成 AtomOps 验证 |
|
||||
| `mc` (shell wrapper) | Python路径改为 `which python3`,去掉硬编码 |
|
||||
| `scripts/nurture_daily.sh` | 改为调用 `mc run` 命令 |
|
||||
| `SKILL.md` | 更新命令示例,文档状态 |
|
||||
| `TOOL.md` | 版本号统一,架构图更新 |
|
||||
|
||||
## 八、文件废弃/归档
|
||||
|
||||
| 文件 | 处理 |
|
||||
|------|------|
|
||||
| `scripts/matrix.py` | 保留但加废弃说明,所有调用改用 mc |
|
||||
| `scripts/nurture_master.sh` | 废弃,功能由 nurture_daily.sh 覆盖 |
|
||||
| 25+ 调试/测试脚本 | 移入 `scripts/_archive/` |
|
||||
| `scripts/yanghao_runner.py` | 交互模式合并到 `mc account login` |
|
||||
| `scripts/task_engine.py` | 蓝图执行功能合并到 mc/engine.py |
|
||||
| `scripts/matrix_modules/nurture/runner.py` | 废弃(1946行,功能被新engine覆盖) |
|
||||
| `scripts/camoufox_manager.py` / `camoufox_server.py` | 移入 `_archive/` |
|
||||
| `scripts/browser_manager.py` / `browser_keepalive.py` | 保留 mc/browser.py,删除重复 |
|
||||
|
||||
## 九、硬编码修复
|
||||
|
||||
| 位置 | 当前 | 修复 |
|
||||
|------|------|------|
|
||||
| `mc` shell wrapper | `/Users/5kecheng/.workbuddy/...` | `which python3` 或 `$AGENTOS_PYTHON` |
|
||||
| `matrix_mgmt.py` L32 | `/Users/chengzige/.workbuddy/...` | `Path.home() / ".workbuddy"` |
|
||||
| `nurture_master.sh` | 硬编码 Python 路径 | 改用 mc 命令 |
|
||||
| `ARCHITECTURE.md` L190 | 窗口位置硬编码 | 从 accounts.yaml 读 |
|
||||
|
||||
## 十、实施顺序
|
||||
|
||||
```
|
||||
Phase 0 (本文档) [完成] 方案设计
|
||||
Phase 1: 操作层提取 [下一步]
|
||||
1. 创建 ops/_base.py (OpResult + PlatformOps 基类)
|
||||
2. 创建 ops/xhs_ops.py (从 engine.py 提取)
|
||||
3. 创建 ops/profile_reader.py (从 engine.py 提取)
|
||||
4. douyin_ops.py 实现 PlatformOps 接口
|
||||
|
||||
Phase 2: 引擎重构
|
||||
1. engine.py 从 773行 缩至 ~250行
|
||||
2. run_single() 改为调用 PlatformOps.execute()
|
||||
3. 集成 runlog.py 结构化日志
|
||||
4. 验证:用现有账号跑一次养号,确认结果一致
|
||||
|
||||
Phase 3: CLI 统一
|
||||
1. mc 补全缺失子命令 (account create, status)
|
||||
2. mc shell wrapper 修复硬编码路径
|
||||
3. 编写 mc 命令参考手册
|
||||
|
||||
Phase 4: 脚本清理
|
||||
1. 25+ 脚本移入 _archive/
|
||||
2. 废弃文件移除
|
||||
3. .gitignore 更新
|
||||
|
||||
Phase 5: 文档
|
||||
1. SKILL.md / TOOL.md / MODULE.md 更新
|
||||
2. 所有版本号统一为 v5.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十一、不破坏的约束
|
||||
|
||||
- `agent-local/` 不动(本机数据,不同步)
|
||||
- `cross_machine/data/matrix/` 不动(联邦状态通道)
|
||||
- `blueprints/` 不动(共享蓝图,格式不变)
|
||||
- `accounts_registry.yaml` 不动
|
||||
- `install.sh` 不动(新机部署依赖它)
|
||||
- `accounts.yaml` 格式不动
|
||||
- **所有 shell 脚本的调用接口保持兼容**(nurture_daily.sh 仍然可用)
|
||||
@@ -0,0 +1,102 @@
|
||||
# 🔧 修复计划与实施报告
|
||||
|
||||
> 版本: v2.0 | 日期: 2026-05-03
|
||||
|
||||
---
|
||||
|
||||
## 实施完成清单
|
||||
|
||||
### ✅ REPAIR_PLAN 原计划
|
||||
|
||||
| 阶段 | 模块 | 状态 | 说明 |
|
||||
|---|---|---|---|
|
||||
| **P0** | cdp_connector 改造 | ✅ | 新增 `_launch_camoufox_persistent()`,支持 persistent_context + 固化指纹 |
|
||||
| **P0** | create_identity.py | ✅ | BrowserForge 指纹生成,pickle 序列化保存 |
|
||||
| **P0** | login_identity.py | ✅ | 信号文件驱动的首次登录流程 |
|
||||
| **P0** | accounts.yaml 更新 | ✅ | 三账号新增 identity_dir 字段 |
|
||||
| **P1** | yanghao_runner 改造 | ✅ 重构为 nurture/runner.py | 集成 behavior 参数化的常驻循环引擎 |
|
||||
| **P1** | run_task | ✅ 合并到 runner.py | nurture_loop 和 nurture_multi |
|
||||
| **P1** | camoufox_manager 改造 | 标记 deprecated | 功能被 matrix CLI 和登录脚本替代 |
|
||||
| **P2** | 批量创建/登录/调度 | ⏳ 骨架已搭 | 通过 matrix account create/login 实现 |
|
||||
|
||||
### ✅ 新架构 P0-P5
|
||||
|
||||
| 优先级 | 模块 | 状态 | 文件 |
|
||||
|---|---|---|---|
|
||||
| **P0** | CLI 统一入口 `matrix` | ✅ | `scripts/matrix.py` — 支持 account/nurture/config/status 四域 |
|
||||
| **P1** | nurture/behavior 行为模拟 | ✅ | `matrix_modules/nurture/behavior.py` — 13项可配置行为参数 |
|
||||
| **P2** | ops/douyin 操作层重构 | ✅ | `ops/douyin/browse.py` + `interact.py` |
|
||||
| **P3** | captcha/sms 接口预留 | ✅ | `matrix_modules/account/sms/` + `captcha/` — 抽象基类 |
|
||||
| **P4** | 蓝图编译器 | ⏳ 接口定义已完成 | blueprint loader/执行器可用,compiler 待完善 |
|
||||
| **P5** | 多平台扩展 | 📐 结构预留 | `ops/xiaohongshu/`、`ops/kuaishou/`、`ops/bilibili/` 目录已创建 |
|
||||
|
||||
---
|
||||
|
||||
## 新增文件清单
|
||||
|
||||
```
|
||||
scripts/
|
||||
├── matrix.py ← 统一 CLI 入口
|
||||
├── matrix_modules/ ← 核心模块包
|
||||
│ ├── __init__.py
|
||||
│ └── nurture/
|
||||
│ ├── behavior.py ← 行为模拟参数化
|
||||
│ └── runner.py ← 常驻循环引擎
|
||||
│ └── account/
|
||||
│ ├── sms/
|
||||
│ │ ├── __init__.py
|
||||
│ │ └── base.py ← 短信验证码抽象接口
|
||||
│ └── captcha/
|
||||
│ ├── __init__.py
|
||||
│ └── base.py ← 图形验证码抽象接口
|
||||
├── ops/ ← 操作层
|
||||
│ ├── __init__.py
|
||||
│ └── douyin/
|
||||
│ ├── __init__.py
|
||||
│ ├── browse.py ← 浏览类操作
|
||||
│ └── interact.py ← 交互类操作
|
||||
```
|
||||
|
||||
## 修改文件清单
|
||||
|
||||
```
|
||||
scripts/
|
||||
├── cdp_connector.py → 新增 _launch_camoufox_persistent() + identity_dir 参数
|
||||
├── create_identity.py → 新建(BrowserForge 指纹生成)
|
||||
└── login_identity.py → 新建(信号文件驱动登录)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 当前 CLI 使用方法
|
||||
|
||||
```bash
|
||||
# 账号管理
|
||||
matrix account list 列出账号
|
||||
matrix account create <name> 创建身份
|
||||
matrix account login <name> 首次登录
|
||||
matrix account status [name] 查看状态
|
||||
|
||||
# 养号执行
|
||||
matrix nurture run -a <name> -r 10 循环养号
|
||||
matrix nurture run -a <name1> -a <name2> 多号并发
|
||||
|
||||
# 配置管理
|
||||
matrix config show 查看全局配置
|
||||
matrix config blueprint list 列出蓝图
|
||||
matrix config blueprint show <name> 查看蓝图
|
||||
|
||||
# 状态监控
|
||||
matrix status all 全局状态
|
||||
matrix status browsers 浏览器状态
|
||||
matrix status accounts 账号状态
|
||||
```
|
||||
|
||||
## 未完成 / 待完善
|
||||
|
||||
| 项目 | 状态 | 原因 |
|
||||
|---|---|---|
|
||||
| 定时任务 schedule | 骨架 | 需与 WorkBuddy 自动化系统集成 |
|
||||
| 蓝图编译器 | 接口定义 | 需要你确认蓝图格式升级方案 |
|
||||
| 多平台扩展 | 目录预留 | 需逐个平台实现 |
|
||||
| 批量导入导出 | 概念设计 | 按需开发 |
|
||||
@@ -0,0 +1,532 @@
|
||||
# 新机部署完整指南
|
||||
|
||||
> **目标**: 在另一台 macOS (Apple Silicon) 机器上完整部署 Matrix 养号系统
|
||||
> **预估时间**: 30-60 分钟(不含首次登录各平台)
|
||||
> **适用版本**: v4.2+
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [环境准备](#1-环境准备)
|
||||
2. [同步代码](#2-同步代码)
|
||||
3. [安装依赖](#3-安装依赖)
|
||||
4. [配置账号](#4-配置账号)
|
||||
5. [首次登录](#5-首次登录)
|
||||
6. [运行养号](#6-运行养号)
|
||||
7. [日常运维](#7-日常运维)
|
||||
8. [迁移账号(从旧机)](#8-迁移账号从旧机)
|
||||
9. [故障排查](#9-故障排查)
|
||||
|
||||
---
|
||||
|
||||
## 1. 环境准备
|
||||
|
||||
| 项目 | 要求 | 检查命令 |
|
||||
|------|------|---------|
|
||||
| macOS | Apple Silicon (M1/M2/M3) | `uname -m` → `arm64` |
|
||||
| Python | 3.10+ | `python3 --version` |
|
||||
| Git | 已安装 | `git --version` |
|
||||
| Homebrew | 可选,用于安装工具 | `brew --version` |
|
||||
| 磁盘空间 | 5GB+ | `df -h ~` |
|
||||
|
||||
如果系统中没有 Python 3.10+,先安装:
|
||||
|
||||
```bash
|
||||
# 通过 Homebrew
|
||||
brew install [email protected]
|
||||
|
||||
# 或使用 pyenv
|
||||
brew install pyenv
|
||||
pyenv install 3.13.12
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 同步代码
|
||||
|
||||
```bash
|
||||
# 设定工作目录(建议与主机构一致)
|
||||
export AGENT_SYNC="$HOME/workbuddy-agent-os/agent-sync"
|
||||
export AGENT_LOCAL="$HOME/workbuddy-agent-os/agent-local"
|
||||
|
||||
# 克隆仓库(请先在本机配置好 Gitee SSH)
|
||||
git clone [email protected]:babycalf/mac-agent-os.git "$AGENT_SYNC"
|
||||
|
||||
# 切换到 matrix 目录
|
||||
cd "$AGENT_SYNC/05_tools/07_matrix"
|
||||
```
|
||||
|
||||
> **网络说明**:仓库托管在 Gitee(国内加速),如主仓库不可达请联系维护者获取同步方式。
|
||||
> 本系统使用坚果云管理 agent-local 数据(非 Git),详见下文第 8 节。
|
||||
|
||||
---
|
||||
|
||||
## 3. 安装依赖
|
||||
|
||||
### 3.1 一键安装
|
||||
|
||||
```bash
|
||||
cd "$AGENT_SYNC/05_tools/07_matrix"
|
||||
bash install.sh
|
||||
```
|
||||
|
||||
此脚本会:
|
||||
- 创建 `agent-local/tools/matrix/` 目录骨架
|
||||
- 生成 `local.yaml`(本机路径配置文件)
|
||||
- 安装 Python 依赖 (`pip install -r requirements.txt`)
|
||||
- 安装 Playwright Chromium
|
||||
- 检查账号配置
|
||||
|
||||
### 3.2 手动安装(如果 install.sh 失败)
|
||||
|
||||
```bash
|
||||
# 建目录
|
||||
mkdir -p "$AGENT_LOCAL/tools/matrix"/{config,data/cookies,profiles,logs,screenshots}
|
||||
mkdir -p "$AGENT_LOCAL/tools/matrix/data/camoufox_pids"
|
||||
mkdir -p "$AGENT_LOCAL/tools/matrix/backups/cookies"
|
||||
mkdir -p "$AGENT_LOCAL/tools/matrix/accounts"/{douyin_01,douyin_02,douyin_camo01}/{content/{raw,edited,thumbnails},scripts/{drafts,posted},publish/{queue,published},backup/cookies}
|
||||
|
||||
# 安装 Python 包
|
||||
pip install -r "$AGENT_SYNC/05_tools/07_matrix/requirements.txt"
|
||||
|
||||
# 安装 Playwright 浏览器
|
||||
python -m patchright install chromium
|
||||
|
||||
# 初始化数据库
|
||||
cd "$AGENT_SYNC/05_tools/07_matrix/scripts"
|
||||
python init_db.py
|
||||
|
||||
# 生成 local.yaml
|
||||
cat > "$AGENT_SYNC/05_tools/07_matrix/local.yaml" << EOF
|
||||
matrix:
|
||||
local_data_root: $AGENT_LOCAL/tools/matrix
|
||||
EOF
|
||||
```
|
||||
|
||||
### 3.3 安装 Camoufox
|
||||
|
||||
Camoufox 是养号系统的核心引擎(Firefox 内核反检测浏览器)。
|
||||
|
||||
```bash
|
||||
# 安装 Python 包
|
||||
pip install camoufox
|
||||
|
||||
# 下载 Camoufox 浏览器二进制(约 200MB)
|
||||
python -m camoufox fetch
|
||||
|
||||
# 验证安装
|
||||
python -c "import camoufox; print(camoufox.__version__)"
|
||||
```
|
||||
|
||||
安装完成后,Camoufox 可执行文件位于:
|
||||
```
|
||||
~/Library/Caches/camoufox/Camoufox.app/Contents/MacOS/camoufox
|
||||
```
|
||||
|
||||
### 3.4 依赖清单
|
||||
|
||||
| 包 | 版本要求 | 用途 |
|
||||
|----|---------|------|
|
||||
| `camoufox` | ≥0.4.11 | Firefox 内核反检测浏览器 |
|
||||
| `patchright` | ≥1.40 | Playwright 浏览器自动化 |
|
||||
| `browserforge` | latest | 浏览器指纹生成 |
|
||||
| `PyYAML` | ≥5.0 | YAML 配置解析 |
|
||||
| `aiofiles` | latest | 异步文件操作 |
|
||||
| `Pillow` | latest | 截图处理 |
|
||||
|
||||
完整清单见 `requirements.txt`。
|
||||
|
||||
---
|
||||
|
||||
## 4. 配置账号
|
||||
|
||||
### 4.1 复制配置模板
|
||||
|
||||
```bash
|
||||
cp "$AGENT_SYNC/05_tools/07_matrix/config_template/accounts.yaml" \
|
||||
"$AGENT_LOCAL/tools/matrix/config/accounts.yaml"
|
||||
```
|
||||
|
||||
### 4.2 编辑账号配置
|
||||
|
||||
编辑 `$AGENT_LOCAL/tools/matrix/config/accounts.yaml`,填入本机账号信息:
|
||||
|
||||
```yaml
|
||||
accounts:
|
||||
# ── 抖音账号 ──
|
||||
- id: douyin_01
|
||||
platform: douyin
|
||||
phone: "185xxxx8610" # 改为本机手机号
|
||||
identity_dir: identities/douyin_01_camo # 身份目录名
|
||||
window: [702, 783] # 窗口尺寸
|
||||
window_position: [0, 0] # 屏幕坐标(多账号防重叠)
|
||||
enabled: true
|
||||
|
||||
- id: douyin_02
|
||||
platform: douyin
|
||||
phone: "185xxxx3366"
|
||||
identity_dir: identities/douyin_02_camo
|
||||
window: [702, 783]
|
||||
window_position: [400, 0] # 紧贴 douyin_01 右侧
|
||||
enabled: true
|
||||
|
||||
- id: douyin_camo01
|
||||
platform: douyin
|
||||
phone: "153xxxx8283"
|
||||
identity_dir: identities/douyin_camo01
|
||||
window: [702, 783]
|
||||
window_position: [750, 0] # 再往右偏移
|
||||
enabled: true
|
||||
|
||||
# ── 小红书账号(共享身份目录)──
|
||||
- id: xhs_01
|
||||
platform: xiaohongshu
|
||||
phone: "185xxxx8610" # 与 douyin_01 同手机号
|
||||
identity_dir: identities/douyin_01_camo # ← 共享!
|
||||
window: [702, 783]
|
||||
window_position: [0, 800] # 抖音下方
|
||||
enabled: true
|
||||
|
||||
- id: xhs_02
|
||||
platform: xiaohongshu
|
||||
phone: "185xxxx3366"
|
||||
identity_dir: identities/douyin_02_camo # ← 共享!
|
||||
window: [702, 783]
|
||||
window_position: [400, 800]
|
||||
enabled: true
|
||||
|
||||
- id: xhs_03
|
||||
platform: xiaohongshu
|
||||
phone: "153xxxx8283"
|
||||
identity_dir: identities/douyin_camo01 # ← 共享!
|
||||
window: [702, 783]
|
||||
window_position: [750, 800]
|
||||
enabled: true
|
||||
```
|
||||
|
||||
**关键规则**:
|
||||
- `identity_dir` 决定浏览器指纹和登录态目录,同手机号不同平台应共用同一目录
|
||||
- 共享 identity_dir 时,**Cookie 保护**由 `cookie_manager.py` 自动处理
|
||||
- `window_position` 控制浏览器启动位置,避免窗口重叠
|
||||
|
||||
### 4.3 配置代理(可选)
|
||||
|
||||
如需为每个账号配置独立静态代理 IP,在账号配置中添加 `proxy` 字段:
|
||||
|
||||
```yaml
|
||||
- id: douyin_01
|
||||
...
|
||||
proxy: socks5://127.0.0.1:1080 # 可选
|
||||
```
|
||||
|
||||
详细 IP 方案见 [IP_SWITCH_GUIDE.md](./IP_SWITCH_GUIDE.md)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 首次登录
|
||||
|
||||
新机首次需要手动登录各平台账号,建立登录态。
|
||||
|
||||
### 5.1 单账号首次登录
|
||||
|
||||
```bash
|
||||
cd "$AGENT_SYNC/05_tools/07_matrix/scripts"
|
||||
python matrix.py account login douyin_01
|
||||
```
|
||||
|
||||
此命令会:
|
||||
1. 启动 Camoufox 并加载对应 identity
|
||||
2. 打开抖音登录页面
|
||||
3. 等待你手动扫码/短信登录
|
||||
4. 登录完成后回车确认 **→ session cookie 自动保存**
|
||||
|
||||
### 5.2 验证登录状态
|
||||
|
||||
```bash
|
||||
python matrix.py account status douyin_01
|
||||
# → 应显示 "已登录" 及 cookie session id
|
||||
|
||||
python matrix.py account status # 查看所有账号
|
||||
```
|
||||
|
||||
### 5.3 批量首次登录的小技巧
|
||||
|
||||
由于抖音和小红书共享 identity_dir,**先登录抖音,小红书自动复用**:
|
||||
|
||||
```
|
||||
douyin_01 登录完成 → xhs_01 自动可用
|
||||
douyin_02 登录完成 → xhs_02 自动可用
|
||||
douyin_camo01 登录完成 → xhs_03 自动可用
|
||||
```
|
||||
|
||||
所以只需要登录 3 次,覆盖 6 个账号。
|
||||
|
||||
---
|
||||
|
||||
## 6. 运行养号
|
||||
|
||||
### 6.1 快速测试
|
||||
|
||||
先单账号跑一圈,验证系统是否正常:
|
||||
|
||||
```bash
|
||||
cd "$AGENT_SYNC/05_tools/07_matrix/scripts"
|
||||
|
||||
# 抖音单账号 2 轮(约 2-3 分钟)
|
||||
python matrix.py nurture run -a douyin_01 -r 2
|
||||
```
|
||||
|
||||
观察日志 `/tmp/matrix_nurture_douyin_01.log`,确认:
|
||||
- Camoufox 浏览器启动成功
|
||||
- 进入播放页正常
|
||||
- 能滑视频
|
||||
- 评论正常
|
||||
|
||||
### 6.2 多账号并发
|
||||
|
||||
```bash
|
||||
# 抖音三账号并行 10 轮(约 15-20 分钟)
|
||||
python matrix.py nurture run \
|
||||
-a douyin_01 -a douyin_02 -a douyin_camo01 \
|
||||
-r 10 --no-daemon
|
||||
```
|
||||
|
||||
各账号日志 `/tmp/matrix_nurture_{account}.log`,实时查看:
|
||||
|
||||
```bash
|
||||
tail -f /tmp/matrix_nurture_douyin_01.log
|
||||
```
|
||||
|
||||
### 6.3 全自动主控脚本
|
||||
|
||||
```bash
|
||||
# 抖音 → 小红书 完整流程
|
||||
bash "$AGENT_SYNC/05_tools/07_matrix/scripts/nurture_master.sh"
|
||||
```
|
||||
|
||||
主控脚本执行顺序:
|
||||
1. Phase 0: 全量 Cookie 备份
|
||||
2. Phase 1: 抖音 3 账号并行(--no-daemon,完成后关浏览器)
|
||||
3. 休息 30 秒
|
||||
4. Phase 2: 小红书 3 账号并行
|
||||
|
||||
日志输出:
|
||||
- 阶段日志:`/tmp/nurture_master/{douyin|xhs}_phase.log`
|
||||
- 各账号日志:`/tmp/matrix_nurture_{account}.log`
|
||||
|
||||
### 6.4 定时任务
|
||||
|
||||
使用 cron 或 macOS launchd 设置每日自动运行:
|
||||
|
||||
```bash
|
||||
# crontab 示例(每天 10:00)
|
||||
0 10 * * * /bin/bash /path/to/nurture_master.sh >> /tmp/nurture_daily.log 2>&1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 日常运维
|
||||
|
||||
### 7.1 清理残留锁文件
|
||||
|
||||
养号异常退出后,Camoufox 可能留下 `.parentlock` 文件,导致下次启动失败:
|
||||
|
||||
```bash
|
||||
# 清理所有 identity 的锁文件
|
||||
find "$AGENT_LOCAL/tools/matrix/identities" -name ".parentlock" -delete
|
||||
```
|
||||
|
||||
建议在每次运行前执行此命令。
|
||||
|
||||
### 7.2 Cookie 备份与恢复
|
||||
|
||||
备份位置:`$AGENT_LOCAL/tools/matrix/backups/cookies/`
|
||||
|
||||
```bash
|
||||
# 手动备份所有账号
|
||||
python -c "
|
||||
from matrix_modules.utils.cookie_manager import backup_all_identities
|
||||
backup_all_identities(platform='manual', label='manual_backup')
|
||||
"
|
||||
```
|
||||
|
||||
### 7.3 查看执行报告
|
||||
|
||||
```bash
|
||||
# 查看各账号最后一轮结果
|
||||
for acct in douyin_01 douyin_02 douyin_camo01 xhs_01 xhs_02 xhs_03; do
|
||||
log="/tmp/matrix_nurture_${acct}.log"
|
||||
[ -f "$log" ] && echo "=== $acct ===" && grep "轮数:\|耗时:\|完成" "$log" | tail -2
|
||||
done
|
||||
```
|
||||
|
||||
### 7.4 更新代码
|
||||
|
||||
```bash
|
||||
cd "$AGENT_SYNC"
|
||||
git pull origin main
|
||||
```
|
||||
|
||||
如果本地有未提交的修改:
|
||||
|
||||
```bash
|
||||
git stash # 暂存本地修改
|
||||
git pull origin main
|
||||
git stash pop # 恢复本地修改
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 迁移账号(从旧机)
|
||||
|
||||
如果需要将旧机器的已登录账号迁移到新机,有两种方式:
|
||||
|
||||
### 方式 A:全量身份目录迁移(推荐)
|
||||
|
||||
将旧机器 `agent-local/tools/matrix/identities/` 下的目录打包:
|
||||
|
||||
```bash
|
||||
# 旧机器上打包
|
||||
tar czf identities_backup.tar.gz \
|
||||
-C ~/workbuddy-agent-os/agent-local/tools/matrix/identities \
|
||||
douyin_01_camo douyin_02_camo douyin_camo01
|
||||
|
||||
# 通过 U 盘/网络传至新机
|
||||
|
||||
# 新机器上解压
|
||||
tar xzf identities_backup.tar.gz \
|
||||
-C ~/workbuddy-agent-os/agent-local/tools/matrix/identities/
|
||||
```
|
||||
|
||||
迁移后**可能需要重新登录**(取决于 Cookie 时效性)。
|
||||
|
||||
### 方式 B:坚果云同步
|
||||
|
||||
如果旧机和新机都安装了坚果云,可以通过坚果云同步 `agent-local` 目录(注意排除大文件):
|
||||
|
||||
```
|
||||
坚果云同步路径: ~/NutstoreCloudBridge/matrix-identities/
|
||||
排除: *.parentlock, *.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 故障排查
|
||||
|
||||
### 9.1 Camoufox 启动失败
|
||||
|
||||
```
|
||||
错误: TargetClosedError / EPIPE
|
||||
```
|
||||
|
||||
**原因**:`.parentlock` 残留 或 Playwright driver 崩溃
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
# 清理锁文件
|
||||
find "$AGENT_LOCAL/tools/matrix/identities" -name ".parentlock" -delete
|
||||
|
||||
# 清理 Playwright 残留进程
|
||||
pkill -f "playwright"
|
||||
pkill -f "camoufox"
|
||||
```
|
||||
|
||||
### 9.2 小红书页面刷挂起
|
||||
|
||||
```
|
||||
日志卡在: "🔄 刷新瀑布流页面..."
|
||||
```
|
||||
|
||||
**原因**:XHS Page.reload 超时后协程未正常退出
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
# kill 当前进程
|
||||
# 清理锁文件后重跑
|
||||
find ... -name ".parentlock" -delete
|
||||
python matrix.py nurture run -a xhs_02 -r 10
|
||||
```
|
||||
|
||||
### 9.3 小红书 QR 码拦截墙
|
||||
|
||||
```
|
||||
日志显示: "🚫 QR码拦截墙(回退重试 1/3)"
|
||||
```
|
||||
|
||||
**原因**:账号被平台标记为非常用登录环境
|
||||
|
||||
**解决**:系统会自动 3 轮回退重试,多数情况可自行恢复。
|
||||
如果持续触发,尝试:
|
||||
1. 手动打开浏览器在该账号下正常浏览几分钟
|
||||
2. 清除 cookies 后重新登录
|
||||
3. 检查代理 IP 是否与该账号常用地一致
|
||||
|
||||
### 9.4 抖音评论触发短信验证码
|
||||
|
||||
```
|
||||
日志显示: "⏱️ SMS 验证码超时"
|
||||
```
|
||||
|
||||
**原因**:抖音检测到异常评论行为,要求短信验证
|
||||
|
||||
**解决**:
|
||||
- 暂时跳过评论(系统已自动跳过)
|
||||
- 增加养号间隔(调大 `behavior.base_delay`)
|
||||
- 换个评论内容
|
||||
|
||||
### 9.5 评论聚焦失败
|
||||
|
||||
```
|
||||
日志显示: "⚠️ 所有聚焦方式均失败 (state=panel_open)"
|
||||
```
|
||||
|
||||
**原因**:坐标偏移 / DOM 变化 / Draft.js 版本更新
|
||||
|
||||
**解决**:系统已自动跳过评论,不影响浏览养号。可尝试重新校准
|
||||
(运行 `python calibrate_input.py` 重新采集坐标)。
|
||||
|
||||
### 9.6 日志太长,不清除旧记录
|
||||
|
||||
养号系统使用追加写日志,多次运行日志会混合。如需清理:
|
||||
|
||||
```bash
|
||||
# 清理所有养号日志
|
||||
rm -f /tmp/matrix_nurture_*.log
|
||||
rm -f /tmp/nurture_master/*.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 附录:养号行为参数
|
||||
|
||||
行为参数可在 `identities/{name}/config.yaml` 中覆盖默认值:
|
||||
|
||||
```yaml
|
||||
behavior:
|
||||
base_delay: 1.5 # 操作间隔(秒)
|
||||
delay_variance: 0.8 # 随机波动范围
|
||||
attention:
|
||||
distraction_chance: 0.05 # "分心"概率
|
||||
watch_duration: [4, 12] # 观看时长(秒)
|
||||
round_break:
|
||||
min_break: 5 # 轮间最短休息(秒)
|
||||
max_break: 20 # 轮间最长休息(秒)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 附录:关键文件索引
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `scripts/matrix.py` | 统一 CLI,所有操作的入口 |
|
||||
| `scripts/nurture_master.sh` | 养号主控脚本 |
|
||||
| `scripts/matrix_modules/runner.py` | 养号循环引擎 |
|
||||
| `scripts/matrix_modules/behavior.py` | 行为参数化 |
|
||||
| `scripts/matrix_modules/utils/cookie_manager.py` | Cookie 安全 |
|
||||
| `scripts/ops/douyin/browse.py` | 抖音浏览操作 |
|
||||
| `scripts/ops/douyin/interact.py` | 抖音交互操作 |
|
||||
| `scripts/douyin_ops.py` | 抖音原子操作(旧方案) |
|
||||
| `blueprints/douyin_browse_v2.yaml` | 抖音日常浏览蓝图 |
|
||||
| `local.yaml` | 本机路径配置(每机独立) |
|
||||
@@ -0,0 +1,137 @@
|
||||
# Matrix 养号系统 — 全量状态机目录 v2.3
|
||||
|
||||
> **方法**:逐状态交互采集特征码,先列框架,你导航到我采集。
|
||||
> **目标**:每个状态有唯一特征码,不重复,不遗漏。
|
||||
|
||||
---
|
||||
|
||||
## 0. 环境变量(每次操作前必检)
|
||||
|
||||
| 环境因子 | 影响 | 检测方式 |
|
||||
|---------|------|---------|
|
||||
| 窗口宽度 | 布局、坐标 | `window.innerWidth` |
|
||||
| 窗口高度 | 布局、坐标 | `window.innerHeight` |
|
||||
| 窗口位置(left, top) | 鼠标事件路由 | `window.screenX/Y` |
|
||||
| 窗口是否激活 | 键盘/鼠标事件是否可达 | AppleScript / `document.hasFocus()` |
|
||||
| 登录态 | 是否可交互 | sessionid cookie + DOM头像 |
|
||||
| 当前URL | 页面判定基础 | `location.href` |
|
||||
| 页面title | 辅助判定 | `document.title` |
|
||||
|
||||
---
|
||||
|
||||
## 1. 状态大类(第一级分类)
|
||||
|
||||
我按"一眼就能看出来"的原则分大类。你看有没有漏的:
|
||||
|
||||
| 大类ID | 名称 | 特征(一瞥即可识别) |
|
||||
|--------|------|-------------------|
|
||||
| `BROWSER` | 浏览器层 | 浏览器启动/关闭/崩溃 |
|
||||
| `LOGIN` | 登录相关 | 登录框/扫码/验证码 |
|
||||
| `HOME` | 首页 | 精选/推荐/关注/朋友 |
|
||||
| `SEARCH` | 搜索 | 搜索结果列表/搜索播放 |
|
||||
| `PLAYER` | 视频播放 | 全屏/覆盖播放/横竖屏 |
|
||||
| `COMMENT` | 评论 | 评论面板/输入框/发送 |
|
||||
| `PROFILE` | 个人主页 | 自己/他人/作品/喜欢 |
|
||||
| `LIVE` | 直播 | 直播间 |
|
||||
| `COMPOSE` | 创作 | 发布/上传 |
|
||||
| `VERIFY` | 验证 | 短信验证码/滑块 |
|
||||
| `ERROR` | 异常 | 404/崩溃/网络断开 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 逐大类的子状态(第二级)
|
||||
|
||||
### 2.1 `BROWSER` — 浏览器层
|
||||
|
||||
| 状态码 | 名称 | 特征码 |
|
||||
|--------|------|--------|
|
||||
| `B_INIT` | 浏览器刚启动 | 无页面,`about:blank` |
|
||||
| `B_READY` | 浏览器就绪 | 抖音页面已加载 |
|
||||
| `B_CRASH` | 浏览器崩溃 | 页面无法响应 |
|
||||
| `B_LOCKED` | profile 锁冲突 | `.parentlock` 残留 |
|
||||
|
||||
### 2.2 `LOGIN` — 登录
|
||||
|
||||
| 状态码 | 名称 | 特征码 |
|
||||
|--------|------|--------|
|
||||
| `L_LOGGED_IN` | 已登录 | sessionid cookie + avatar icon |
|
||||
| `L_LOGGED_OUT` | 未登录 | 无sessionid、右上角显示"登录"按钮 |
|
||||
| `L_SCAN` | 扫码登录 | 二维码弹窗 |
|
||||
| `L_PHONE` | 手机号登录 | 输入手机号页面 |
|
||||
| `L_PASSWORD` | 密码登录 | 用户名密码输入框 |
|
||||
| `L_VERIFY_SMS` | 短信验证 | `.second-verify-panel` |
|
||||
|
||||
### 2.3 `HOME` — 首页
|
||||
|
||||
| 状态码 | 名称 | 特征码 |
|
||||
|--------|------|--------|
|
||||
| `H_JINGXUAN` | 精选页 | URL=`/jingxuan` + `.discover-tab-container` + `[data-e2e="alink-item"]` ≥ 3 |
|
||||
| `H_RECOMMEND` | 推荐页 | URL=`/ ?recommend=1` + 单列feed + `[data-e2e="alink-item"]` |
|
||||
| `H_FOLLOW` | 关注页 | URL=`/follow` + 左侧关注列表 |
|
||||
| `H_FRIEND` | 朋友页 | URL=`/friend` |
|
||||
| `H_SEARCH_INPUT` | 搜索框激活 | URL=cheng + `[data-e2e="searchbar-input"]` 聚焦 |
|
||||
|
||||
### 2.4 `SEARCH` — 搜索
|
||||
|
||||
| 状态码 | 名称 | 特征码 |
|
||||
|--------|------|--------|
|
||||
| `S_LIST` | 搜索结果列表 | URL=`/search/` + 多列卡片 `.search-result-card` |
|
||||
| `S_PLAYER` | 搜索播放页 | URL=`/search/` + video≥2 + player UI |
|
||||
| `S_FILTER` | 搜索筛选激活 | `.Bp4xnVjA`(子分类激活态) |
|
||||
|
||||
### 2.5 `PLAYER` — 视频播放
|
||||
|
||||
这是最复杂的大类,需要细拆。
|
||||
|
||||
| 状态码 | 名称 | 特征码 |
|
||||
|--------|------|--------|
|
||||
| `P_FULL` | 全屏播放 | video≥2 + URL含`/video/` 或 `modal_id` + `[data-e2e="video-player-digg"]` |
|
||||
| `P_OVERLAY` | 覆盖播放 | video=1 + `[data-e2e="video-player-digg"]` + `[class*="overlay"]` |
|
||||
| `P_MUTED` | 静音 | video.muted=true |
|
||||
| `P_PAUSED` | 暂停 | video.paused=true |
|
||||
| `P_LOOP` | 连播 | 连播按钮激活 |
|
||||
| `P_CLEAR` | 清屏模式 | 按J后的纯净模式 |
|
||||
| `P_HOME` | 作者主页 | URL=`/user/` + 从播放页跳转 |
|
||||
| `P_COLLECTION` | 合集 | 合集播放模式 |
|
||||
| `P_HASHTAG` | 话题页 | 话题标签页 |
|
||||
|
||||
### 2.6 `COMMENT` — 评论
|
||||
|
||||
| 状态码 | 名称 | 特征码 |
|
||||
|--------|------|--------|
|
||||
| `C_CLOSED` | 评论关闭 | 无 comment-list + 无 editor |
|
||||
| `C_PANEL` | 评论面板打开 | `[data-e2e="comment-list"]` 可见 + `.public-DraftEditor-content` 存在 |
|
||||
| `C_INPUT_FOCUSED` | 输入框聚焦 | `C_PANEL` + activeElement=editor + 光标闪烁 |
|
||||
| `C_TEXT_ENTERED` | 文字已输入 | `C_INPUT_FOCUSED` + editor.textContent>0 + 发送按钮可见 |
|
||||
| `C_SENT` | 已发送 | comment-list 含刚发文本 |
|
||||
| `C_VERIFY` | 验证码触发 | `.second-verify-panel` |
|
||||
| `C_LIST_SCROLL` | 正在滚动评论列表 | 评论列表滚动条位置变化 |
|
||||
|
||||
### 2.7 `PROFILE` — 个人主页
|
||||
|
||||
| 状态码 | 名称 | 特征码 |
|
||||
|--------|------|--------|
|
||||
| `P_SELF` | 我的主页 | URL=`/user/self` + `[data-e2e="user-detail"]` |
|
||||
| `P_OTHER` | 他人主页 | URL=`/user/` + `[data-e2e="user-detail"]` |
|
||||
| `P_POSTS` | 作品Tab | 作品Tab激活 |
|
||||
| `P_LIKES` | 喜欢Tab | 喜欢Tab激活 |
|
||||
| `P_COLLECTS` | 收藏Tab | 收藏Tab激活 |
|
||||
| `P_HISTORY` | 历史Tab | 历史Tab激活 |
|
||||
|
||||
### 2.8 其他
|
||||
|
||||
| 状态码 | 名称 | 特征码 |
|
||||
|--------|------|--------|
|
||||
| `V_SMS` | 短信验证码 | `.second-verify-panel` + `input[placeholder*="验证码"]` |
|
||||
| `V_SLIDE` | 滑块验证 | 滑块组件可见 |
|
||||
| `E_404` | 404 | 页面含404 |
|
||||
| `E_TIMEOUT` | 超时 | 页面加载超时 |
|
||||
| `E_BLOCKED` | 被拦截 | 反爬页面/访问限制 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 下一阶段:交互采集特征码
|
||||
|
||||
框架搭完了,你看 2.1~2.8 还有没有漏的大类或子状态?
|
||||
|
||||
确认框架没问题后,我们一个一个状态来采集:你导航到那个状态,我读特征码,你确认对不对。先从最简单的 `H_JINGXUAN`(精选页)开始?
|
||||
@@ -0,0 +1,96 @@
|
||||
# MC 系统改造任务清单
|
||||
|
||||
> 开始: 2026-06-14 | 状态: 进行中
|
||||
> 目标: 连夜完成全链路改造
|
||||
|
||||
---
|
||||
|
||||
## 第一阶段: CLI 命令统一 (1-2天) ← 现在开始
|
||||
|
||||
### 1.1 清理归档遗留脚本
|
||||
- [ ] 建 `scripts/archive/` 目录
|
||||
- [ ] 识别可归档脚本 (测试/调试/不再使用的)
|
||||
- [ ] 移动归档, 保留核心 15 个脚本
|
||||
- [ ] 建 `LEGACY_INDEX.md` 说明归档内容
|
||||
|
||||
### 1.2 规范 mc 命令入口
|
||||
- [ ] 检查现有 `mc` 入口 (scripts/mc/ 目录)
|
||||
- [ ] 包装 `mc collect` (调 collect_batch_runner)
|
||||
- [ ] 包装 `mc login` (调 login_identity)
|
||||
- [ ] 包装 `mc sms` (调 sms API)
|
||||
- [ ] 包装 `mc status` (调 matrix_mgmt)
|
||||
- [ ] 所有命令支持 `--json` 输出
|
||||
|
||||
### 1.3 mc status --json 完善
|
||||
- [ ] 返回所有账号状态 + 采集时间 + 各平台信息
|
||||
- [ ] 供 Dashboard 直接消费
|
||||
|
||||
---
|
||||
|
||||
## 第二阶段: 平台插件化 (3-5天)
|
||||
|
||||
### 2.1 建插件框架
|
||||
- [ ] 建 `platforms/` 根目录
|
||||
- [ ] 实现 `base.py` 基类 (BasePlatform)
|
||||
- [ ] 实现插件自动发现 (`__init__.py`)
|
||||
- [ ] mc 自动加载已注册插件
|
||||
|
||||
### 2.2 抖音插件
|
||||
- [ ] 创建 `platforms/douyin/`
|
||||
- [ ] 迁移采集逻辑 (现 collect_batch_runner 中的抖音部分)
|
||||
- [ ] 迁移养号逻辑 (现 nurture_blueprint)
|
||||
- [ ] 创建 SKILL.md
|
||||
|
||||
### 2.3 小红书插件
|
||||
- [ ] 创建 `platforms/xiaohongshu/`
|
||||
- [ ] 迁移采集逻辑
|
||||
- [ ] 修复"我"按钮点击问题
|
||||
- [ ] 创建 SKILL.md
|
||||
|
||||
---
|
||||
|
||||
## 第三阶段: 接入开源生态 (1周)
|
||||
|
||||
### 3.1 发布功能集成
|
||||
- [ ] 集成 social-auto-upload 的 douyin_uploader
|
||||
- [ ] 集成 social-auto-upload 的 xiaohongshu_uploader
|
||||
- [ ] 包装为 `mc douyin publish` / `mc xhs publish`
|
||||
|
||||
### 3.2 搜索互动集成
|
||||
- [ ] 集成 xiaohongshu-mcp
|
||||
- [ ] 包装为 `mc xhs search` / `mc xhs interact`
|
||||
|
||||
### 3.3 反检测升级
|
||||
- [ ] 引入高斯抖动 (dy-cli 策略)
|
||||
- [ ] 引入指数退避
|
||||
|
||||
---
|
||||
|
||||
## 第四阶段: 联邦多机 + 持续扩展
|
||||
|
||||
### 4.1 guardd 改造 (已完成 ✅)
|
||||
- [x] guardd.py: 心跳数据改写到 agent-local/runtime/guardd/
|
||||
- [x] 注释掉 _git_sync() 调用, 不再提交 Gitee
|
||||
- [x] .gitignore: 加入 04_memory/cross_machine/data/
|
||||
- [x] git rm --cached: 清除 78 个历史心跳文件
|
||||
- [x] Dashboard guardd 插件: 新增读本机 guardd 状态
|
||||
- [x] 兼容旧 cross_machine/data/ 数据
|
||||
|
||||
### 4.2 Tailscale + mc remote (已完成 ✅)
|
||||
- [x] app.py: 新增 /api/machine/status 端点 (本机完整状态)
|
||||
- [x] app.py: 新增 /api/machine/exec 端点 (远程执行 mc 命令)
|
||||
- [x] mc CLI: 新增 remote 子命令 (list/ping/status/exec)
|
||||
- [x] 支持 HTTP API 和 SSH 双通道通信
|
||||
- [x] 代理绕过: requests 库绕过 SOCKS5 代理
|
||||
- [x] 机器注册表: agent-local/runtime/machines.json
|
||||
- [x] 文档 FRAMEWORK_V1.md 已更新
|
||||
- [ ] 安装 Tailscale: `brew install tailscale && tailscale up`
|
||||
|
||||
### 4.3 Dashboard 合并
|
||||
- [ ] 把 matrix_mgmt.html 功能迁移到 index.html
|
||||
- [ ] 统一侧边栏导航
|
||||
- [ ] 去重账号列表
|
||||
|
||||
### 4.4 历史版本化
|
||||
- [ ] 每次采集存历史快照
|
||||
- [ ] Dashboard 加趋势图表
|
||||
@@ -0,0 +1,113 @@
|
||||
# Matrix 养号系统全面测试报告
|
||||
|
||||
> **测试时间**: 2026-04-30 16:48:37
|
||||
> **测试蓝图**: douyin_browse_v2, douyin_search_browse
|
||||
> **测试账号**: douyin_01, douyin_02
|
||||
|
||||
---
|
||||
|
||||
## 测试总览
|
||||
|
||||
| 指标 | 值 |
|
||||
|------|-----|
|
||||
| 总测试数 | 4 |
|
||||
| 通过数 | 0 |
|
||||
| 失败数 | 4 |
|
||||
| 通过率 | 0% |
|
||||
|
||||
## 按账号汇总
|
||||
|
||||
| 账号 | 蓝图 | 登录 | 步骤通过 | 总步骤 | 耗时 | 结果 |
|
||||
|------|------|------|---------|--------|------|------|
|
||||
| douyin_01 | douyin_browse_v2 | ❌ | 7 | 11 | 104.6s | ❌ |
|
||||
| douyin_01 | douyin_search_browse | ❌ | 4 | 7 | 78.6s | ❌ |
|
||||
| douyin_02 | douyin_browse_v2 | ❌ | 8 | 11 | 113.0s | ❌ |
|
||||
| douyin_02 | douyin_search_browse | ❌ | 6 | 7 | 76.7s | ❌ |
|
||||
|
||||
## 详细步骤结果
|
||||
|
||||
### douyin_01 / douyin_browse_v2
|
||||
|
||||
| 步骤 | 操作 | 参数 | 结果 | 耗时 | 错误 |
|
||||
|------|------|------|------|------|------|
|
||||
| 1 | goto_home | {} | ❌ | 28000ms | 视频加载超时 |
|
||||
| 2 | wait_watch | {'seconds': 8} | ✅ | 8000ms | |
|
||||
| 3 | like | {'probability': 0.4} | ❌ | 100ms | DouyinOps.like() got an unexpected keyword argument 'probability' |
|
||||
| 4 | next_video | {} | ✅ | 4000ms | |
|
||||
| 5 | wait_watch | {'seconds': 12} | ✅ | 12000ms | |
|
||||
| 6 | collect | {'probability': 0.15} | ❌ | 100ms | DouyinOps.collect() got an unexpected keyword argument 'probability' |
|
||||
| 7 | next_video | {} | ✅ | 4000ms | |
|
||||
| 8 | wait_watch | {'seconds': 10} | ✅ | 10000ms | |
|
||||
| 9 | like | {'probability': 0.3} | ❌ | 100ms | DouyinOps.like() got an unexpected keyword argument 'probability' |
|
||||
| 10 | next_video | {} | ✅ | 4000ms | |
|
||||
| 11 | wait_watch | {'seconds': 15} | ✅ | 15000ms | |
|
||||
|
||||
### douyin_01 / douyin_search_browse
|
||||
|
||||
| 步骤 | 操作 | 参数 | 结果 | 耗时 | 错误 |
|
||||
|------|------|------|------|------|------|
|
||||
| 1 | goto_home | {} | ✅ | 12000ms | |
|
||||
| 2 | search | {'keyword': '${SEARCH_KEYWORD}'} | ❌ | 7000ms | SEARCH_KEYWORD 未替换,搜索无效 |
|
||||
| 3 | click_search_result | {'index': 0} | ❌ | 3000ms | 不在搜索结果页 |
|
||||
| 4 | wait_watch | {'seconds': 10} | ✅ | 10000ms | |
|
||||
| 5 | like | {'probability': 0.5} | ❌ | 100ms | DouyinOps.like() got an unexpected keyword argument 'probability' |
|
||||
| 6 | go_back | {} | ✅ | 5000ms | |
|
||||
| 7 | goto_home | {} | ✅ | 13000ms | |
|
||||
|
||||
### douyin_02 / douyin_browse_v2
|
||||
|
||||
| 步骤 | 操作 | 参数 | 结果 | 耗时 | 错误 |
|
||||
|------|------|------|------|------|------|
|
||||
| 1 | goto_home | {} | ✅ | 30000ms | |
|
||||
| 2 | wait_watch | {'seconds': 8} | ✅ | 8000ms | |
|
||||
| 3 | like | {'probability': 0.4} | ❌ | 100ms | DouyinOps.like() got an unexpected keyword argument 'probability' |
|
||||
| 4 | next_video | {} | ✅ | 4000ms | |
|
||||
| 5 | wait_watch | {'seconds': 12} | ✅ | 12000ms | |
|
||||
| 6 | collect | {'probability': 0.15} | ❌ | 100ms | DouyinOps.collect() got an unexpected keyword argument 'probability' |
|
||||
| 7 | next_video | {} | ✅ | 4000ms | |
|
||||
| 8 | wait_watch | {'seconds': 10} | ✅ | 10000ms | |
|
||||
| 9 | like | {'probability': 0.3} | ❌ | 100ms | DouyinOps.like() got an unexpected keyword argument 'probability' |
|
||||
| 10 | next_video | {} | ✅ | 4000ms | |
|
||||
| 11 | wait_watch | {'seconds': 15} | ✅ | 15000ms | |
|
||||
|
||||
### douyin_02 / douyin_search_browse
|
||||
|
||||
| 步骤 | 操作 | 参数 | 结果 | 耗时 | 错误 |
|
||||
|------|------|------|------|------|------|
|
||||
| 1 | goto_home | {} | ✅ | 23000ms | |
|
||||
| 2 | search | {'keyword': '${SEARCH_KEYWORD}'} | ✅ | 9000ms | |
|
||||
| 3 | click_search_result | {'index': 0} | ✅ | 6000ms | |
|
||||
| 4 | wait_watch | {'seconds': 10} | ✅ | 10000ms | |
|
||||
| 5 | like | {'probability': 0.5} | ❌ | 100ms | DouyinOps.like() got an unexpected keyword argument 'probability' |
|
||||
| 6 | go_back | {} | ✅ | 3000ms | |
|
||||
| 7 | goto_home | {} | ✅ | 12000ms | |
|
||||
|
||||
## 问题分析与改进建议
|
||||
|
||||
| 严重度 | 类别 | 账号 | 问题 | 改进建议 |
|
||||
|--------|------|------|------|---------|
|
||||
| P1 | 登录 | douyin_01 | douyin_01 未登录,部分互动操作可能受限 | 手动登录该账号,或使用 --export-cookies 导出后切换 |
|
||||
| P0 | 操作失败 | douyin_01 | 步骤 1 [goto_home] 失败: 视频加载超时 | 需要进一步调查 |
|
||||
| P1 | 操作失败 | douyin_01 | 步骤 3 [like] 失败: DouyinOps.like() got an unexpected keyword argument 'probability' | 需要进一步调查 |
|
||||
| P1 | 操作失败 | douyin_01 | 步骤 6 [collect] 失败: DouyinOps.collect() got an unexpected keyword argument 'probability' | 需要进一步调查 |
|
||||
| P1 | 操作失败 | douyin_01 | 步骤 9 [like] 失败: DouyinOps.like() got an unexpected keyword argument 'probability' | 需要进一步调查 |
|
||||
| P1 | 登录 | douyin_01 | douyin_01 未登录,部分互动操作可能受限 | 手动登录该账号,或使用 --export-cookies 导出后切换 |
|
||||
| P0 | 操作失败 | douyin_01 | 步骤 2 [search] 失败: SEARCH_KEYWORD 未替换,搜索无效 | 需要进一步调查 |
|
||||
| P1 | 操作失败 | douyin_01 | 步骤 3 [click_search_result] 失败: 不在搜索结果页 | 需要进一步调查 |
|
||||
| P1 | 操作失败 | douyin_01 | 步骤 5 [like] 失败: DouyinOps.like() got an unexpected keyword argument 'probability' | 需要进一步调查 |
|
||||
| P1 | 登录 | douyin_02 | douyin_02 未登录,部分互动操作可能受限 | 手动登录该账号,或使用 --export-cookies 导出后切换 |
|
||||
| P1 | 操作失败 | douyin_02 | 步骤 3 [like] 失败: DouyinOps.like() got an unexpected keyword argument 'probability' | 需要进一步调查 |
|
||||
| P1 | 操作失败 | douyin_02 | 步骤 6 [collect] 失败: DouyinOps.collect() got an unexpected keyword argument 'probability' | 需要进一步调查 |
|
||||
| P1 | 操作失败 | douyin_02 | 步骤 9 [like] 失败: DouyinOps.like() got an unexpected keyword argument 'probability' | 需要进一步调查 |
|
||||
| P1 | 登录 | douyin_02 | douyin_02 未登录,部分互动操作可能受限 | 手动登录该账号,或使用 --export-cookies 导出后切换 |
|
||||
| P1 | 操作失败 | douyin_02 | 步骤 5 [like] 失败: DouyinOps.like() got an unexpected keyword argument 'probability' | 需要进一步调查 |
|
||||
|
||||
## 系统级检查
|
||||
|
||||
| 检查项 | 状态 | 说明 |
|
||||
|--------|------|------|
|
||||
| Chrome 版本 | ✅ | Google Chrome 147.0.7727.138 |
|
||||
| Patchright | ❌ | 未安装 |
|
||||
| 数据库 | ✅ | /Users/chengzige/workbuddy-agent-os/agent-local/tools/matrix/data/matrix.db |
|
||||
| 蓝图 douyin_browse_v2 | ✅ | /Users/chengzige/workbuddy-agent-os/agent-sync/05_tools/07_matrix/blueprints/douyin_browse_v2.json |
|
||||
| 蓝图 douyin_search_browse | ✅ | /Users/chengzige/workbuddy-agent-os/agent-sync/05_tools/07_matrix/blueprints/douyin_search_browse.json |
|
||||
@@ -0,0 +1,235 @@
|
||||
# Matrix 系统全面升级规划框架 v6.0
|
||||
|
||||
> 日期: 2026-06-14 | 状态: 规划阶段
|
||||
> 本文件定义全部需求,拆解为可执行的任务清单
|
||||
|
||||
---
|
||||
|
||||
## 一、身份与账号 → 主页信息增强
|
||||
|
||||
### 现状
|
||||
profiles.json 已采集 `fans`、`posts`、`following`、`likes` 字段,但前端卡片未展示。
|
||||
|
||||
### 改动
|
||||
在身份与账号页面的平台行中增加:
|
||||
```
|
||||
🎵 抖音 ✅ ✅ ✅ 2次 小美养生茶 📊1.1k粉 📹11作 🔑 🚫 🗑
|
||||
```
|
||||
|
||||
在 `api_sms_accounts` 返回数据中透传 `fans`、`posts`、`following`、`likes` 字段。
|
||||
|
||||
---
|
||||
|
||||
## 二、命令与任务 → 信息采集模块重构
|
||||
|
||||
### 当前问题
|
||||
- 页面太简单,只有一个下拉+两个按钮
|
||||
- 只能按账号选,不能按身份/身份的平台选
|
||||
|
||||
### 目标结构
|
||||
|
||||
```
|
||||
┌─ 👤 信息采集 ──────────────────────────────────┐
|
||||
│ │
|
||||
│ 选择范围: [按身份 ▾] [按平台 ▾] [按账号 ▾] │
|
||||
│ │
|
||||
│ ┌─ 可选列表(按选择范围动态展示)───────────────┐ │
|
||||
│ │ ☑ 📱 15370103682 │ │
|
||||
│ │ ├ ☑ 🎵 抖音 (小美养生茶) │ │
|
||||
│ │ └ ☐ 📕 小红书 (xhs_01) │ │
|
||||
│ │ ☐ 📱 13382504284 │ │
|
||||
│ │ └ ☐ 🎵 抖音 (douyin_133) │ │
|
||||
│ └──────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [👤 执行选中] [📋 全部采集] │
|
||||
│ │
|
||||
│ 采集日志: │
|
||||
│ ✅ douyin_test 采集完成 → 小美养生茶(1.1k粉) │
|
||||
│ ⏳ xhs_01 采集中... │
|
||||
└───────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 采集范围切换逻辑
|
||||
- **按身份**:显示手机号列表,勾选后该身份下所有平台都采集
|
||||
- **按平台**:显示抖音/小红书列表,勾选后所有该平台的账号都采集
|
||||
- **按账号**:显示所有账号列表(当前方式)
|
||||
|
||||
---
|
||||
|
||||
## 三、定时任务 → 完整可执行系统
|
||||
|
||||
### 当前状态
|
||||
`mc/scheduler.py` 已实现:
|
||||
- YAML 配置读取
|
||||
- cron 表达式支持(`time: "09:00"` 格式)
|
||||
- 自动执行 mc run 命令
|
||||
- 日志记录
|
||||
|
||||
**缺少的**:
|
||||
- Dashboard 创建/编辑/启停管理
|
||||
- 历史执行记录
|
||||
- 执行结果回传(成功/失败)
|
||||
- 跨机器独立运行
|
||||
- 命令行 mc schedule 完整子命令
|
||||
|
||||
### 目标架构
|
||||
|
||||
```
|
||||
┌─ 定时任务系统 ───────────────────────────────────┐
|
||||
│ │
|
||||
│ 配置层:config/schedule.yaml │
|
||||
│ schedules: │
|
||||
│ douyin_daily: │
|
||||
│ enabled: true │
|
||||
│ account: douyin_test │
|
||||
│ blueprint: douyin_daily │
|
||||
│ rounds: 3 │
|
||||
│ time: "09:00" │
|
||||
│ days: "1,2,3,4,5,6,7" # 每周运行日 │
|
||||
│ │
|
||||
│ 调度层:mc/scheduler.py │
|
||||
│ - 30秒轮询检查 │
|
||||
│ - 到达时间→执行 mc run │
|
||||
│ - 记录结果到 logs/schedule_{date}.jsonl │
|
||||
│ │
|
||||
│ 管理层:Dashboard │
|
||||
│ - 任务列表(显示/编辑/删除/启停) │
|
||||
│ - 历史记录(最近20次执行结果) │
|
||||
│ - 手动触发执行 │
|
||||
│ │
|
||||
│ CLI层:mc schedule │
|
||||
│ mc schedule list │
|
||||
│ mc schedule add --id xxx ... │
|
||||
│ mc schedule remove --id xxx │
|
||||
│ mc schedule start/stop │
|
||||
│ mc schedule history --id xxx │
|
||||
└────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 执行结果记录格式
|
||||
```jsonl
|
||||
{"id":"douyin_daily","time":"09:00","date":"2026-06-14","status":"success","success":12,"failed":1,"duration":180}
|
||||
{"id":"douyin_daily","time":"09:00","date":"2026-06-15","status":"failed","error":"Cookie expired","duration":5}
|
||||
```
|
||||
|
||||
### 跨机器执行
|
||||
- 每台机器独立运行 scheduler.py
|
||||
- 从本地 accounts.yaml 读取账号
|
||||
- 使用本地 profiles.json
|
||||
- 结果写入本地 logs/
|
||||
|
||||
---
|
||||
|
||||
## 四、语料库 → 全面升级 + 移到命令与任务
|
||||
|
||||
### 当前结构(v1.x)
|
||||
```yaml
|
||||
categories:
|
||||
赞美:
|
||||
comments: ["讲得太好了"]
|
||||
templates: ["{keyword}很好"]
|
||||
```
|
||||
|
||||
### 目标结构(v2.0)
|
||||
```yaml
|
||||
version: "2.0"
|
||||
|
||||
# 三维语料模型:身份 × 场景 × 内容
|
||||
personas:
|
||||
health_lover:
|
||||
name: "养生爱好者"
|
||||
tags: ["养生", "健康"]
|
||||
|
||||
scenes:
|
||||
first_comment:
|
||||
label: "首次评论"
|
||||
rules: ["与视频内容相关"]
|
||||
follow_up:
|
||||
label: "跟帖回复"
|
||||
rounds: 2
|
||||
|
||||
content:
|
||||
health_lover.first_comment:
|
||||
- "这个养生方法很实用"
|
||||
health_lover.follow_up.round_1:
|
||||
- "确实如此,{keyword}我也是这么认为的"
|
||||
|
||||
# AI 生成配置
|
||||
ai:
|
||||
provider: openai
|
||||
model: gpt-4o-mini
|
||||
temperature: 0.8
|
||||
prompt_template: |
|
||||
你是一个{persona},请对视频"{title}"发表{direction}评论。
|
||||
要求:{rules}
|
||||
|
||||
# 故事线/对话脚本
|
||||
storylines:
|
||||
douyin_hot_topic:
|
||||
name: "抖音热门话题讨论"
|
||||
script:
|
||||
- scene: intro
|
||||
text: "最近{keyword}这个事我也关注了"
|
||||
- scene: develop
|
||||
text: "其实这个事情要从几个方面看..."
|
||||
- scene: reply_expected
|
||||
text: "你觉得呢?"
|
||||
```
|
||||
|
||||
### Dashboard 语料库管理
|
||||
```
|
||||
命令与任务 → 语料库 TAB
|
||||
├─ TAB: 按身份 — 选择身份→查看/编辑评论模板
|
||||
├─ TAB: 按场景 — 首次评论/跟帖回复/作者回复
|
||||
├─ TAB: 按故事线 — 创建/编辑对话脚本
|
||||
├─ TAB: AI 生成 — 配置 API Key/模型/提示词模板
|
||||
└─ TAB: 统计 — 语料总量/各分类数量/使用频率
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、批量执行 → 自动刷新 + 参数完整性
|
||||
|
||||
### 当前状态
|
||||
- 账号列表:每次 `loadMatrixRun` 调用时从 API 获取 ✅ 自动更新
|
||||
- 蓝图列表:同上 ✅ 自动更新
|
||||
- 执行参数:轮数/轮间隔/账号间延迟/混合随机/语料分类/代理策略
|
||||
|
||||
### 需要确认的
|
||||
| 参数 | 状态 |
|
||||
|------|------|
|
||||
| --accounts | ✅ 自动从 API 获取 |
|
||||
| --blueprints | ✅ 自动从 API 获取 |
|
||||
| --rounds | ✅ 有 |
|
||||
| --interval | ✅ 有 |
|
||||
| --stagger | ✅ 有(新增) |
|
||||
| --mix | ✅ 有 |
|
||||
| --corpus | ✅ 有(但需确认是否生效) |
|
||||
| --proxy | ✅ 有 |
|
||||
| --keep | ❌ 预览和执行都缺少 |
|
||||
|
||||
### 修复
|
||||
- `--keep` 参数在 `batchPreview` 和 `batchExecute` 中补全
|
||||
|
||||
---
|
||||
|
||||
## 六、实施路线
|
||||
|
||||
| 阶段 | 内容 | 优先级 | 工作量 |
|
||||
|------|------|--------|--------|
|
||||
| P1 | 身份与账号增加粉丝/视频数展示 | 高 | 0.5天 |
|
||||
| P2 | 信息采集模块重构(三维选择) | 高 | 1天 |
|
||||
| P3 | 定时任务完善(历史+结果+管理) | 高 | 2天 |
|
||||
| P4 | 语料库 v2 + Dashboard 管理 | 中 | 3天 |
|
||||
| P5 | 批量执行参数补全 + 自动刷新 | 中 | 0.5天 |
|
||||
| P6 | 同步文档 + 其他机器部署 | 高 | 1天 |
|
||||
|
||||
---
|
||||
|
||||
## 七、风险与依赖
|
||||
|
||||
| 风险 | 影响 | 缓解 |
|
||||
|------|------|------|
|
||||
| scheduler.py 当前只解析 time,不支持 cron 全语法 | 定时灵活性 | 先保持 time 格式兼容,后续扩展 |
|
||||
| profiles.json 中粉丝/视频数据可能为空(未采集) | 展示不全 | 为空时显示"-",提示用户采集 |
|
||||
| 语料库 v2 格式与 v1 不兼容 | 旧语料不可用 | 代码兼容两种格式 |
|
||||
Reference in New Issue
Block a user