Files
mcn-short-video/project/短视频脚本创作/V1.0/subskills/mcn-dou-analysis/references/浏览器搜索抖音账号操作规范.md
T
maogeigei c48902f063 09-10 工作台:配置收敛、复盘字段契约修复、原创选题分镜支持、榜单期号区间显示
配置收敛:
- 端口/DB名/产出根/榜单目录单源化到 mcn-work-shop/config.json,代码层统一经 load-config.js 读取
- 新增 get-port.js 供 start.bat 读端口(bat 内嵌 node -e 会被 cmd 截断,读到的是兜底值)
- start.bat 修复失效的 managed node 路径(原写死 22.22.2 已不存在),改为遍历 versions 自动探测

复盘诊断页(真 bug 修复):
- 问题清单严重度全部显示成绿色 + 修改建议不显示:模型输出 {sev:'high',fix} 与前端读取 {severity:'高',suggestion} 字段名与取值均不匹配
- 前端新增 normIssue 归一化,兼容 sev/severity/level 与中英取值,并回补所属维度显示
- 在 submit-review-tasks 与诊断/复盘 prompt 中固化 issues_json 字段契约,从源头防 schema 漂移

分镜提示词:
- 原创选题(video_id 为空)原本无生成入口(分镜按 video_id 查询)
- listStoryboards 支持按 rewrite_id 查询,前端放开入口、切版本重查,并补落库指令(此前入库靠模型自由发挥)

榜单展示:
- 期号改为显示区间「08/31 ~ 09/06」,避免被误读为单日(期号=该周周一)
- 后端新增 collectRanges,从落盘文件读真实 dateStart/dateEnd 随 API 返回(日榜 start=end 不显区间)

其他:
- 清理 dsh 环境废弃后的历史叙述类废话(16 文件约 18 处),文末变更记录区保留
- 新增 docs/工作台UI规范.md(设计 token / 布局 / 8 页面路由 / 12 类组件 / 9 条已知坑)
2026-09-10 18:28:42 +08:00

19 KiB
Raw Blame History

浏览器搜索抖音账号操作规范

通过 browser-harness 搜索抖音账号 ID,获取账号主页信息与视频列表。 核心原则:适度访问网站,控制访问频率与行为节奏,不对目标站点造成负担。


一、适用场景

  • 已知抖音号或账号 ID,需要获取该账号的主页信息(昵称、粉丝数、简介等)
  • 需要获取账号下的视频列表(视频 ID、标题、点赞数等)
  • 三方数据 API 与 MCP 平台均无法覆盖的账号

二、执行流程

步骤 0:适度访问 — 首页浏览(50% 概率执行)

子步骤 操作 说明
0a 随机决定是否执行(50% 概率) 不每次都走,适度访问
0b 打开抖音首页 new_tab("https://www.douyin.com") —
0c 检测登录弹窗,有则点击关闭按钮(X / "暂不登录") 首页阶段自动关闭,不需登录
0d 随机停留 3~8 秒 适度访问,不快速跳转
0e 随机滚动 1~2 次页面 适度浏览行为

步骤 1:搜索账号 ID

子步骤 操作 说明
1a 导航到搜索页 https://www.douyin.com/search/{账号ID}?type=user 或在搜索框输入 —
1b 检测登录弹窗 如弹出登录窗口,停止操作,提示用户手动登录
1c 等待搜索结果加载 wait_for_load()

步骤 2:进入达人主页

子步骤 操作 说明
2a 从搜索结果中找到对应账号 人工确认匹配(抖音号可能与搜索词不同)
2b 点击进入主页 —
2c 检测登录弹窗 如弹出登录窗口,停止操作,提示用户手动登录
2d wait_for_load() 等待主页加载完成 —
2e 随机停留 2~5 秒 适度访问

步骤 3:提取账号基础信息

通过 js(...) 提取以下字段:

字段 说明
昵称 账号显示名称
抖音号 账号 short id(可搜索短号)
抖音ID(sec_uid) 账号唯一标识,主页 URL 中 /user/{sec_uid} 那串
抖音地址 主页链接 https://www.douyin.com/user/{sec_uid}
粉丝数 关注者数量
关注数 关注数量
获赞数 总获赞
作品数 视频作品总数
简介 个人介绍
IP属地 账号所在地区
头像 URL 头像图片地址

步骤 4:提取视频列表(数量按 SKILL.md「视频获取数量」参数)

子步骤 操作 说明
4a 滚动到视频列表区域 —
4b 每次滚动后等待 1~3 秒(随机) 适度访问,不连续快速滚动
4c 滚动 2~3 次即可;停止条件:收集数量达到 SKILL.md「视频获取数量」参数,或滚动到底部后加载不出更多视频(先到者为准) 达到目标数或无法加载更多即停,禁止无限滚动
4d 通过 js(...) 提取每条视频数据 从 React Fiber 中提取 awemeInfo,包含完整 stats/video/textExtra

滚动容器与加载技巧(实测踩坑记录,2026-08):

  1. 抖音达人主页的滚动容器不是 window,是 .route-sc 元素(overflow-y:auto)。直接滚动 window 无效,必须滚动真实容器:
    // 定位真实滚动容器(含视频链接的 overflow 祖先),显式滚到底触发懒加载
    const container = document.querySelector('.route-sc') ||
      Array.from(document.querySelectorAll('a[href*="/video/"]')).map(a => {
        let el = a.parentElement;
        while (el && el.scrollHeight <= el.clientHeight) el = el.parentElement;
        return el;
      }).find(Boolean);
    if (container) container.scrollTop = container.scrollHeight;
    
  2. 滚动后等待 1~3 秒再检查:若滚动到底(scrollTop 不再增长)或链接数不再增加,即"加载不出更多",立即停止(不无限滚动)。
  3. 备选:用 harness 的滚轮助手 scroll(x, y, dy)(派发 mouseWheel 事件,滚动光标下元素),适用于容器定位困难时。
  4. 提取兜底:Fiber 提取(awemeInfo)个别卡片可能取不到(虚拟化卡片差异),用 a[href*="/video/"] 的 href 提取 aweme_id 兜底,保证数量完整。

数据提取方式: 通过遍历页面上 a[href*="/video/"] 元素的 React Fiber,向上查找 awemeInfo 对象,获取完整的视频数据(含 stats、video、textExtra 等字段),而非仅从 DOM 文本解析。

提取方法优先级(2026-08-31 实测纠正):

  1. 首选:列表组件 Fiber defaultDataList(一次拿全,含 createTime)——08-26 旧梦留声机 36 条、08-31 俊希 136 条均实测通过:
    • 从 #root 的 __reactContainer$ / __reactFiber$ 键向下遍历(child/sibling 链),找 memoizedProps.defaultDataList 数组,每条含 awemeId / desc / createTime / stats(diggCount 等驼峰) / textExtra
    • createTime 只有这个来源可靠:逐卡片 awemeInfo 的 createTime 在列表页可能缺失(undefined 被 JSON.stringify 省略),defaultDataList 是全量组件数据,136/136 含 createTime
    • 统计字段是驼峰式:stats.diggCount / commentCount / shareCount / collectCount / playCount(不是 snake_case 的 digg_count)
  2. 兜底:卡片 Fiber awemeInfo——逐卡片提取 awemeInfo.video.duration(毫秒)等 defaultDataList 可能缺的字段;两者按 awemeId 合并:defaultDataList 提供 createTime/stats,卡片提供 duration
  3. 禁止:逐条打开 /video/{id} 视频页抓发布时间——15 次跳转是明显爬虫特征,且低效;正确路径是主页一次滚动 + Fiber 一次提取

访问账号主页(2026-08-31 实测纠正):

  • 必须走搜索路径:https://www.douyin.com/search/{账号ID}?type=user → 搜索结果中定位用户卡片 → 模拟点击进入主页(CDP Input.dispatchMouseEvent mouseMoved→mousePressed→mouseReleased,或 click_at_xy),禁止直接构造 /user/{sec_uid} 地址跳转
  • 搜索结果卡片链接带完整参数(如 /user/{sec_uid}brjmRxiM9i),直接构造缺后缀的地址会访问异常;且频繁直达地址 = 爬虫特征
  • 标签页复用:先在已有标签页上导航,不新建(见 5.5 标签页复用规则)

提取的视频字段(13列标准):

列序 字段 说明 数据来源
1 序号 自增序号 脚本生成
2 视频ID aweme_id 页面数据
3 视频标题 视频描述文案 页面数据
4 视频地址 https://www.douyin.com/video/{aweme_id} 拼接生成
5 点赞数 digg_count(数字) 页面数据
6 点赞(显示) 如 "2.1万"、"10万+" 页面显示文本
7 评论数 comment_count 页面数据
8 分享数 share_count 页面数据
9 收藏数 collect_count 页面数据
10 播放量 play_count(如页面可见) 页面数据
11 视频时长 duration(秒) 页面数据
12 发布时间 create_time(格式化为 YYYY-MM-DD) 页面数据
13 标签 从标题中提取的 # 标签,逗号分隔 标题解析

步骤 5:整理输出

  • 账号基础信息 → 结构化保存
  • 视频列表 → 保存为 Excel 到 {产出根目录}/{达人昵称}/短视频表格.xlsx

注意:浏览器抓取的数据保存为 Excel 文件(短视频表格.xlsx),与三方数据 API 保存的 JSON 格式(视频数据.json)不同。


三、登录弹窗处理逻辑

场景 处理方式
首页浏览阶段(步骤0) 自动关闭弹窗,不需要登录
搜索阶段(步骤1) 停止操作,提示用户登录,用户登录后继续
进入主页阶段(步骤2) 停止操作,提示用户登录,用户登录后继续

提示语示例:

检测到登录弹窗,请在浏览器中手动登录抖音账号,登录完成后告诉我继续。


四、适度访问原则

  1. 随机停留时间:所有等待时间使用随机区间(如 38 秒、13 秒),不使用固定值
  2. 随机滚动节奏:滚动间隔随机化,不连续快速滚动
  3. 不每次都走首页浏览:50% 概率跳过,避免每次行为完全一致
  4. 控制请求量:视频列表收集数量达到 SKILL.md「视频获取数量」参数即停止滚动,不无限加载
  5. 单次任务单账号:一次只处理一个账号,不批量并发

五、browser-harness 调用方式(环境 SOP)

环境说明(2026-09-02 调整):browser-harness 由 uv 工具安装,可执行文件位置按系统区分——Windows:~/.local/bin/browser-harness.exe;macOS/Linux:~/.local/bin/browser-harness;技能本体位置(09-02 起)——主技能 短视频工作台/subskills/browser-harness/(源仓库:project/短视频脚本创作/V1.0/subskills/browser-harness/,含 envs/browser-harness/ 环境与 src/;不再挂在 mcn-dou-analysis 下;09-10 起无 dsh 部署环境)。

5.0 环境检查与安装(每次浏览器任务前【必做】)

① 检测是否已安装(任一方法即可判定):

方法 操作 判定
① 可执行文件 检查 ~/.local/bin/browser-harness.exe(Windows)/ ~/.local/bin/browser-harness(macOS/Linux)是否存在 存在 = 已安装
② 命令探测 command -v browser-harness(macOS/Linux)/ where browser-harness(Windows)是否有输出 有输出 = 已安装
③ doctor 验证(可选) browser-harness doctor(确认工具/daemon/Chrome 三要素) 三要素就绪 = 可用

② 未安装 → 提醒用户安装(由 SKILL.md「browser-harness 依赖(红线)」驱动):

  • 可跳过:改用三方数据 API / MCP 兜底数据源,但功能一/二浏览器抓取无法执行
  • 同意安装:uv tool install --python 3.12 --upgrade --force browser-harness(--python 3.12 防止选中过旧版本;--upgrade --force 覆盖旧安装)
  • 技能本体:源仓库 project/短视频脚本创作/V1.0/subskills/browser-harness/(主技能 短视频工作台/subskills/browser-harness/;09-10 起无 dsh 部署环境;如缺失可从 browser-harness 仓库的 browser-harness skill 命令重新生成)
  • 安装后验证:command -v browser-harness(macOS/Linux)/ where browser-harness(Windows)有输出 + browser-harness doctor 三要素全绿,再进入下方 5.1 环境准备

5.1 环境准备(每次浏览器任务前【必做】)

① 清除代理环境变量(最重要,漏掉必踩坑):本机代理软件(如 Shadowsocks 的 Privoxy 组件监听 10800)会劫持 127.0.0.1 的 CDP 请求(报 "Internal Privoxy Error" 或连接失败)。按系统清除:

  • Windows(PowerShell):
Remove-Item Env:HTTP_PROXY, Env:HTTPS_PROXY, Env:http_proxy, Env:https_proxy -ErrorAction SilentlyContinue
$env:NO_PROXY = "127.0.0.1,localhost,::1"
  • macOS/Linux(bash/zsh):
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY
export NO_PROXY="127.0.0.1,localhost,::1"

② 连接方式(按顺序尝试):

方式 操作 说明
A. 自动(推荐) 直接运行 browser-harness(daemon 自动启动并连接浏览器) 最简单;可能触发 Chrome 授权弹窗(见 5.2)
B. 定向连接 设置 BU_CDP_URL 后运行:Windows $env:BU_CDP_URL="http://127.0.0.1:<端口>" / macOS export BU_CDP_URL="http://127.0.0.1:<端口>" 端口:先探测 9222(用户 Chrome 隐式调试端口)/ 9223(独立实例),取有效者
C. 独立实例 Windows:chrome.exe --remote-debugging-port=9223 --user-data-dir=<固定目录> about:blank;macOS:"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9223 --user-data-dir=<固定目录> about:blank 与用户浏览器隔离;Chrome 151+ 首次连接同样可能弹授权

5.2 Chrome 151+ 远程调试授权(关键机制)

  • Chrome 151+ 无论隐式(9222)还是显式(--remote-debugging-port)启动,CDP 端点默认 404,首次连接会弹「Allow remote debugging?」授权框;点击「允许」后端点才可用(Chrome 会记住,后续不再弹)
  • 弹窗可能出现在后台窗口:看不到时打开 chrome://inspect/#remote-debugging 页面启用(勾选后同样生效)
  • 连接前探测授权状态:Windows(PowerShell)Invoke-WebRequest http://127.0.0.1:<端口>/json/version / macOS/Linux(bash/zsh)curl -s http://127.0.0.1:<端口>/json/version —— 返回含 "Browser" 的 JSON = 可用;404/超时 = 未授权或非 CDP

5.3 失败排查顺序(按此执行,不跳步)

1. doctor:browser-harness doctor(确认工具/daemon/Chrome 三要素)
2. 端口探测:9222 / 9223 / 9224 的 /json/version(IPv4 + IPv6 [::1] 都试)
   - 返回 Browser JSON → 用它(BU_CDP_URL 定向)
   - 404 但端口有监听 → 非 CDP 或未授权(走 5.2 授权)
   - 无监听 → 启动独立实例或等 daemon 自动连接
3. 代理检查:确认 HTTP_PROXY/HTTPS_PROXY 已清(5.1 ①)
4. daemon 异常:browser-harness --reload(重启 daemon 后再试)
5. 仍失败 → 提示用户:Chrome 窗口点「允许」+ chrome://inspect 检查

5.4 调用示例(准备就绪后)

BH="$HOME/.local/bin/browser-harness.exe"

# 适度访问 — 打开首页
"$BH" <<'PY'
new_tab("https://www.douyin.com")
wait_for_load()
PY

# 搜索账号
"$BH" <<'PY'
goto_url("https://www.douyin.com/search/{账号ID}?type=user")
wait_for_load()
PY

# 提取页面数据
"$BH" <<'PY'
result = js("""
    return {
        title: document.title,
        html: document.body.innerHTML.substring(0, 5000)
    }
""")
print(result)
PY

5.5 标签页复用规则(重要,避免窗口/标签页堆积)

操作 Chrome 前先检查已打开的窗口/标签页:有则直接复用,没有才新建。

  1. 检查已打开标签页:用 browser-harness 列出当前标签页(cdp("Target.getTargets", flatten=True) 或 page_info() 查看当前页),确认目标窗口是否已有抖音标签页
  2. 有已打开标签页 → 直接复用:在现有标签页上导航即可——goto_url("https://www.douyin.com/search/{账号ID}?type=user") 或先 goto_url("https://www.douyin.com") 再搜索;不要每次 new_tab 新建标签页(多任务串行共用同一 Chrome 时,标签页会无限堆积)
  3. 没有标签页/窗口 → 才新建:new_tab("https://www.douyin.com")
  4. 用完不关闭:任务完成后保留标签页(留给后续任务复用),下次任务直接导航到目标地址即可
  5. 多任务串行:多个刷新/导入任务共用同一 9223 Chrome 实例,前一个任务的抖音标签页直接导航复用,无需重新打开

5.6 并发互斥(浏览器锁,09-01 新增,多 AI 会话并行时强制)

背景:工作台多个 AI 会话任务可并行(客户端并发上限≈3),但浏览器是共享单实例(9223 Chrome)。两个任务同时操作会互相导航标签页、丢失对方数据,因此浏览器操作必须互斥(一次只有一个任务在用浏览器)。非浏览器操作(解析/提炼/复盘/写脚本,走 MCP/文件)不受影响,可全并行。

锁规则(每个需要浏览器的任务必须遵守):

  1. 锁文件位置:工作台目录下的 .browser-lock(工作台目录 = 本技能根下的 mcn-work-shop/)。工作台 /api/run 对浏览器类任务会把运行时解析出的绝对路径注入 prompt,AI 会话执行时以注入的路径为准;此处不写死盘符。
    • 工作台触发的会话 cwd 即工作台目录,故可直接用相对路径 .browser-lock(推荐,跨机器可迁移)
    • 手工执行(cwd 不是工作台目录)时,先定位工作台目录再拼 .browser-lock
  2. 操作前:检查锁文件是否存在(ls)→ 存在则等 10 秒重试(最多 18 次 ≈ 3 分钟)
  3. 死锁保护:锁文件修改时间超过 10 分钟 → 视为死锁,可删除后抢占
  4. 拿锁:echo "<任务名> <时间戳>" > .browser-lock → 才操作浏览器
  5. 释放:浏览器操作全部完成后(无论成败)rm -f .browser-lock
  6. 串行协调:多个任务抢锁 = 先到先用;拿到锁的任务完成后释放,下一个任务继续;标签页复用规则(5.5)仅在自己持有锁期间适用
# 前置:确认当前目录就是工作台目录(目录内含 .browser-lock 与 server.js)
# 拿锁(互斥,带重试)
for i in $(seq 1 18); do
  if [ ! -f ".browser-lock" ]; then
    echo "$(date '+%H:%M:%S') ${任务名}" > ".browser-lock"
    break
  fi
  # 死锁保护:锁超过 10 分钟强制抢占
  if [ -f ".browser-lock" ] && [ $(($(date +%s) - $(stat -c %Y ".browser-lock" 2>/dev/null || echo 0))) -gt 600 ]; then
    rm -f ".browser-lock"
    continue
  fi
  sleep 10
done
# ... 浏览器操作 ...
# 释放锁(无论成败)
rm -f ".browser-lock"
# 检查已打开标签页
"$BH" <<'PY'
targets = cdp("Target.getTargets", flatten=True)["targetInfos"]
for t in targets:
    if t.get("type") == "page":
        print(t.get("url", "")[:80])
PY

# 有抖音标签页 → 直接导航复用(不新建)
"$BH" <<'PY'
goto_url("https://www.douyin.com/search/{账号ID}?type=user")
wait_for_load()
PY

5.7 浏览器进程生命周期(红线,09-02 用户明确)

已开启的 Chrome 浏览器(9223 调试实例、用户手动开启的 Chrome、daemon 自动连接的实例)一律不主动关闭,除非用户明确要求关闭。

  1. 禁止主动关闭:任务完成/失败/异常后,不得 taskkill / Stop-Process / kill 已开启的 Chrome 进程;用户没说要关就留着
  2. 只关自己启动的临时实例:仅当本次任务自己用 --remote-debugging-port 新启动的、且明确标记为临时用途的实例,才可自行回收;复用已有实例时禁止关闭
  3. 工作台/脚本清理:清理进程(如查占用端口时发现 Chrome)先确认是否为用户在用实例,是则跳过,不清理
  4. 为什么要保留:9223 调试 Chrome 承载登录态/授权记忆/标签页复用,关闭后下次任务需重新启动+重新授权,成本高且可能打断用户正在进行的操作

六、已知问题

  • 抖音网页版需要 JS 渲染,且有限流/验证码机制
  • 视频列表懒加载,滚动 2~3 次收集到 SKILL.md「视频获取数量」参数数量即可停止
  • 未登录状态下搜索可能被限制,部分功能需要登录
  • Chrome 需开启 remote debugging(chrome://inspect/#remote-debugging)