移植自 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 带网关原话 / 正常返回)。
8.3 KiB
8.3 KiB
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. 快速操作指南
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