> 基于 2026-06-01 多轮真实测试验证通过。
> 测试账号:小小程序猿🐒
从抖音作品的评论区中提取评论用户,逐个执行:
https://www.douyin.com/article/{id}https://www.douyin.com/video/{id}```bash
openclaw browser start
```
http://127.0.0.1:18800)| 工具 | 用途 | 说明 |
|---|---|---|
| ------ | ------ | ------ |
Playwright (chromium) | 浏览器自动化 | 通过 CDP 连接 OpenClaw Chrome |
page.goto() | 页面导航 | 跳转到作品页、用户主页 |
page.evaluate() | 执行 JS | 所有 DOM 操作(查找元素、点击、提取数据) |
page.locator() | 定位元素 | 检测编辑器是否可见 |
page.keyboard.type() | 键盘输入 | 私信内容输入(delay模拟真人) |
page.keyboard.press('Enter') | 发送消息 | 按 Enter 键发送私信 |
document.querySelectorAll() | 查找元素 | 提取评论区用户链接 |
Element.getBoundingClientRect() | 获取位置 | 判断元素可见性和位置 |
Element.click() | 原生点击 | 触发 React 事件(比 dispatchEvent 稳定) |
1. 打开作品页
2. 滚动到评论区
3. 提取所有评论用户(跳过自己)
4. 取前 N 个用户(建议 ≤3)
↓ 逐个处理:
a. 跳转到该用户主页
b. 检查是否已关注
c. 未关注 → 点「关注」
d. 点「私信」
e. 输入打招呼内容
f. 按 Enter 发送
g. 等待 3-5 秒
h. 处理下一位
5. 全部完成
const page = await context.newPage();
await page.goto('https://www.douyin.com/article/7645340255293426982', {
waitUntil: 'domcontentloaded',
timeout: 15000
});
await new Promise(r => setTimeout(r, 5000));
> 作品可以是图文(/article/{id})或视频(/video/{id})。
> 应该选评论区活跃的作品(点赞数高的通常评论也多)。
await page.evaluate(() => {
for (const el of document.querySelectorAll('*')) {
if (el.textContent.includes('全部评论')) {
el.scrollIntoView({ block: 'start' });
break;
}
}
});
await new Promise(r => setTimeout(r, 2000));
> 不要用 window.scrollBy —— 评论区在独立滚动容器里,但用户提取只需要第一屏评论可见即可。
> 如果要加载更多评论(数量少时),滚动容器:.parent-route-container。
const users = await page.evaluate(() => {
const allLinks = document.querySelectorAll('a[href*="/user/"]');
const seen = new Set();
const results = [];
for (const a of allLinks) {
const href = a.getAttribute('href') || '';
// 跳过自己
if (href.includes('self')) continue;
const rect = a.getBoundingClientRect();
if (rect.y < 300 || rect.y > 3000) continue;
const name = a.textContent.trim();
// 过滤无效数据
if (!name || name.length < 1 || name.length > 12) continue;
if (name.includes('作者') || name.includes('回复') || name.includes('分享')) continue;
if (name === '0' || name === '1' || name === '2' || name === '') continue;
if (seen.has(name)) continue;
seen.add(name);
const fullUrl = href.startsWith('//') ? 'https:' + href : href;
results.push({ name, url: fullUrl });
}
return results;
});
// 取前3个
const targets = users.slice(0, 3);
过滤规则说明:
href.includes('self') — 跳过自己的主页链接name.includes('作者') — 跳过自己出现在评论区("小小程序猿🐒 作者")name === '0'/'1'/'2' — 跳过点赞数(误识别)rect.y < 300 — 跳过顶部导航/个人资料区name.length 1-12 — 正常用户名长度范围await page.goto(target.url, { waitUntil: 'domcontentloaded', timeout: 15000 });
await new Promise(r => setTimeout(r, 4000));
> 不要尝试点击用户名/头像来跳转 —— 抖音的 SPA 路由会拦截点击。
> 直接用 page.goto() 导航到用户的 https://www.douyin.com/user/{user_id} 最稳定。
// 先检查是否已关注
const isFollowed = await page.evaluate(() =>
document.body.innerText.includes('已关注')
);
if (!isFollowed) {
await page.evaluate(() => {
for (const el of document.querySelectorAll('*')) {
if (el.textContent.trim() === '关注') {
const rect = el.getBoundingClientRect();
// 用户信息区的关注按钮在右侧(x>900),宽度>50
if (rect.x > 900 && rect.width > 50) {
el.click();
return;
}
}
}
});
await new Promise(r => setTimeout(r, 2000));
}
按钮位置说明:
关注(x≈986)和 私信(x≈1082)class="semi-button" 渲染rect.x > 900 来过滤掉左侧导航栏的「关注」标签// 点击私信按钮
await page.evaluate(() => {
for (const el of document.querySelectorAll('*')) {
if (el.textContent.trim() === '私信') {
const rect = el.getBoundingClientRect();
if (rect.x > 1000 && rect.width > 50) {
el.click();
return;
}
}
}
});
await new Promise(r => setTimeout(r, 2000));
// 输入并发送
const editor = page.locator('[contenteditable]').first();
if (await editor.isVisible().catch(() => false)) {
await editor.click();
await new Promise(r => setTimeout(r, 300));
await page.keyboard.type('你好,感谢你为流浪狗发声。', { delay: 12 });
await new Promise(r => setTimeout(r, 500));
await page.keyboard.press('Enter');
await new Promise(r => setTimeout(r, 3000));
}
私信输入说明:
- 只能用
keyboard.type 输入,不能用 innerHTML 或 execCommand - 按 Enter 发送(不是点发送按钮)
Step 7:处理下一位
// 每个人之间间隔 3-5 秒
await new Promise(r => setTimeout(r, 3000));
// 回到 Step 4,处理下一位用户
⚠️ 注意事项与风控
风控防护(最重要)
风险 解决方案 :---- :--------- 每条私信内容相同 每人都发不一样的内容 操作频率太快 每人间隔 3-5 秒,每天 ≤3-5 人 被举报 私信内容要礼貌、自然,不要营销 验证码弹窗 立即停止,手动验证后继续 账号被限制 严格遵守频率限制
私信内容规范
❌ 不行:
- "添加微信xxx" "点击链接xxx"(营销感太重)
- 每个人发一模一样的文字
- 明显AI生成的套话
✅ 可以:
- "哈喽,感谢你为流浪狗发声。"
- "你好呀,看到你也关注流浪动物,感觉遇到同好了~"
- "谢谢你的支持!希望每只流浪的小动物都能遇到好心人🐾"
- "看到你的评论好暖心,替流浪的它们谢谢你🙏"
已知限制
- 私密账号:可以关注(发起关注请求),但不能发私信
- 一条限制:对方回复你之前,只能发一条文字消息
- 只能文字:首次消息只能是文字,不能发图片/链接
- 每天限制:抖音对私信有风控,每天 3-5 条比较安全
⏱ 时间间隔建议
点关注 → 等 2 秒
点私信 → 等 2 秒
输入内容 → 1 秒
按 Enter → 等 3 秒
进入下一个人 → 等 3-5 秒
每处理 5 人 → 休息 1 分钟
❓ 常见问题
Q: 为什么找不到用户?
可能原因:
- 作品没有评论(刚发布或无人互动)
- 评论区需要滚动加载(用容器
.parent-route-container 滚动) - 所有用户都是自己的号或已处理过的
Q: 关注按钮点了没反应?
可能原因:
- 点的位置不对(点到了左侧导航的「关注」标签)
- 已经关注过了(按钮变成「已关注」)
- 需要先登录
解决: 用 rect.x > 900 过滤位置
Q: 私信发不出去?
可能原因:
- 对方是私密账号(只能关注不能私信)
- 已经发过一条(对方没回复前只有一条额度)
- 输入框没聚焦
Q: 怎么确认私信发送成功?
检查页面文本: 发送成功后聊天面板会出现你发的消息内容
Q: 浏览器断开连接了?
# 重启浏览器
openclaw browser stop
openclaw browser start
🐛 踩坑记录(2026-06-01 实战)
问题 表现 根因 修复 :---- :------ :---- :------ 用户名点不进主页 点击无反应 SPA 路由拦截点击 用 page.goto() 直接导航 头像点不进主页 还在原页面 同上 用 page.goto() 直接导航 点到自己的主页 看到自己的资料 href 包含 self过滤 href.includes('self') 点到「作者」的链接 处理了自己 「小小程序猿🐒 作者」也在评论区 过滤 name.includes('作者') 关注到了左侧标签 点了没反应 x<100 的「关注」是导航标签 用 rect.x > 900 过滤 私信点到了顶部导航 打开了消息列表页 顶部也有「私信」按钮 用 rect.x > 1000 过滤 输入框找不到 编辑器返回空 私信面板还没加载完 等 2 秒再找 backtick 在 zsh 中报错 shell 解析错误 反引号被 zsh 解释 脚本写入文件再执行 let 在 zsh eval 中报错parse error zsh 不识别 let ui=0 写入 .cjs 文件再执行 私信内容太官方 用户觉得是机器人 回复模板化 每条都不一样,像真人聊天
共 1 个版本