从评论区的通知入口,到私信列表的红点标记,我用一套 Chrome 扩展实现了抖音全场景的自动回复。这篇文章拆解完整流程图、关键技术细节和踩过的坑。
1. 系统全景
抖音创作者后台
├── 通知入口 → 评论区自动回复
│ ├── 筛选"全部消息" → "评论"
│ ├── 检测最新评论
│ ├── 关键词匹配 / 默认回复 / 随机回复 / AI 回复
│ └── 支持收藏表情回复
│
└── /user/self → 私信自动回复
├── 陌生人消息 → 自动回关
├── 小红点检测 → 未读消息
├── 多版本 DOM 适配 → 提取昵称和内容
├── 关键词匹配 / 默认回复 / AI 回复
└── 自动关闭会话,避免干扰
2. 评论区自动回复
2.1 入口定位
评论通知藏在右上角 “通知” 按钮的下拉面板里,需要 hover 才能触发:
点击 notifyBtn = find('//p[text()="通知"]')
if (notifyBtn 存在) {
hover(notifyBtn) // 悬停展开下拉面板
wait 1秒
2.2 筛选链路:两步到位
通知面板里消息类型混杂——关注、点赞、@我、评论全在一起。需要两步筛选才能精准拿到评论:
// 第一步:打开下拉筛选项
click( filterDropdown )
click( dropdownList 中 "全部消息" )
// 第二步:切到评论
click( filterDropdown )
click( dropdownList 中 "评论" )
为什么分两步? 实测直接从”通知”切”评论”偶现不生效,先切”全部消息”再切”评论”是最稳定的路径。
2.3 提取最新评论
nickname = 第一条评论中的用户昵称
content = 第一条评论中的文本内容
2.4 去重:内容比对
current = nickname + ":" + content
if (上一次记录 != "" && 上一次记录 != current) {
// 是新消息,触发处理流程
}
上一次记录 = current
用简单的字符串比对代替互斥锁——轻量且可靠。
2.5 回复流程
// 1. 先勾住消息
showPopup(current) // 浮动弹窗提示
hook(nickname, content) // 转发到外部系统
// 2. 点击评论内容,展开回复输入框
click(第一条评论的文本区域)
// 3. 等待"回复"按钮出现(最多6秒)
replyBtn = waitFor( '回复按钮', 6000ms )
click(replyBtn)
// 4. 按优先级决定回复内容
reply = 关键词匹配(content)
|| 默认回复
|| 随机回复
|| AI回复(nickname, content)
回复优先级:关键词 → 默认配置 → 随机池 → AI。
2.6 收藏表情的特殊处理
回复内容支持 收藏表情N 格式,N 指收藏表情列表中的序号:
if (reply 匹配 /^收藏表情(\d+)$/) {
// 点击表情面板按钮
click( 表情按钮 )
// 切换到收藏表情 Tab
click( 收藏表情Tab )
// 选择第 N 个
click( 第N个收藏表情 )
} else {
// 普通文本输入
input( 输入框, reply )
}
// 点击发送
click( 发送按钮 )
3. 私信自动回复
3.1 页面隔离
私信逻辑只在创作者后台执行,其他页面不触发:
if (当前URL 以 "https://www.douyin.com/user/self" 开头) {
执行私信流程
}
3.2 会话管理:先清场
进入私信列表后,先把上一次残留的会话面板关掉,确保从干净状态开始:
// 确保私信列表面板打开
if (列表面板未打开) {
hover( 私信按钮 )
}
// 关闭上次可能残留的会话
click( "关闭会话" )
click( "退出会话" )
click( 返回按钮 )
3.3 陌生人自动回关
抖音把陌生人消息放在独立分组。脚本检测后自动回关:
strangerTab = find( '//div[text()="陌生人消息"]' )
if (strangerTab 存在) {
click(strangerTab)
click( 第一条陌生人会话 )
click( "回关"按钮 )
click( 详情页中的"关注"按钮 )
}
3.4 未读消息检测:小红点
抖音私信使用 Semi Design 组件库,未读标记是 semi-badge-count 样式的数字 badge:
badge = find( '私信对话框中带 semi-badge-count 类名的 span' )
if (badge 存在) {
click(badge) // 点进未读会话
3.5 消息内容提取:四路降级
私信页面的 DOM 结构因 A/B 实验存在多个版本,提取消息内容用了四级 fallback:
content = tryXpath('版本A的消息选择器')
|| tryXpath('版本B的消息选择器')
if (content 为空) {
content = tryXpath('版本C的消息选择器')
|| tryXpath('版本D的消息选择器')
}
nickname = tryXpath('版本A的昵称选择器')
|| tryXpath('版本B的昵称选择器')
昵称和消息内容都存在多版本适配,确保任何一个页面变体都能正确提取。
3.6 输入与发送:双路径适配
不同版本下输入框和发送按钮的 DOM 结构也不同:
// 输入框
textarea = find( '版本A的输入框路径' )
if (textarea 存在) {
input( 版本A路径, reply )
} else {
input( 版本B路径, reply )
}
// 发送按钮
sendBtn = find( '版本A的发送按钮' )
if (sendBtn 不存在) {
sendBtn = find( '版本B的发送按钮' )
}
click(sendBtn)
3.7 处理完收尾
回复后关闭会话,恢复干净状态,避免面板残留影响下一轮轮询:
click( "关闭会话" )
click( "退出会话" )
click( 返回按钮 )
4. 统一消息分发
评论和私信共享同一套钩子函数:
// 浮动提示
showPopup( 昵称 + ":" + 内容 )
// 转发到外部客服系统 / 记录日志
hook(昵称, 内容, 头像)
hook 函数是插件与外部系统的桥梁,负责把消息推送到客服工单系统或写入数据库。
5. 回复决策树
新消息到达
├── 关键词匹配命中 → 直接回复
│ ├── 收藏表情格式 → 发送表情
│ └── 普通文本 → 输入框 + 点发送
├── 默认回复已配置 → 直接回复
├── 随机回复池有内容 → 随机选一条回复
└── 以上都不满足 → 调用 AI
├── Coze Bot(会话缓存 + 异常自动重建)
└── FastGPT(兼容 /chat/completions 和 /responses 双格式)
6. 架构一览
| 模块 | 关键设计 |
|---|---|
| 评论区 | hover 触发面板、两步筛选锁定评论、收藏表情发送 |
| 私信 | URL gating、小红点检测、陌生人自动回关、多版本 DOM 适配 |
| 回复引擎 | 关键词 → 默认 → 随机 → AI 四级降级链 |
| AI 接入 | Coze + FastGPT 双后端,异常时自动清除会话重建 |
| 会话管理 | 处理前后显式开关面板,不依赖页面自动行为 |
| 去重 | 字符串比对代替互斥锁,轻量可靠 |
7. 设计原则
- 面板生命周期显式管理 — 打开 → 操作 → 关闭,每步都不假设页面会自动清理
- 操作间必须 sleep — 抖音的虚拟 DOM 需要时间 diff,不等就找不到元素
- 先清场再干活 — 开始任何操作前先关掉残留面板,从零开始
- 去重用比对而非加锁 — 内容字符串比对简单且不会死锁
- 每个选择器都有备胎 — 评论区、私信、输入框、发送按钮,全部做了 fallback
- 回复有兜底 — 关键词不命中、默认没配置、随机池为空,最终落到 AI,保证不会冷落用户
阶段一:评论区入口
- 循环开始,判断当前在创作者后台页面
- 找到”通知”按钮,hover 悬停展开下拉面板
- 两步筛选——先切”全部消息”,再切”评论”
- 提取第一条评论的昵称和内容
- 和上一条消息比对,相同就跳过,不同就进入回复流程
阶段二:评论回复
- 弹窗提示 + hook 转发到外部系统
- 点击评论内容 → 等待”回复”按钮出现(最多 6 秒)
- 按优先级决策回复:关键词 → 默认 → 随机 → AI
- 判断回复类型——收藏表情就走表情链路,普通文本就走输入框
- 点击发送 → 关闭评论面板 → 按 ESC 退出
阶段三:私信入口
- 判断 URL 是
/user/self,不是就结束本轮 - 展开私信面板 → 清场(关闭会话、退出会话、返回列表)
阶段四:陌生人处理
- 检测是否有”陌生人消息”分组
- 有就自动点击 → 回关 → 关注
阶段五:未读消息检测
- 查私信列表是否有红点 badge
- 没有就收尾退出,有就点击红点进入会话
阶段六:私信内容提取
- 昵称提取:选择器 A,不行就选择器 B
- 消息提取:选择器 A/B → A 或 B 不行就 C/D
阶段七:私信回复
- 弹窗提示 + hook 转发
- 同样的四级降级决策:关键词 → 默认 → 随机 → AI
- 输入框双路径适配:A 版本不行用 B 版本
- 发送按钮双路径适配
- 点击发送 → 关闭会话 → 退出会话 → 返回列表 → 本轮结束