从零搭一个抖音竞品监控 Agent
端到端教程:搭一个每天自动跟踪竞品抖音账号、检测新视频、生成分析简报的 Agent,月费不到 $1.20。
先说结论 — 一个完整的 Python agent,每天监控 10 个竞品抖音账号:检测新视频、追踪互动变化、用 LLM 生成竞品简报。费用:数据约 $0.90/月 + LLM 分析约 $0.30/月 = $1.20/月。完整代码在下面,cron 或任何调度器都能跑。
每天早上人工刷 10 个竞品抖音账号、记笔记、写总结?一个月你花 15 小时做这件事。$1.20/月的 agent 每天 7 点自动完成,一天不漏。
Agent 做什么
每天早 7 点:
- 拉每个竞品的用户资料(粉丝数、简介变化)
- 拉他们的最新视频列表(最近 20 条)
- 和昨天的快照对比,找出新发的视频
- 对新视频拉详细互动数据
- 全部数据喂给 LLM 分析
- 输出结构化简报(推 Slack、发邮件或存文件)
需要什么
- SandBase API Key(数据和 LLM 都用同一把)
- Python 3.10+
openai包(pip install openai)
完整代码
#!/usr/bin/env python3
"""抖音竞品监控 agent。
追踪竞品账号、检测新视频、分析趋势。
每天 cron 跑一次:0 7 * * * python3 /path/to/monitor.py
"""
import json
import os
from datetime import datetime, timezone
from pathlib import Path
from openai import OpenAI
# --- 配置 ---
COMPETITORS = [
{"uid": "competitor_1_uid", "name": "品牌 A"},
{"uid": "competitor_2_uid", "name": "品牌 B"},
{"uid": "competitor_3_uid", "name": "品牌 C"},
{"uid": "competitor_4_uid", "name": "品牌 D"},
{"uid": "competitor_5_uid", "name": "品牌 E"},
{"uid": "competitor_6_uid", "name": "品牌 F"},
{"uid": "competitor_7_uid", "name": "品牌 G"},
{"uid": "competitor_8_uid", "name": "品牌 H"},
{"uid": "competitor_9_uid", "name": "品牌 I"},
{"uid": "competitor_10_uid", "name": "品牌 J"},
]
SNAPSHOT_DIR = Path("./snapshots")
SNAPSHOT_DIR.mkdir(exist_ok=True)
client = OpenAI(
base_url="https://api.sandbase.ai/v1",
api_key=os.environ["SANDBASE_API_KEY"],
)
def fetch_profile(uid: str) -> dict:
"""拿用户资料。"""
resp = client.chat.completions.create(
model="douyin/app-v3/user-profile",
messages=[],
extra_body={"uid": uid},
)
return json.loads(resp.choices[0].message.content)
def fetch_video_list(uid: str, count: int = 20) -> list:
"""拿最近视频列表。"""
resp = client.chat.completions.create(
model="douyin/creator/item-list",
messages=[],
extra_body={"uid": uid, "count": count},
)
return json.loads(resp.choices[0].message.content)
def fetch_video_detail(aweme_id: str) -> dict:
"""拿单条视频的详细指标。"""
resp = client.chat.completions.create(
model="douyin/app-v3/video-detail",
messages=[],
extra_body={"aweme_id": aweme_id},
)
return json.loads(resp.choices[0].message.content)
def load_previous(name: str) -> dict:
path = SNAPSHOT_DIR / f"{name}.json"
if path.exists():
return json.loads(path.read_text())
return {"videos": [], "follower_count": 0}
def save_snapshot(name: str, data: dict):
path = SNAPSHOT_DIR / f"{name}.json"
path.write_text(json.dumps(data, ensure_ascii=False, indent=2))
def detect_new(current: list, previous: list) -> list:
prev_ids = {v.get("aweme_id") for v in previous}
return [v for v in current if v.get("aweme_id") not in prev_ids]
def generate_briefing(all_data: list[dict]) -> str:
"""LLM 生成竞品简报。"""
prompt = f"""你是一个专注抖音的竞品分析师。
分析以下竞品活动数据,产出简洁的每日简报。
重点关注:
1. 谁发了新内容,什么主题/形式
2. 显著粉丝变化(>1% 涨跌)
3. 互动异常高的视频(相对其平均水平)
4. 跨竞品的内容策略共性或转变
数据:
{json.dumps(all_data, ensure_ascii=False, indent=2)}
输出结构化简报:
- 一句话总结(不超过 3 句)
- 新内容亮点(按竞品)
- 互动异常
- 给我们品牌的建议动作
"""
resp = client.chat.completions.create(
model="anthropic/claude-sonnet-4",
messages=[{"role": "user", "content": prompt}],
max_tokens=2000,
)
return resp.choices[0].message.content
def run():
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
print(f"[{today}] 开始竞品监控...")
all_data = []
calls = 0
for comp in COMPETITORS:
uid, name = comp["uid"], comp["name"]
print(f" 检查 {name}...")
profile = fetch_profile(uid)
videos = fetch_video_list(uid)
calls += 2
prev = load_previous(name)
new_videos = detect_new(videos, prev.get("videos", []))
details = []
for v in new_videos[:5]:
details.append(fetch_video_detail(v["aweme_id"]))
calls += 1
all_data.append({
"name": name,
"follower_count": profile.get("follower_count", 0),
"follower_change": profile.get("follower_count", 0) - prev.get("follower_count", 0),
"new_videos_count": len(new_videos),
"new_videos": details,
})
save_snapshot(name, {
"videos": videos,
"follower_count": profile.get("follower_count", 0),
"date": today,
})
print(f" 生成简报({calls} 次数据调用)...")
briefing = generate_briefing(all_data)
calls += 1
out = SNAPSHOT_DIR / f"briefing-{today}.md"
out.write_text(f"# 竞品简报:{today}\n\n{briefing}")
print(f" 简报已存:{out}")
print(f" 总调用:{calls},预估费用:${calls * 0.001 + 0.01:.4f}")
if __name__ == "__main__":
run()
逐步拆解
第 1 步:用户资料(10 次调用,$0.01)
每个竞品账号查一次粉丝数、昵称、简介。和昨天对比发现:涨粉 5%?掉粉?改了简介(暗示品牌转型)?
第 2 步:视频列表(10 次调用,$0.01)
拉最近 20 条视频 ID + 发布时间。和昨天的快照 diff 就知道谁今天发了新视频。大部分竞品每天 0-3 条,delta 很小。
第 3 步:新视频详情(0-15 次,$0-$0.015)
只对新视频拉详细数据(播放量、点赞、评论、分享)。每个竞品最多查 5 条新视频,控制成本。
第 4 步:LLM 分析(1 次,约 $0.01)
整批数据一次性喂给 Claude Sonnet 4。输出结构化简报,含可执行建议。
费用
| 组件 | 每天调用 | 单价 | 日费用 |
|---|---|---|---|
| 用户资料 | 10 | $0.001 | $0.010 |
| 视频列表 | 10 | $0.001 | $0.010 |
| 新视频详情 | ~10 | $0.001 | $0.010 |
| LLM 简报 | 1 | ~$0.01 | $0.010 |
| 合计 | ~31 | $0.040/天 |
月费:$1.20/月,监控 10 个竞品。
对比一下:初级分析师每天 30 分钟做同样的事,时薪 ¥150 = ¥2,250/月。Agent 做得更好(每天一条不漏、10 个账号全查完)、费用是人工的 0.3%。
怎么跑
Cron(最简单)
0 7 * * * SANDBASE_API_KEY=sk-... python3 /path/to/monitor.py >> /var/log/monitor.log 2>&1
GitHub Actions(私有仓库免费)
name: 竞品监控
on:
schedule:
- cron: '0 23 * * *' # 北京时间 7 AM = UTC 23:00 前一天
jobs:
monitor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install openai
- run: python monitor.py
env:
SANDBASE_API_KEY: ${{ secrets.SANDBASE_API_KEY }}
扩展思路
加告警:粉丝变化超阈值时立刻发 Slack webhook,不等每日简报。
加微博交叉验证:竞品抖音爆了一条视频时,查他们微博是否同步发了(用 weibo/app/user-timeline),揭示跨平台分发策略。
加趋势:存 30 天快照,让 LLM 识别周趋势:“品牌 A 本月产品演示类内容比上月多 40%“。
局限
- 需要知道 UID:得有竞品的抖音用户 ID,从公开主页 URL 可以拿到
- 频率注意:30 次并发没问题。扩到 100 个竞品(300 次)时隔开几分钟
- 数据时效:互动数据是查询时刻的快照。刚发 1 小时的视频互动还没起来,不代表最终表现
- 只有公开数据:私信、私密视频、限制账号不可访问
FAQ
能监控超过 10 个账号吗?
能。费用线性增长:20 个 ≈ $2.40/月,50 个 ≈ $6/月。超过 50 个建议批次间加 2 秒间隔。
竞品删视频能检测到吗?
能。昨天有今天没有的视频 ID = 被删了。在 detect_new 基础上加 deleted = prev_ids - current_ids。
能用 GPT-4o 替代 Claude Sonnet 4 吗?
能。把 model="anthropic/claude-sonnet-4" 改成 model="openai/gpt-4o",同一个端点、同一把 key。单次分析调用成本差异可忽略。
怎么拿竞品 UID?
从公开主页 URL:https://www.douyin.com/user/{uid}。也可以用 douyin/search/user-search 搜名字后从结果里提取。


