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,181 @@
|
||||
# Matrix 养号系统 — 系统架构设计
|
||||
|
||||
> **版本**:v2.1.0
|
||||
> **最后更新**:2026-05-01
|
||||
> **设计原则**:原子化可复用 → 固化不反复 → 全链路串接
|
||||
|
||||
---
|
||||
|
||||
## 1. 整体架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 用户触发(对话/定时) │
|
||||
└─────────────────┬───────────────────────────┬───────────────┘
|
||||
│ │
|
||||
┌───────▼───────┐ ┌─────────▼────────┐
|
||||
│ yanghao_runner.py │ │ task_scheduler.py │
|
||||
│ (手动/交互入口) │ │ (定时任务入口) │
|
||||
└───────┬───────┘ └─────────┬────────┘
|
||||
│ │
|
||||
└──────────┬────────────────┘
|
||||
│
|
||||
┌────────▼────────┐
|
||||
│ CDPConnector │
|
||||
│ (浏览器连接层) │
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌──────────────┼──────────────┐
|
||||
│ │ │
|
||||
┌───────▼──────┐ ┌────▼────┐ ┌───────▼──────┐
|
||||
│ Chrome CDP │ │Camoufox │ │ auth_manager │
|
||||
│ (端口 9222+) │ │原生 API │ │ (登录管理) │
|
||||
└───────┬──────┘ └────┬────┘ └───────┬──────┘
|
||||
│ │ │
|
||||
└──────┬───────┘ │
|
||||
│ │
|
||||
┌──────▼──────┐ ┌─────────▼────────┐
|
||||
│ DouyinOps │ │ Cookie 文件 │
|
||||
│ (原子操作库) │ │ (持久化存储) │
|
||||
└──────┬──────┘ └─────────────────┘
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│ 蓝图引擎 │
|
||||
│ task_engine │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 原子化模块清单
|
||||
|
||||
| 模块 | 文件 | 职责 | 依赖 |
|
||||
|------|------|------|------|
|
||||
| **auth_manager** | `scripts/auth_manager.py` | 登录检测、Cookie 导出/注入、等待登录 | 无(纯函数 + Playwright API) |
|
||||
| **cdp_connector** | `scripts/cdp_connector.py` | 浏览器连接(Chrome CDP / Camoufox 原生) | auth_manager(登录检测) |
|
||||
| **douyin_ops** | `scripts/douyin_ops.py` | 抖音原子操作(18个:like/collect/comment/scroll等) | Playwright Page |
|
||||
| **local_paths** | `scripts/local_paths.py` | 统一路径管理 | 无 |
|
||||
| **page_state** | `scripts/page_state.py` | 页面模式检测、状态建议 | Playwright Page |
|
||||
| **task_engine** | `scripts/task_engine.py` | 蓝图加载与逐步执行 | douyin_ops |
|
||||
| **yanghao_runner** | `scripts/yanghao_runner.py` | 完整养号流程入口(交互/参数双模式) | cdp_connector + douyin_ops |
|
||||
| **switch_account** | `scripts/switch_account.py` | 账号切换、状态查看 | auth_manager |
|
||||
| **full_test** | `scripts/full_test.py` | 全面测试 + 报告生成 | task_engine + auth_manager |
|
||||
|
||||
---
|
||||
|
||||
## 3. 登录管理(auth_manager 原子操作)
|
||||
|
||||
### 3.1 检测流程
|
||||
|
||||
```
|
||||
get_login_status(context, page)
|
||||
│
|
||||
├── Cookie 检测(主方案)
|
||||
│ ├── 遍历所有 Cookie
|
||||
│ ├── 检查 sessionid / sid_guard 是否存在
|
||||
│ └── 返回 cookie_ok + cookie_count + session_id
|
||||
│
|
||||
└── DOM 检测(备选,仅移动端视口有效)
|
||||
├── 检查 [data-e2e='user-avatar']
|
||||
├── 检查 [data-e2e='user-detail']
|
||||
└── 返回 dom_ok
|
||||
|
||||
└── 综合判断
|
||||
├── cookie_ok + dom_ok → logged_in=True, method="both"
|
||||
├── cookie_ok only → logged_in=True, method="cookie"
|
||||
├── dom_ok only → logged_in=True, method="dom"
|
||||
└── 均无 → logged_in=False
|
||||
```
|
||||
|
||||
### 3.2 可用 API
|
||||
|
||||
| 函数 | 用途 | 返回 |
|
||||
|------|------|------|
|
||||
| `check_login_by_cookie(context)` | Cookie 检测 | bool |
|
||||
| `check_login_by_dom(page, platform)` | DOM 检测 | bool |
|
||||
| `get_login_status(context, page)` | 多维综合检测 | dict |
|
||||
| `export_cookies(context, path)` | 导出 Cookie | int(数量) |
|
||||
| `inject_cookies(context, path)` | 注入 Cookie | int(数量) |
|
||||
| `wait_for_login(context, page)` | 等待手动登录 | dict |
|
||||
| `get_session_id(cookies)` | 提取 sessionid | str/None |
|
||||
|
||||
### 3.3 持久化策略
|
||||
|
||||
```
|
||||
Chrome 方案:Profile 目录持久化(浏览器关闭重启后 Cookie 自动保留)
|
||||
↓
|
||||
首次切换/登录后 → auth_manager.export_cookies() → data/cookies/{id}_cookies.json
|
||||
↓
|
||||
Camoufox 启动时 → auth_manager.inject_cookies() → 从 Cookie 文件恢复登录
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 浏览器方案对比
|
||||
|
||||
| 维度 | Chrome CDP | Camoufox (Firefox) |
|
||||
|------|-----------|-------------------|
|
||||
| 启动入口 | `switch_account.py --method profile` | `CDPConnector(browser_type="camoufox")` |
|
||||
| 登录方式 | Chrome Profile 持久化(自动) | Cookie 注入(从文件) |
|
||||
| 登录检测 | auth_manager Cookie 检测 | auth_manager Cookie 检测 |
|
||||
| 操作系统指纹 | 实际 macOS(CDP 覆盖 UA) | 固定 Windows(`os='windows'`) |
|
||||
| 中文字体 | 系统自带 | 需指定 fonts 参数 |
|
||||
| 反检测 | CDP 指纹注入 + JS 注入 | Camoufox 内置 + humanize |
|
||||
| 适用场景 | 主力养号(doyin_01/02) | 辅助养号(douyin_camo01/02) |
|
||||
|
||||
---
|
||||
|
||||
## 5. 蓝图执行链路
|
||||
|
||||
```
|
||||
yanghao_runner.py / task_engine.py
|
||||
│
|
||||
├── 1. CDPConnector.connect() → 启动/连接浏览器
|
||||
├── 2. conn.init_anti_detection() → 指纹注入
|
||||
├── 3. auth_manager.get_login_status() → 验证登录
|
||||
├── 4. 加载 blueprint JSON → 读取步骤
|
||||
├── 5. DouyinOps(page) → 绑定操作对象
|
||||
├── 6. 逐步骤执行:
|
||||
│ ├── goto_home()
|
||||
│ ├── wait_watch(seconds)
|
||||
│ ├── like(probability)
|
||||
│ ├── collect(probability)
|
||||
│ ├── next_video()
|
||||
│ ├── search(keyword)
|
||||
│ ├── post_comment(text)
|
||||
│ └── ...
|
||||
└── 7. 记录执行结果 → matrix.db
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 已知问题跟踪
|
||||
|
||||
| ID | 状态 | 问题 | 涉及文件 | 修复日期 |
|
||||
|----|------|------|---------|---------|
|
||||
| P0 | ✅ 已修复 | DOM 登录检测桌面端误报 | auth_manager.py + switch_account.py | 2026-05-01 |
|
||||
| P1 | ✅ 已修复 | Camoufox 显示 macOS | cdp_connector.py | 2026-05-01 |
|
||||
| P1 | ✅ 已修复 | Camoufox 中文乱码 | cdp_connector.py | 2026-05-01 |
|
||||
| P2 | ✅ 已修复 | douyin_browse_v3/nurture_v1 未注册 DB | DB task_blueprints | 2026-05-01 |
|
||||
| P3 | ✅ 已修复 | 冗余 profiles/douyin_01 目录(11MB) | 文件系统 | 2026-05-01 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 快速操作指南
|
||||
|
||||
```bash
|
||||
TOOL=~/workbuddy-agent-os/agent-sync/05_tools/07_matrix
|
||||
|
||||
# 查看账号状态
|
||||
python $TOOL/scripts/switch_account.py --status
|
||||
python $TOOL/scripts/auth_manager.py 9222 # 独立登录检测
|
||||
|
||||
# 启动 Chrome + 切换账号 + 自动导出 Cookie
|
||||
python $TOOL/scripts/switch_account.py --method profile --target douyin_01 --port 9222
|
||||
|
||||
# 启动 Camoufox + Cookie 注入 + 执行蓝图(正确方式)
|
||||
python $TOOL/scripts/yanghao_runner.py --account douyin_camo01 --blueprint douyin_browse_v2 --browser camoufox
|
||||
|
||||
# 完整测试
|
||||
python $TOOL/scripts/full_test.py --account-only douyin_01
|
||||
```
|
||||
Reference in New Issue
Block a user