Files
MediaCrawler/mac-agent-os-main/05_tools/07_matrix/ARCHITECTURE.md
T
butubb 2112c1a870
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
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 带网关原话 / 正常返回)。
2026-10-10 17:12:25 +08:00

8.6 KiB
Raw Blame History

Douyin 全模拟运营系统架构 v1.0

最后更新: 2026-05-15 基于 AgentOS 多机协同体系


设计原则

  1. 代码走同步,数据留本机 — 脚本在 agent-sync (Gitee),工作区在 agent-local (不参与同步)
  2. 四层隔离 — 管理层/流水线层/操作层/数据层,每层独立演进
  3. 每账号独立工作区 — 身份、素材、文案、发布记录各自独立
  4. 原子操作可组合 — 所有操作遵循 前置锚点 → 执行 → 后置锚点 模式
  5. 与现有养号系统共存 — 新架构不破坏 matrix.py / nurture_blueprint.py

目录结构

~/workbuddy-agent-os/
├── agent-sync/                              ← Gitee 同步(代码/技能)
│   └── 05_tools/
│       └── 07_matrix/
│           ├── ARCHITECTURE.md              ← 本文档
│           ├── scripts/
│           │   ├── matrix.py                ← 统一 CLI
│           │   ├── atom_ops.py              ← 原子操作库
│           │   ├── nurture_blueprint.py     ← 养号蓝图
│           │   ├── douyin_ops.py            ← 抖音专用操作
│           │   ├── matrix_modules/          ← 子模块
│           │   ├── pipelines/               ← [新] 流水线脚本
│           │   │   ├── __init__.py
│           │   │   ├── content_publish.py   ← 内容发布流水线(待建)
│           │   │   ├── ecom_pipeline.py     ← 电商流水线(待建)
│           │   │   └── live_pipeline.py     ← 直播流水线(待建)
│           │   └── ops/                     ← 平台操作
│           └── blueprints/
│
├── agent-local/                             ← 本机数据(不参与同步)
│   └── tools/
│       └── matrix/
│           ├── config/
│           │   └── accounts.yaml            ← 账号注册信息
│           ├── identities/                  ← 浏览器指纹+登录态
│           │   ├── douyin_01_camo/
│           │   ├── douyin_02_camo/
│           │   └── douyin_camo01/
│           └── accounts/                    ← [新] 每账号工作区
│               ├── douyin_01/
│               │   ├── content/             ← 视频素材
│               │   │   ├── raw/             ← 原始素材
│               │   │   ├── edited/          ← 剪辑成品
│               │   │   └── thumbnails/      ← 封面图
│               │   ├── scripts/             ← 脚本文案
│               │   │   ├── drafts/          ← 草稿
│               │   │   └── posted/          ← 已发布
│               │   ├── publish/             ← 发布记录
│               │   │   ├── queue/           ← 待发布队列
│               │   │   └── published/       ← 已发布记录
│               │   └── backup/
│               │       └── cookies/         ← 登录态备份
│               ├── douyin_02/               ← 同上
│               └── douyin_camo01/           ← 同上

四层架构

Layer 1: 数据层(本机,不同步)

每个账号独立文件夹,包含四类数据:

子目录 用途 数据来源
content/ 视频素材(raw/edited/thumbnails) 外部导入 / 剪辑
scripts/ 脚本文案(drafts/posted) AI 生成 / 手动编写
publish/ 发布队列 + 历史记录 系统自动写入
backup/ 登录态备份 系统自动备份

Layer 2: 操作层(代码,Gitee 同步)

原子操作(atom_ops.py 和 douyin_ops.py):

操作 状态 说明
browse ✅ 浏览视频流
like / collect ✅ 点赞/收藏
comment path a ✅ 弹窗覆盖层评论(KeyX+Enter)
comment path b ✅ 全屏视频页评论(scroll+click+Enter)
search ✅ 搜索并打开
follow ✅ 关注
publish_video ⏳ 待建 上传视频+文案+封面
live_sim ⏳ 待建 直播推流模拟
product_select ⏳ 待建 选品/带货
dm_send ⏳ 待建 私信

Layer 3: 流水线层(代码,Gitee 同步)

流水线 状态 操作链
养号流水线 (nurture) ✅ browse → interact → comment → loop
内容发布流水线 ⏳ 待建 读取队列 → 登录 → 上传 → 发布 → 记录
电商流水线 ⏳ 待建 选品 → 添加到橱窗 → 推广
直播流水线 ⏳ 待建 OBS推流 → 直播间互动 → 带货

Layer 4: 管理层(规划中)

  • 内容排期日历
  • 多账号任务调度
  • 发布成功率 KPI

两条评论路径对比

维度 Path A: 弹窗覆盖层 Path B: 全屏视频页
入口 精选页→点卡片→弹窗播放器 直接打开 /video/xxx URL
评论区状态 隐藏 (hasCL=false) → KeyX 打开 页面上方直接可见
激活方式 坐标 (479,687) 双击 scrollIntoView + click 输入容器
输入方式 pbcopy + Meta+V (共享) pbcopy + Meta+V (共享)
发送方式 Enter Enter
适用场景 养号流程中的日常操作 收到指定链接后自动评论

Route 规则:

if URL 包含 /video/ → Path B
else → 检查 hasCL
  if hasCL=true → 直接聚焦
  if hasCL=false → KeyX 打开 → Path A

并行执行架构(v4.3 新增)

mc run 使用 mc/engine.py 的 BatchEngine 执行批量任务。v4.3 改为并行模式:

设计要点

  1. 单账号全轮复用浏览器 — 每个账号创建一个 Camoufox 连接,跑完全部轮次再关闭
  2. 多账号 asyncio.gather — 所有账号的 _run_account_all_rounds() 同时启动
  3. 浏览器启停优化 — N 个账号 × R 轮 → 启停 N 次(而非 N×R 次)

新旧对比

旧版 (v1.1):
  轮1: A→B→C (串行) → 间隔 → 轮2: A→B→C → 间隔 → 轮3: A→B→C
  # 每步开闭一次浏览器,后一个等前一个完成
  # 3账号×3轮 ≈ 500-900s/批次

新版 (v1.2):
  A的全部3轮 ──┐
  B的全部3轮 ──┼── asyncio.gather ── 同时完成
  C的全部3轮 ──┘
  # 每账号一个持久浏览器,互不等待
  # 3账号×3轮 ≈ 150-350s/批次(约节省 60%)

代码入口

方法 职责
BatchEngine.run() prepare 所有账号 → gather 子任务 → 汇总
_run_account_all_rounds() 每账号:resolve → cookie 检查 → 启动浏览器 → 循环轮次 → 关闭
run_single(conn=...) 单轮单账号:导航到首页 → 执行蓝图步骤 → 返回报告
_pick_blueprint(round_idx) 混合随机/顺序选择本轮蓝图

共享连接模式

run_single() 新增 conn 参数:

  • conn=None → 自行创建并关闭浏览器(独立使用场景)
  • conn=CDPConnector → 复用已有连接(_run_account_all_rounds 内部调用)

注意事项

  • 并行启动多个 Camoufox 实例时,不要同时调用 connect() 中的 pkill -f camoufox (目前 connect() 中始终执行,但因同步调用在 async 之前完成,3 个并行的 connect() 的 pkill 都在任何 Camoufox 启动前执行完毕,因此不会跨进程误杀)
  • BrowserManager.prepare() 在 run() 中统一调用,不在子任务中重复执行

2026-05-15 修改:窗口位置固定从 accounts.yaml 读取,不再保存回写。 Camoufox 启动偏移会导致保存的坐标偏离预期(如 0→652, 400→2169)。

账号 固定位置
douyin_01 (0, 0)
douyin_02 (400, 0)
douyin_camo01 (750, 0)

评论故障修复记录(2026-05-15)

问题

养号流程中评论发送失败,日志显示 页面出现评论: ❌

根因

  1. 输入方式错误: keyboard.type() 被 Draft.js 忽略,execCommand fallback 不触发 React 状态
  2. 发送键错误: Alt+Enter 不再被新版抖音支持

修复

文件 行 改前 改后
runner.py Step 2 输入 keyboard.type → execCommand pbcopy + Meta+V
runner.py Step 3 发送 Ctrl+Enter → Alt+Enter Enter
runner.py 坐标保存 每次结束回写 accounts.yaml 删除,固定读配置
nurture_blueprint.py op_comment 发送 Alt+Enter (osascript) keyboard.press Enter