twitter-interact — 工具说明
本文是
expert-bd专家包内的工具说明书,不独立出现在技能列表中。由相关 Workflow 指引调用。
在 Twitter/X 上执行互动操作:点赞 / 取消点赞 / 转推 / 取消转推 / 收藏 / 取消收藏 / 关注 / 取关。
输入:推文 URL(https://x.com/<user>/status/<id>)或用户 handle(@xxx / 主页 URL)+ 动作类型。
输出:{ok, tweet_id|user, action, session} JSON;已处于目标态时输出 note: 已... + exit 0。
Reply / Quote 属于
twitter-post的发布范畴,不在本工具能力范围内。本工具与 login-manager 完全无关——互动是纯浏览器操作,走持久化 session
twitter-post共用同一个 session),登录态在 session profile 里闭环,不导出 cookie/UA 落中央存储。
9 个子命令
| 子命令 | 目标 | 频率限制 |
|---|---|---|
like <tweet> |
点赞 | 1 min / 200 / 日 |
unlike <tweet> |
取消点赞 | 1 min / 200 / 日 |
retweet <tweet> |
转推(纯转,不Quote) | 5 min / 50 / 日 |
unretweet <tweet> |
取消转推 | 5 min / 50 / 日 |
bookmark <tweet> |
收藏 | 1 min / 100 / 日 |
unbookmark <tweet> |
取消收藏 | 1 min / 100 / 日 |
follow <user> |
关注用户 | 5 min / 50 / 日 |
unfollow <user> |
取关用户 | 5 min / 50 / 日 |
run |
一键跑(全流程:login 探活 + 操作) | — |
频率限制:平台 anti-automation 阈值 + 经验值(30 min 风险窗口 / reply 27x like 权重)。如触发风控 → 24h 静默。
前置条件
1. 探活与登录(本工具自管,不走 login-manager)
走持久化 session twitter(与 twitter-post 共用同一个 session 名 twitter,靠 session 名字符串约定共享同一 profile 目录与登录态——任一工具登录后另一个不需重登)。探活方式:开 session open 平台首页 + snapshot 看是否跳登录页。
run 子命令在脚本内自动探活(_check_session_alive);单条子命令(like / retweet / ...)不内嵌探活,调用方(agent)按下方流程先探活再调单条。
# 探活(默认无头模式)
camoufox-cli --session twitter --persistent --json open "https://x.com/"
sleep 3
camoufox-cli --session twitter --json snapshot
# snapshot 看页面是否跳到登录页 / 出现登录按钮 / 推文是否正常可见
# → 没跳登录页、内容正常 = 登录态有效,探活完即 close session(登录态在磁盘 profile,后续操作按需重起无头复用)
# → 跳到登录页 / 出现登录按钮 = 登录态失效,走重登
重登流程(失效时)——登录流程按 browser-guide skill 走有头手动登录(手机号+验证码 / Twitter APP 扫码),登录后close session——登录态落磁盘 profile,不留进程占内存。互动操作用 --session twitter --persistent 重起无头即恢复,用完再 close。只在 session 卡死时由调用方手动 camoufox-cli --session twitter --json close teardown。
# X 登录风控对无头 + QR 识别严格,有头人工登录最稳
camoufox-cli --session twitter --persistent --headed --json open "https://x.com/login"
# 告知用户「**Twitter/X** 浏览器已打开,请在窗口里手动完成登录(账号密码 / 手机 APP 扫码),完成后告诉我」
# 等用户回复后 snapshot 验登录态就位
# 登录就位后 close session——登录态落磁盘 profile,按需重起无头复用
不导出 cookie/UA——登录态只在 session profile 里闭环,不落 ~/.openclaw/logins/。本工具不调用 cookies export / identity export。
2. 频率跟踪文件(首次自动创建)
~/.openclaw/agents/main/sessions/twitter-interact-frequency.json —— 每次成功互动操作后自动 append。发布频率在 twitter-post 的 twitter-frequency.json,两者分开追踪、互不影响。
3. 单一持久化 session twitter(与 twitter-post 共用)
所有互动操作共享同一个 --persistent session twitter(指纹冻结 + cookie 留 profile)。并发调用由 forked cli 的 fail-first 队列串行拒绝——脚本不自动排队、不自动等待,读到 session twitter 正忙 文本时 exit 3,调用方(agent)应等待当前操作完成后再试。
与 twitter-post 共 session:两者都用 --session twitter,共享同一 profile 目录与登录态——一方登录后另一方不需重登。靠 session 名字符串约定即可,无需别的机制。
调用方式
单条操作
# 点赞
twitter-interact like https://x.com/username/status/1234567890
# 转推
twitter-interact retweet https://x.com/username/status/1234567890
# 关注
twitter-interact follow @openai
# 或
twitter-interact follow https://x.com/openai
一键跑
# 一键:login 探活 → 操作
twitter-interact run --tweet-url <url> --action <like|retweet|bookmark>
twitter-interact run --user <handle> --action <follow|unfollow>
并发约束(fail-first,不并行)
# 单一 session twitter,并发调用由 forked cli fail-first 队列拒绝
# 脚本读到 "session twitter 正忙" → exit 3,agent 应等待重试(不自动排队)
# 串行使用:每次操作用完即 close session(登录态在磁盘 profile),下一次重起无头复用同一 profile
脚本实现要点
twitter_interact.py内置三个模式,agent 无需手写 eval:
- article-scoped 探针:按 tweet_id 定位含
a[href*="/status/<id>"]的 article,按钮查找限定其内——会话页有多 article,barequerySelector('[data-testid="like"]')会抓第一个(父推)误操作。- testid 确认菜单:retweet→
[data-testid="retweetConfirm"]、unretweet→unretweetConfirm、unfollow→confirmationSheetConfirm,比 text match 稳且不受本地化影响。- 晚水合轮询:Python 侧 20×500ms 找按钮 / article,确认菜单 20×250ms。
- 按钮互换验证状态:like↔unlike、bookmark↔removeBookmark、retweet↔unretweet、-follow↔-unfollow,点击后轮询对立按钮出现确认成功(非 aria-pressed)。
单条 like(典型)
1. 探活(见「探活与登录」段)→ 登录态有效继续,失效走重登
2. camoufox-cli --session twitter --persistent open https://x.com/i/web/status/<id>
└─ 若 session 正忙 → forked cli fail-first → 脚本 exit 3(不 close 正在跑的 session,不排队)
注:操作执行 + 探活都走默认无头(自动化操作无需用户在场);只有登录走有头
3. 脚本 _poll_probe(tid, ["unlike","like"]):
├─ unlike 在 → 已点赞,输出 note + exit 0(不记频率)
├─ like 在 → _click_scoped(tid,"like") → _poll_probe(tid,["unlike"]) 验翻转 → record + 输出
└─ 10s 内都没找到 → exit 1(DOM 未加载或未登录)
4. check_freq_limit(操作前已校验)→ 通过则 record_action
5. close session(登录态在磁盘 profile,下次按需重起无头复用)
6. 输出 {ok, tweet_id, action, session}
retweet(带 confirm 菜单)
1-3. 同 like(探针找 unretweet/retweet)
4. _click_scoped(tid,"retweet") → 弹 confirm 菜单
5. _click_confirm("retweetConfirm"):轮询 20×250ms 找 [data-testid="retweetConfirm"] 并 click
└─ 用 testid 不用 text,结构上不可能选成 Quote
6. sleep 1s → _poll_probe(tid,["unretweet"]) 验翻转 → record
7. 输出 {ok, tweet_id, action, session}
follow
1-2. camoufox open https://x.com/<handle>
3. _poll_suffix(["-unfollow","-follow"]):
├─ -unfollow 在 → 已关注,note + exit 0
├─ -follow 在 → _click_suffix("-follow") → sleep 1s → _poll_suffix(["-unfollow"]) 验翻转 → record
└─ 都没找到 → exit 1
4. check_freq_limit (follow: 5 min, 50/day)
5. record_action + close session(登录态在磁盘 profile)
unfollow(带 confirm 菜单)
1-2. camoufox open https://x.com/<handle>
3. _poll_suffix(["-follow","-unfollow"]):-follow 在 → 未关注 note;-unfollow 在 → 继续
4. _click_suffix("-unfollow") → 弹 confirm
5. _click_confirm("confirmationSheetConfirm"):轮询找 [data-testid="confirmationSheetConfirm"] 并 click
6. sleep 1s → _poll_suffix(["-follow"]) 验翻转
7. close session(登录态在磁盘 profile)
频率限制(详细)
| 动作 | 最小间隔 | 日上限 | 周上限 | 触发后行为 |
|---|---|---|---|---|
| like | 60s | 200 | 1000 | 24h 静默 |
| retweet | 300s | 50 | 200 | 24h 静默 |
| bookmark | 60s | 100 | 500 | 24h 静默 |
| follow | 300s | 50 | 200 | 24h 静默 |
| unfollow | 300s | 50 | 200 | 24h 静默 |
频率跟踪文件:~/.openclaw/agents/main/sessions/twitter-interact-frequency.json
{
"actions": {"like": 23, "retweet": 5, "follow": 2},
"today_count": 30,
"week_count": 120,
"last_action_at": "2026-07-05T09:30:00+08:00",
"last_action_type": "like"
}
风控告警阈值:日累计 50% 上限时输出 warning(不是 hard block)。
错误处理
| 情况 | 处理 |
|---|---|
| Cookie 失效(探活 exit 2) | 走「探活与登录」段重登流程(browser-guide,有头手动登录),完成后重试一次 |
| session 正忙(forked cli fail-first) | exit 3 + 透传 busy 文本,不 close(避免 tear down 正在跑的另一个操作),agent 等待重试 |
| Tweet ID / Handle 解析失败 | exit 1(提示格式错) |
| 频率限制触发 | exit 1(提示等待时间) |
| 按钮已是对立态(unlike/unretweet/-unfollow 在) | 输出 note: 已... + exit 0,不记频率 |
| 探针 10s 内未找到按钮 / article(DOM 未水合或未登录) | exit 1,提示检查登录态或 selector |
| 频率触发风控 | 立即记录 + 24h 静默 + exit 1 |
Pitfalls
pitfall: 会话页抓到父推的按钮(非目标推)
- 症状:conversation / thread 页有多个 article,bare
document.querySelector('[data-testid="like"]')抓第一个(通常是父推),点赞/转推到错的推 - workaround:脚本已用 article-scoped 探针——按 tweet_id 找含
a[href*="/status/<id>"]的 article,按钮查找限定其内。agent 不要绕过脚本手写 bare selector
pitfall: retweet 误选 Quote
- 症状:点 retweet 按钮后菜单有 "Repost" / "Quote" 两项,选错成 Quote → 推出去带评论
- workaround:脚本用
[data-testid="retweetConfirm"]定位确认按钮,结构上不可能选成 Quote。不要改回 text match(本地化/改版易碎)
pitfall: 晚水合——按钮 / confirm 菜单延迟出现
- 症状:X 是 CSR + 水合,刚 open 完 eval 立刻找按钮常返回 null;confirm 菜单 click 后也需 100-500ms 才渲染
- workaround:脚本 Python 侧轮询——按钮/article 20×500ms(共 10s),confirm 菜单 20×250ms(共 5s)。agent 不要用单次 eval + sleep 2s 重试 3 次的旧模式
pitfall: 用 aria-pressed 判断 like 状态不可靠
- 症状:X 的 like 按钮 aria-pressed 时有时无、值不一致,按它判状态常误判
- workaround:脚本用按钮互换模型——看 unlike 在就是已点赞、like 在就是未点赞,点击后轮询对立按钮出现确认成功。不读 aria-pressed
pitfall: 频率间隔未严格遵守
- 症状:连发点赞 / 转推 → X 触发 "This request looks like it might be automated"
- workaround:check_freq_limit 在每次操作前校验,强制 wait
pitfall: 并发调用撞 fail-first 队列
- 症状:两个 twitter-interact 调用同时跑 → 第二个收到
session twitter 正忙→ exit 3 - workaround:这是预期行为(单一 session + forked cli fail-first)。agent 读到 exit 3 应等待当前操作完成再重试,不自动排队、不自动 close session(close 会 tear down 正在跑的那个操作)
pitfall: X UI 改版 → testid 失效
- 症状:
[data-testid="like"]/retweetConfirm等找不到 - workaround:本工具的 testid 积淀自 OpenCLI
clis/twitter/(实战维护中),比公开推测稳;仍需部署后真机验证。看到 exit 1 时应触发 selector 检查
Notes
- 发布频率与互动频率分开追踪,互不影响
- 不与 published-track 共享频率统计(本工具自有 FREQ_TRACKER_PATH)
- BD 常用组合:关注目标用户(follow)+ 点赞目标推(like)+ 收藏(bookmark)
- 不导出 cookie/UA,不用
identity export