前言
抖音PC端没有开放聊天API,想做消息监控或自动回复只能自己动手。传统方案是抓包拦截WebSocket,门槛高且容易被检测。本文介绍一种纯前端注入方案,零依赖,浏览器控制台粘贴即用。
核心思路
- MutationObserver 监听DOM变化,实时捕获新消息
- data-index="0" 始终指向最新一条消息,避免全量扫描
- classList 判断发送/接收方向(
messageMessageBoxisFromMe) - document.execCommand 向Slate富文本编辑器写入内容并模拟发送
踩坑记录
消息重复输出
[class*="message"] 选择器太宽泛,匹配到了消息容器的子元素,一条消息被处理多次。改用精确类名 .messageMessageBoxmessageBox 解决。
昵称互相覆盖
用一个变量 lastNick 记住上一个昵称,自己和对方的昵称会互相覆盖。拆分为 lastSelfNick / lastOtherNick 分别记录。
发送后旧消息重复
DOM重新渲染后元素引用失效,Set 去重失败。改用 data-index="0" 只监听最新消息,配合 lastContent 内容对比去重。
两个data-index="0"
左侧会话列表也有 data-index="0",querySelector 会误匹配。遍历所有 data-index="0",只取包含 .messageMessageBoxmessageBox 的那个。
写入输入框但发送按钮禁用
直接改 textContent 不会触发Slate编辑器内部状态更新。改用 document.execCommand('insertText') + Selection API,Slate能正确识别。
连发相同消息被吞
按内容去重导致相同内容被过滤。改为只对比 lastContent,新消息插入后 data-index="0" 的DOM元素变了,自然不会被误判。
功能
- 实时监听:文本、图片、大表情、小表情、分享视频
- 昵称识别:连续消息无头像时自动继承上一条昵称
- 关键词自动回复:可配置多条规则,3秒冷却防刷屏
- 重复注入自动清理:断开旧Observer,重新启动
使用方法
- 打开抖音PC端,进入聊天页面
- F12打开控制台,粘贴代码回车
- 修改
autoReply数组配置关键词和回复
const autoReply = [
{ keyword: '你好', reply: '你好呀~' },
{ keyword: '在吗', reply: '在的~' },
{ keyword: '加群', reply: '群主,群众中有坏蛋' },
];完整代码
(function() {
if (window.__chatMonitorObserver) {
window.__chatMonitorObserver.disconnect();
window.__chatMonitorObserver = null;
console.log('[已移除旧注入,重新启动]');
}
window.__chatMonitorRunning = true;
let lastContent = '';
let lastSelfNick = '';
let lastOtherNick = '';
const autoReply = [{
keyword: '你好',
reply: '你好呀~'
},
{
keyword: '在吗',
reply: '在的~'
},
{
keyword: '加群',
reply: '群主,群众中有坏蛋'
},
];
let replyCooldown = false;
function getNick(el) {
const nameEl = el.querySelector('.MessageBoxMessageTitleavatarName');
if (nameEl) return nameEl.textContent?.trim() || '';
return '';
}
function getContent(el) {
const shareBox = el.querySelector('.MessageItemShareAwemecontainer');
if (shareBox) {
const autorName = shareBox.querySelector('.MessageItemShareAwemeautorName');
const coverImg = shareBox.querySelector('img.commonMyImageimgReal');
let result = '[分享]';
if (autorName) result += ' @' + autorName.textContent?.trim();
if (coverImg && coverImg.src) result += ' ' + coverImg.src;
return result;
}
const imgBox = el.querySelector('.MessageItemImageImageBox');
if (imgBox) {
const img = imgBox.querySelector('img');
if (img && img.src) return '[图片] ' + img.src;
return '[图片]';
}
const emojiBox = el.querySelector('.MessageItemEmojiemojiBox');
if (emojiBox) {
const img = emojiBox.querySelector('img');
if (img && img.src) return '[大表情] ' + img.src;
return '[大表情]';
}
const textEl = el.querySelector('.TextMessageTextpureText');
if (textEl) return textEl.textContent?.trim() || '';
const emojiEl = el.querySelector('.TextMessageTextemoji img');
if (emojiEl) {
const title = emojiEl.getAttribute('title');
const src = emojiEl.src;
if (title && src) return title + ' ' + src;
if (title) return title;
if (src) return '[表情] ' + src;
return '[表情]';
}
return '';
}
function sendMessage(text) {
const editor = document.querySelector('[data-slate-editor="true"]');
if (!editor) {
console.log('[自动回复] 未找到输入框');
return;
}
editor.focus();
setTimeout(() => {
const sel = window.getSelection();
const range = document.createRange();
range.selectNodeContents(editor);
sel.removeAllRanges();
sel.addRange(range);
const result = document.execCommand('insertText', false, text);
setTimeout(() => {
const sendBtn = document.querySelector('.e2e-send-msg-btn');
if (sendBtn) {
sendBtn.dispatchEvent(new MouseEvent('click', {
bubbles: true,
cancelable: true
}));
console.log(`[自动回复] 已发送: ${text}`);
} else {
console.log('[自动回复] 未找到发送按钮');
}
}, 800);
}, 300);
}
function checkAutoReply(content, isSelf) {
if (isSelf || replyCooldown) return;
for (const rule of autoReply) {
if (content.includes(rule.keyword)) {
replyCooldown = true;
setTimeout(() => {
replyCooldown = false;
}, 3000);
setTimeout(() => sendMessage(rule.reply), 500);
// console.log(`[自动回复] 匹配关键词"${rule.keyword}",将回复"${rule.reply}"`);
return;
}
}
}
function findChatIndex0() {
const all = document.querySelectorAll('[data-index="0"]');
for (const el of all) {
if (el.querySelector('.messageMessageBoxmessageBox')) return el;
}
return null;
}
function checkLatest() {
const indexEl = findChatIndex0();
if (!indexEl) return;
const msgBox = indexEl.querySelector('.messageMessageBoxmessageBox');
if (!msgBox) return;
if (msgBox.querySelector('.MessageBoxRecalledrecallLayout')) return;
const contentBox = msgBox.querySelector('.messageMessageBoxcontentBox');
if (!contentBox) return;
const content = getContent(msgBox);
if (!content) return;
if (content === '已读' || content === '发送中') return;
if (content === lastContent) return;
lastContent = content;
const isSelf = contentBox.classList.contains('messageMessageBoxisFromMe');
let nick = '';
const hasAvatar = msgBox.querySelector('.commonIMAvataravatarContainer');
if (hasAvatar) {
nick = getNick(msgBox);
if (isSelf) lastSelfNick = nick;
else lastOtherNick = nick;
} else {
nick = isSelf ? lastSelfNick : lastOtherNick;
}
if (!nick) nick = isSelf ? '我' : '对方';
const action = isSelf ? '发送' : '收到';
console.log(`[${action}] 昵称:${nick} 消息:${content}`);
checkAutoReply(content, isSelf);
}
const observer = new MutationObserver(() => {
setTimeout(checkLatest, 200);
});
window.__chatMonitorObserver = observer;
observer.observe(document.body, {
childList: true,
subtree: true
});
setTimeout(checkLatest, 500);
console.log('[监测已启动] 软件/网站/小程序开发,JS逆向,微信: Akaxz_');
console.log('[自动回复规则] ' + autoReply.map(r => `"${r.keyword}"→"${r.reply}"`).join(', '));
})();扩展方向
- 对接后端API,将消息推送到服务器
- 接入AI接口实现智能回复
- 添加更多消息类型支持(语音、视频通话等)
- 打包成Chrome插件,一键启用