移植自 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 带网关原话 / 正常返回)。
10 KiB
10 KiB
2026-06-20 工作日誌
00:00-00:30 — 执行状态显示细腻度升级
背景
用户反馈 Dashboard 侧边栏的执行历史区块只显示"进程运行中"/"进程已结束"两种状态,但后端状态机有10种状态。
修改内容
- 后端 (
services/command_bus.py):CommandStatus枚举定义 10 种状态:queued / preflighting / preflight_failed / dispatching / running / completed / failed / timed_out / crashed / cancelled ✅ 已有 - 前端 (
frontend/src/modules/matrix_views.js): 重写loadExecutionHistory()函数:- 新增
STATUS_MAP常量,每种状态映射到独立图标+颜色+中文标签+分组 - 顶部显示各状态的实际数量标签(不合并分组)
- 每台机器显示 ok/active/fail 细分(不再只看完成率)
- 每条执行记录显示:状态标签 | 机器 | 账号 | 消息 | 耗时 | 时间
- 格式化的耗时显示(s/m 自适应)
- Vite build 完成,hash 更新为 index-BhCDf8FF.js
- 新增
- 无需重启服务(静态文件在磁盘上实时读取)
00:30-01:00 — 信息采集全链路断点分析(L1→L5)
背景
用户反馈信息采集页面点击「采集选中」后没有获取到内容。
分析结论
断点在 L1(登录检测),不是数据回传问题:
- 所有 recent collect log 都显示
ensure_login返回"unknown"→ 账号被跳过 - 实际 douyin_134 有 3 个 session cookie(有效登录态)但 DOM 锚点检测不到
- 旧版
collect_batch_runner.py用不同检测逻辑能正确识别,新版LoginStateMachine._detect()只查 DOM 锚点失败
L1 修复
- 抖音
logged_in锚点从 2 个扩展到 9 个 - 新增 Cookie 兜底检测 — DOM 检测失败后用
page.context.cookies()检查 sessionid/token - 新增页面标题检测 —
"xxx的抖音"= 已登录,"记录美好生活"= 未登录 _recover_cookie()改为导航到user/self— 不再只刷新首页,强制触发登录态
L1→L5 测试验证
- L1: ✅ 登录检测通过(dl/fix-recover-cookie -> 进入蓝图执行)
- L2: ✅ 蓝图引擎启动,到达 check_verify_dialog 钩子
- L3: ✅ CommandBus dispatch → status:"accepted", PID=32964
- L4: ✅ API /api/ops/status 正常返回
- L5: ✅ 前端可通过 API 获取(等待下次 build)
- 次要问题:douyin_test 触发 SMS 验证弹窗导致执行卡住(已有钩子但 _recover_sms 阻塞)
文档更新
FEDERATION_GUIDE.md新增「十一、五层执行架构 (L1–L5)」完整文档- 更新 4.4 登录状态机说明,记录 2026-06-20 修复细节
- 合并 4.4/4.5 多机账号管理部分(之前有格式错误)
09:00-16:30 — 登录状态机重构 + 全场景验证通过
背景
- 14:00 用户提供阿里百炼 API key,配置 vision_bridge.py 远程视觉支持(DashScope qwen-vl-plus)
- 15:00-16:20 反复调试抖音登录,逐个修复问题
修复清单
- 检测器误判 logged_in — 移除
[data-e2e="user-avatar"]锚点(视频创作者头像也匹配) - 增加文本检测 —
body.innerText检查"未登录"和"粉丝/关注"关键词 - 登录按钮被浮层拦截 — JS fallback
el.click()绕过 Playwright 可见性检查 - 手机号为空 — 添加
_ensure_phone()检查当前值,空则重填 - 短信验证码取旧码 — 改为直接调用 ApiSMSHandler._fetch_messages() + 过滤
id > min_id - 登录按钮是"确认登录"不是"登录" — 多文本匹配
验证结果(三种场景全通过)
- 全新登录: detect→点登录→填手机→获取验证码→登录→douyin_read_profile 9步 ✅
- 短期过期: detect→JS点登录→JS点一键登录→验证码→确认登录→douyin_read_profile 9步 ✅
- 已登录: detect→logged_in→直接执行蓝图 ✅
代码清理
login_state_machine.py重构为三组件架构(PlatformDetector / RecoveryChain / LoginManager)SmsRecovery限制仅小红书使用(抖音由 DouyinLoginRecovery 处理)cdp_connector.pyclose() 三层兜底修复 Camoufox stop() 缺失mc/cli.pysetup_log() 加 logging.basicConfig 修复日志不输出- 归档 2 个 export_* 蓝图到 _archive/
FEDERATION_GUIDE.md更新登录状态机章节 + 蓝图清单
16:30-18:10 — 小红书登录修复 + 全场景验证通过
修复清单
- SmsRecovery 调用错版本 — 之前调 sms_login(抖音版),改为直接调 xhs_login(小红书6位框版)
- XhsDetector cookie 误判 — 移除 cookie 直接返回 logged_in
- xhs_login.is_logged_in() 太松 — 改为严格匹配 + 登录面板检测
- 步骤顺序错误 — 「协议同意处理」移到点登录后
- "同意并继续"按钮文字 — 改为「同意并继续」,class 为 div.foot-btn
- 缺少 oauth-tip 切换 — 填手机号后需点 div.oauth-tip
- SmsRecovery 二次验证过严 — 移除重复验证,信任 xhs_login
验证结果(18:08 全新登录 8/8 成功)
✅ 昵称=橙子哥 | ID=254437248 | 关注=1 | 粉丝=6
两种平台验证状态
| 场景 | 抖音 | 小红书 |
|---|---|---|
| 全新登录 | ✅ | ✅ |
| 短期过期 | ✅ | 🔵 |
| 已登录 | ✅ | ✅ |
18:10-18:45 — 养号蓝图 v2.0 更新
基础修
- 冷却前缀匹配 —
_get_cooldown()去掉xhs_/dy_/dy_前缀 - wait_watch 补到 xhs_ops — 使小红书养号蓝图可用
- 搜索 @random 支持 — douyin_ops + xhs_ops 均支持随机关键词
4个养号蓝图更新
| 蓝图 | 版本 | 步数 | 变化 |
|---|---|---|---|
| douyin_daily | v2.0 | 40 | 10个视频,1-2条评论,概率点赞/收藏 |
| douyin_active_v1 | v2.0 | 80 | 2次@random搜索+各6结果,50%评论率 |
| xhs_daily | v2.0 | 49 | 10篇笔记,1-2条评论,参照抖音 |
| xhs_active_v1 | v2.0 | 89 | 2次搜索+各6结果+关注,参照抖音 |
19:10-20:40 — 养号蓝图 v2.x 修复
抖音日常 v2.1 (最终通)
- 根因:
open_video只单点不验证 + 蓝图未进详情页 - 修复: open_video 双击+验证+焦点+回首页兜底
- like/collect 改为键盘 z(非 DOM 点击)
- 结果: 45步 39成功 6失败 ✅
修复清单
- douyin_ops._click_selector — 加 JS fallback(备用)
- douyin_ops.like — 键盘 z 为主线
- douyin_ops.open_video — 双击+验证+焦点+回首页
- douyin_daily蓝图 — 每视频前加 open_video
- xhs_ops — 补 wait_watch、go_back
- xhs_ops.xhs_click_note — 回首页兜底、返回 False
- engine._get_cooldown — 去前缀匹配
待测试
- xhs_daily 小红书日常(需用户配合验证码)
20:40-21:40 — 抖音版面整理 + 录制验证
录制成果(2轮,共48步操作)
- 第1轮: 弹窗模式完整操作(点赞z→评论x→收藏→关注g→下一页→首页→主页)
- 第2轮: 搜索"美食"→结果操作 + 全屏详情页/video/xxx操作
- 发现: 键盘快捷键(z/x/g/ArrowDown) 两种模式通用
- 收藏按钮是SVG图标,非 data-e2e 选择器
蓝图整理(9→6个活跃)
| 状态 | 蓝图 |
|---|---|
| ✅ 保留 | douyin_daily / active / comment / reply / search / read_profile |
| 📦 归档 | comment_test / search_browse / collect(_archive/ 保留旧版做参考) |
| ↩️ 不删 | _archive/12个旧蓝图保留不动 |
23:50 — 今日复盘与明日任务清单
今日底线(已通过验证)
- douyin_read_profile: ✅
- xiaohongshu_read_profile: ✅
- 抖音登录(3场景): ✅
- 小红书登录(全新登录): ✅
- 抖音原子操作全测: 15/16 ✅(仅follow失败)
今日未解决的问题
1. post_comment(抖音)— 代码返回成功但实际没发
- 根因: _do_execute 中
ok = await self.post_comment()返回'ok'字符串,Python 视为 truthy,直接显示 sent - 实际: 注释输入框
.public-DraftEditor-content点击→打字→Enter,但评论未出现在列表 - 修复方向(已改未测): 加 send 按钮查找(发送/发布类名)+comment-list 文本验证,验证不通过返回 failed
- 旧代码参考:
archive/interactive_test.py的 step_send_comment 和matrix_modules/nurture/runner.py的 _send_comment
2. follow(抖音)— 失败
- 当前实现:
page.keyboard.press("g")+ _click_selector 查找关注按钮 - 录制发现: 用户按 g 键关注/取消关注,键盘方法本身正确
- 可能原因: 视频详情页中已关注作者,g 键变成取消关注
3. xhs_post_comment(小红书)— 完全没发出去
- 根因:
p.content-input选择器找不到(CSS modules 添加 hash) - 录制数据: 正确路径是 → 笔记详情页滑到底部 → 找到
DIV[class*="inner"]点击激活 →P.content-input出现 → 填字 →BUTTON.btn.submit发送 - 但
p.content-input始终匹配不到,尝试了 x 键/JS激活/scrollTo 等5种方式均失败 - 明天方向: 用截图+视觉识别找输入框位置,或改用 Playwright getByPlaceholder
4. xhs_click_note 在 go_back 后失败
- 笔记返回首页后 feed 未渲染完就找笔记,找不到
- 方向: go_back 后加 2-3秒延迟
明日任务清单(优先级排序)
P0: 修抖音 post_comment 验证(已改代码,明天测试验证)
P0: 修抖音 follow(查 g 键是否被已关注状态干扰)
P0: 修小红书 post_comment(截图视觉分析找输入框)
P1: 修 xhs_click_note 后 feed 刷新延迟
P1: 修 xhs_like 选择器稳定性
P1: 抖音高活跃蓝图 douyin_active 测试
P1: 新建小红书 xhs_comment_on_post / xhs_search 蓝图
P2: 小红书高活跃蓝图 xhs_active 测试
P2: 双平台日常养号自动化定时任务
关键教训(以后不要犯)
- 录制数据要直接用(坐标/元素类名),不要加 is_visible() 等额外检查
- 抖音和小红书的操作不能通用(x 键开评论在抖音通,小红书不通)
- 代码返回 ✅ 不等于页面真的有反应,每种操作必须加验证
- post_comment 必须检查 comment-list 中是否出现刚发的文字
- 跑测试用"原子操作全测"蓝图(每个操作一次),不用养号蓝图(49步浪费时间)
- CSS modules 类名不可靠,优先用 text/placeholder/坐标
- 每次测试前先给路径让用户审查,确认再跑
补注: 2026-06-21 08:20 确认小红书 xhs_post_comment 测试通过 ✅