这一篇我们接着上一篇往下聊。
如果你还没看过第一篇,简单回顾一下大体框架:我们计划用浏览器插件把抖音直播间页面作为一个“数据源”,实时捕捉评论区的新消息,然后把这些消息交给豆包API处理,最后再把AI生成的回复自动填写到直播间的输入框里,实现半自动或全自动互动。上一篇文章已经把豆包API的接入方式、鉴权流程、以及最基础的“发一条消息给豆包,拿到回复”这条链路跑通了。
这篇文章要解决的是整个流程里最关键的中间环节:插件开发和网页捕捉。
说白了,就是两件事:
- 怎么做一个浏览器插件,让它能在直播间页面后台运行。
- 怎么从这个不断滚动的评论区里,精准、不重复、不遗漏地抓到我们需要的评论内容。
这篇文章会把这套方案的架构思路、插件的核心代码结构、DOM捕捉的技巧、常见的坑和排查方法全部讲透。文章偏实战,代码会直接贴出来,你可以照着抄,改一改就能用在自己的项目里。
1. 整体架构设计:为什么非要绕一圈用插件,而不是直接调API
在动手写代码之前,先聊清楚一个很多人都会问的问题:抖音直播间的评论数据,直接通过JavaScript请求接口拿不就行了吗?为什么还要费劲搞一个浏览器插件去“捕捉”网页内容?
这个问题的答案,决定了整个项目的架构走向。
首先,是数据接口的不可控性。
抖音直播间的评论数据确实是通过内部接口传输的,但这些接口通常是加签名的、动态变化的、并且依赖特定的请求头。你可以在浏览器控制台里看到这些请求,但想要在外部环境中模拟出来,需要逆向分析签名算法,而且这个算法随时可能更新。一旦更新,你的代码就会彻底失效,需要重新分析。而浏览器插件的方式完全绕开了这个环节——我们不碰接口,我们只“看”页面。页面显示什么,我们就读什么。抖音前端团队升级、改版,只要页面上的文字还在渲染,我们的插件就能继续工作。这是一种“寄生”式的方案,稳定性反而更高。
其次,是跨域限制和登录态的问题。
就算你逆向出了接口,请求的时候还需要带上完整的Cookie和鉴权信息。这些信息在外部环境(比如Node.js脚本)里很难持久化维护,而且频繁调用还可能触发账号风险。而浏览器插件运行在页面上下文中,天然继承了你的登录状态。你不需要处理任何Cookie、Token、签名,因为你在浏览器里看到的页面本身,就是已经通过验证的。
第三,是互动回写的需求。
别忘了,我们的目标不只是“读取”评论,还要“回复”评论。回复这个动作,本质上就是往直播间的输入框里填入文字、模拟发送。这个操作如果脱离浏览器环境,需要自己去构造WebSocket消息或者调用发消息的接口,复杂度直接翻倍。而在插件里,只需要操作DOM元素,模拟键盘输入和点击事件就行了。
所以,架构就清晰了,整个链路分为四层:
- 数据源层:抖音直播间页面,我们捕捉的对象。
- 捕捉层:Content Script(内容脚本),注入到页面中,监听DOM变化,提取评论数据。
- 处理层:Background Service Worker(后台脚本),接收Content Script发来的数据,调用豆包API,拿到AI回复。
- 回写层:Content Script把AI回复填入直播间输入框,完成互动闭环。
用一张简单的流程图表示就是:
code复制直播间页面(评论)
↓ (DOM监听)
Content Script 捕捉模块
↓ (chrome.runtime.sendMessage)
Background Service Worker
↓ (fetch调用)
豆包API
↓ (返回回复)
Background Service Worker
↓ (chrome.tabs.sendMessage)
Content Script 注入回复模块
↓ (模拟输入)
直播间输入框
这四层各司其职,使用浏览器插件最标准的Manifest V3架构来组织。下面我把每一层的实现细节拆开讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 插件骨架:Manifest V3下的项目结构
网上很多插件教程还在用Manifest V2,但Chrome已经在逐步淘汰V2了,新开发的插件直接用V3。V3和V2最大的区别在于后台脚本从常驻的background.html换成了事件驱动的service worker,而且不能用XMLHttpRequest,只能用fetch。好在fetch对Service Worker支持得很好,调用豆包API完全没问题。
这部分的代码结构如下:
code复制douyin-ai-plugin/
├── manifest.json # 插件清单文件,核心配置
├── background.js # 后台服务,负责调用豆包API
├── content.js # 内容脚本,捕捉评论和注入回复
├── popup.html # 弹出页面,显示状态和配置
├── popup.js # 弹出页面的逻辑
└── icons/
├── icon16.png
├── icon48.png
└── icon128.png
先看最重要的manifest.json,这是插件的入口配置:
json复制{
"manifest_version": 3,
"name": "直播间AI互动助手",
"version": "1.0.0",
"description": "捕捉直播间评论,调用豆包API自动生成回复",
"permissions": [
"storage",
"activeTab",
"scripting"
],
"host_permissions": [
"https://live.douyin.com/*",
"https://ark.cn-beijing.volces.com/*"
],
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["https://live.douyin.com/*"],
"js": ["content.js"],
"run_at": "document_idle"
}
],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
}
}
很多人在host_permissions这里容易忽略细节。如果你的豆包API是通过https://ark.cn-beijing.volces.com这个域名访问的,那这里一定要加上这个域名的权限。我之前见过一个案例,fetch请求在页面上正常,放到Service Worker里就报跨域错误,原因就是漏配了这个字段。V3里跨域请求的域名白名单是严格受host_permissions控制的,少了它,请求根本发不出去。
另外,content_scripts的matches字段限定了插件只在抖音直播页面生效,别搞成<all_urls>,否则每个页面都执行脚本,既影响性能,也很容易被识别为可疑行为。
run_at设置为document_idle是为了确保页面DOM基本加载完成后再注入脚本,避免过早执行导致找不到目标节点。虽然我们后面要用MutationObserver监听动态节点,但首屏的基础结构还是要等加载完才好定位。
3. 网页捕捉的核心:如何精准抓取直播间评论
这是整个项目技术含量最高的部分,也是大部分新手最容易卡住的地方。直播间的评论是实时刷新的,DOM节点不断被创建和移除,而且评论数据分布在不同的元素里,怎么稳定地拿到每一条新评论,并且保证不重复、不遗漏?
3.1 定位评论容器:选择器不是写死就能万事大吉
抖音直播间的DOM结构隔一段时间就会调整。你在今天写死的css选择器,可能下周就失效了。所以第一步不是急着写选择器,而是打开开发者工具,花点时间分析当前直播间的DOM结构。
以网页版抖音直播间为例(不同版本的结构可能有差异),评论区通常在一个带有滚动条的子容器内,每一条评论是一个独立的元素,类似这样:
html复制<div class="webcast-chatroom___item">
<div class="webcast-chatroom___nick-name">用户名</div>
<div class="webcast-chatroom___content">评论内容</div
