Files
MediaCrawler/mac-agent-os-main/PLANS/REFORM_ANALYSIS.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

242 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 改造分析报告:现状 vs 目标架构
> 日期: 2026-07-04 | 基于 `PLANS/TASK_ORCHESTRATION_ARCHITECTURE.md`
> 审计范围: 全部 7 个模块,逐项检查
---
## 一、改造项总览
| # | 模块 | 改造类型 | 优先级 |
|:-:|:-----|:---------|:-------|
| 1 | `scheduler.py` | 🔧 **重写** — 现有逻辑不满足需求 | P0 |
| 2 | `priority_queue.py` | ✅ **不动** — 现有类直接可用 | - |
| 3 | `command_bus.py` | 🆕 **新增** smart_comment 类型 | P1 |
| 4 | `video_analyzer.py` | 🆕 **新建** — 不存在 | P1 |
| 5 | `corpus.py` | 🔧 **改造** — 加行业过滤 + 万能兜底 | P1 |
| 6 | `douyin.yaml` | 🔧 **重构** — 语料分层 | P1 |
| 7 | `profiles.json` | 🔧 **补字段** — 加 industry | P2 |
| 8 | `ops-command.js` | 🆕 **加功能** — 三队列显示 | P3 |
---
## 二、逐项分析
---
### 改造项 1:`scheduler.py` — 🔧 重写
**当前代码**(`guardd/modules/scheduler.py:33-362`):
当前是单队列模式:
```python
class Scheduler:
def __init__(self):
self.queue = PriorityQueue() # ← 一个队列装所有优先级
self.active_tasks: dict[int, dict] # {slot_id: task}
self.paused_tasks: dict[int, dict]
```
| 功能点 | 现状 | 目标 | 问题 |
|:-------|:-----|:-----|:-----|
| 队列数量 | **1 个** 混装所有优先级 | **3 个** 独立队列(P0/P1/P2) | ❌ P0不能插队,P2不能填空 |
| `_pop_next_task()` | 遍历所有任务,按`(priority, scheduled_at)`排序后取第一个 | 先看P0→再看P1→再看P2,且跳过 busy 账号 | ❌ 无法实现优先级隔离 |
| 账号互斥 | slot_manager.find_account() 在分配时检查 | 三层检查:入队时+分配时+执行前 | ❌ 入队层不检查,可能重复入队 |
| 账号状态表 | 无 | `account_slots: dict[str, int]` | ❌ 没有快速查询账号状态的能力 |
| P0 抢占 | 无 | 当前任务结束后插队 | ❌ 完全未实现 |
| P2 劣后 | 无 | 只在空闲时执行,可被抢占 | ❌ 完全未实现 |
| 暂停任务暂存 | `paused_tasks` 存在但不被 active 使用 | P0插入时暂停P1,完成后恢复 | ❌ 逻辑不完整 |
**改造原因**:当前逻辑是**功能错误的**。三个优先级的任务混在一个队列里,虽然排序时按 priority 字段,但 `_pop_next_task` 取完第一个任务后就 break 了,不会继续往后看。当高优任务 due 时间还没到时(`scheduled_at > now`),堆顶返回 None,整个调度循环就停了。这导致 P0 任务无法真正插队。
**改动量**:~200行,重写 `Scheduler` 类。
---
### 改造项 2:`priority_queue.py` — ✅ 不动
**当前代码**(`guardd/modules/priority_queue.py:1-79`):
```python
class PriorityQueue:
"""基于 heapq 实现,支持优先级排序 + 时间调度 + 取消/重排"""
```
当前实现完全满足需求。三队列只需创建三个独立实例:
```python
self.queue_priority = PriorityQueue() # P0
self.queue_normal = PriorityQueue() # P1
self.queue_filler = PriorityQueue() # P2
```
无需修改此类。
---
### 改造项 3:`command_bus.py` — 🆕 新增 smart_comment
**当前代码**(`services/command_bus.py:807-842`):
```python
CMD_REGISTRY = {
"nurture": {...},
"collect": {...},
"login": {...},
"logout": {...},
"comment": {...},
"like": {...},
"interact": {...},
"record": {...},
}
```
| 功能点 | 现状 | 目标 | 问题 |
|:-------|:-----|:-----|:-----|
| 评论类型 | `comment` / `interact` — 直接传 `mc task comment` | + `smart_comment` — 先分析视频再评论 | ❌ 缺少视频分析环节 |
| 分发逻辑 | 按机器分组后直接发到 guardd | 先调 VideoAnalyzer 分析所有URL,再分组分发 | ❌ 无分析环节 |
**改造原因**:**新功能需求**。现有 comment/interact 可以保留不变,新增 smart_comment 走新的视频分析流程。
**改动量**:~20行,加一条注册表 + dispatch 分支。
---
### 改造项 4:`video_analyzer.py` — 🆕 新建
**当前**:文件不存在。
**需要新建**一个完整的视频分析模块,包含:
- 浏览器打开 URL 提取标题/描述
- 关键词匹配行业分类
- 根据账号 industry 选评论
**改造原因**:**完全是新增功能**,原来是直接传评论或者随机取语料,现在需要先分析视频内容再做匹配。
**改动量**:~150行新文件。
---
### 改造项 5:`corpus.py` — 🔧 改造
**当前代码**(`scripts/mc/corpus.py:51-57`):
```python
KEYWORD_CATEGORY_MAP = [
(["科技", "数码", "手机"], ["称赞", "提问"]),
(["美食", "做饭", "菜"], ["称赞", "共鸣"]),
(["旅游", "风景", "旅行"], ["称赞", "提问"]),
(["情感", "生活", "感悟"], ["共鸣", "安慰"]),
(["知识", "科普", "教育"], ["提问", "补充"]),
]
```
| 功能点 | 现状 | 目标 | 问题 |
|:-------|:-----|:-----|:-----|
| 关键词覆盖 | **5组**(科技/美食/旅游/情感/知识) | **9+组**(加上医疗/财经/育儿/汽车等) | ❌ 无医疗关键词,健康类视频无法匹配 |
| 行业过滤 | 无 | 根据账号 industry 过滤语料 | ❌ 医疗账号可能发科技评论 |
| 万能兜底 | `_get_random_comment()` 全域随机 | 从万能池(称赞/提问/共鸣)取 | ❌ 没有万能池概念 |
| 分类→方向映射 | `DIRECTION_TO_CATEGORY` 5个 | 同步扩展 | ❌ 需要对齐 |
**改造原因**:**现有功能不完整**。关键词覆盖太窄,缺少行业过滤机制和万能兜底逻辑。
**改动量**:~50行,改 `KEYWORD_CATEGORY_MAP` + `get_comment_for_video()`。
---
### 改造项 6:`douyin.yaml` — 🔧 重构
**当前结构**(`corpus/douyin.yaml:239行`):
```
categories:
赞美: (30条,通用)
共鸣: (15条,通用)
提问: (15条,通用)
感慨: (15条,通用)
客观: (10条,通用)
补充: (5条,通用)
```
| 功能点 | 现状 | 目标 | 问题 |
|:-------|:-----|:-----|:-----|
| 语料分层 | **平铺**,都在同一层 | **两层**:万能池 + 行业池 | ❌ 无法区分行业 |
| accessible 字段 | 无 | `accessible: "*"` 或 `accessible: ["health"]` | ❌ 无法限制账号使用 |
| match_tags 字段 | 无 | 每个行业池带关键词标签 | ❌ 无法自动匹配视频 |
**改造原因**:**结构设计不满足新需求**。需要按行业分层,加 accessible 和 match_tags 字段。
**改动量**:YAML 结构调整,将现有评论分类到"万能称赞""万能提问""万能共鸣"下,新增"大健康称赞"等行业池。
---
### 改造项 7:`profiles.json` — 🔧 补字段
**当前**(`profiles.json:344行`):
```json
{
"douyin_133": {"nickname":"苏州胃肠体检敏敏", ...},
"douyin_test": {"nickname":"小美养生茶", ...},
}
```
没有一个账号有 `industry` 字段。
**改造原因**:**缺少关键数据**。没有 industry 字段,VideoAnalyzer 无法判断账号该用哪个语料池。
**改动量**:每个账号加一行 `"industry": "health"` 或 `"industry": "general"`,手动配置。
---
### 改造项 8:`ops-command.js` — 🆕 加功能
**当前代码**:
前端已有 P0/P1/P2 的 HTML 筛选 checkbox(第41-43行),但后台 scheduler 返回的队列数据中优先级是混在一起的,前端无法真正按优先级分类展示。
**改造原因**:**新功能需求**。后台改为三队列后,前端需要分开显示三个队列的长度+内容。
**改动量**:~80行,加三个队列的独立展示区域。
---
## 三、改造原因分类
| 类别 | 数量 | 项 |
|:-----|:-----|:----|
| ❌ **功能错误**(现有逻辑有问题) | 1 | scheduler.py — 单队列导致P0/P2无法正常工作 |
| ⚠️ **功能不完整**(有但不够) | 2 | corpus.py 关键词覆盖窄、douyin.yaml 无行业过滤 |
| 🆕 **新功能需求**(完全新增) | 4 | video_analyzer.py、command_bus smart_comment、profiles.json industry、ops-command三队列 |
| ✅ **无需修改** | 1 | priority_queue.py |
---
## 四、按 Phase 的改造详细清单
### Phase 1:队列改造(P0)
| 文件 | 当前行数 | 改动 | 原因 |
|:-----|:---------|:------|:------|
| `guardd/modules/scheduler.py` | 362行 | 重写:单队列→三队列 + 账号互斥表 + P0抢插 + P2填空 | ❌ 功能错误,当前单队列无法实现优先级隔离 |
### Phase 2:语料重组(P1)
| 文件 | 当前行数 | 改动 | 原因 |
|:-----|:---------|:------|:------|
| `corpus/douyin.yaml` | 239行 | 重构为万能池+行业池 | 🆕 新需求,需要按行业分层 |
| `scripts/mc/corpus.py` | 701行 | 扩展关键词 + 加行业过滤 + 万能兜底 | ⚠️ 关键词覆盖窄,缺少过滤 |
| `profiles.json` | 344行 | 各账号加 industry 字段 | 🆕 新需求,需要标记账号行业 |
### Phase 3:视频分析(P1)
| 文件 | 当前行数 | 改动 | 原因 |
|:-----|:---------|:------|:------|
| **新建** `services/video_analyzer.py` | 0 → ~150行 | 视频URL分析+分类+选评论 | 🆕 完全新增 |
| `services/command_bus.py` | 1289行 | CMD_REGISTRY 加 smart_comment | 🆕 新需求 |
### Phase 4:指挥台展示(P2)
| 文件 | 当前行数 | 改动 | 原因 |
|:-----|:---------|:------|:------|
| `frontend/views/ops-command.js` | 413行 | 三队列独立展示 | 🆕 新需求 |