竞品上新监控:用搜索 API 盯住对手发布了什么新功能
做产品和做运营的人都有同一个需求:竞品昨晚发了新功能、改了定价页、上了新集成,我今天早上就想知道。靠刷对方官网和 RSS 是笨办法------你只能覆盖你知道的那几个页面。更稳的路子是拿一组"竞品 × 动作"查询词定期搜一遍,看哪些页面的标题和位置变了。
这篇给一个能天天跑的监控脚本:固定一组查询词,每天拉一次首屏,和昨天的快照做 diff,输出"新增/消失/位次变化"三张表。参数与字段以 SerpBase 官方文档的 search 端点说明 为准;每次成功请求 1 credit,成本低到可以每天跑。
为什么用搜索而不是爬官网
爬官网的问题是你得先知道有哪些页面。竞品的更新日志、定价页、changelog、文档新页面,有的在 /blog,有的在 /docs,有的藏在 /whats-new------你漏一个入口就漏一类更新。
搜索结果不一样:你搜"竞品名 + changelog",Google 已经替你把全网相关页面按相关度排好了,包括你自己没想到的第三方测评、Integration 目录页、GitHub release 讨论。你要的是"这个竞品最近网上出现了什么新页面",不是"我盯着的那几个 URL 变了没有"------前者覆盖面大得多,而且首屏排序本身就是相关度信号。
监控脚本
python
import csv, json, pathlib, requests
from datetime import date
API = "https://api.serpbase.dev/google/search"
KEY = "你的 API Key"
HEADERS = {"X-API-Key": KEY, "Content-Type": "application/json"}
# 查询词组:竞品名 × 动作词,固定不变才能比
WATCH = [
("竞品A", "changelog"),
("竞品A", "pricing"),
("竞品A", "new feature"),
("竞品B", "release notes"),
("竞品B", "integration"),
]
def search(q: str, hl: str = "en", gl: str = "us") -> list:
resp = requests.post(API, headers=HEADERS,
json={"q": q, "hl": hl, "gl": gl, "page": 1}, timeout=30)
data = resp.json()
if data.get("status") != 0:
return []
return data.get("organic", [])
def snapshot() -> dict:
"""今天的快照:{查询词: {链接: 位次}}"""
snap = {}
for brand, action in WATCH:
q = f"{brand} {action}"
items = search(q)
snap[q] = {it["link"]: it["rank"] for it in items if it.get("link")}
return snap
def diff(today: dict, yesterday: dict) -> dict:
out = {"新增": [], "消失": [], "位次变化": []}
for q, links in today.items():
old = yesterday.get(q, {})
for link, rank in links.items():
if link not in old:
out["新增"].append({"查询词": q, "链接": link, "位次": rank})
elif old[link] != rank:
out["位次变化"].append({"查询词": q, "链接": link,
"旧位次": old[link], "新位次": rank})
for link, rank in old.items():
if link not in links:
out["消失"].append({"查询词": q, "链接": link, "旧位次": rank})
return out
if __name__ == "__main__":
hist = pathlib.Path("watch_history")
hist.mkdir(exist_ok=True)
day = date.today().isoformat()
today_file = hist / f"{day}.json"
today = snapshot()
if today_file.exists():
today = json.loads(today_file.read_text("utf-8"))
else:
today_file.write_text(json.dumps(today, ensure_ascii=False), encoding="utf-8")
prev = sorted(hist.glob("*.json"))[-2] if len(list(hist.glob("*.json"))) > 1 else None
if not prev:
print("首个快照已保存,明天开始出 diff")
else:
d = diff(today, json.loads(prev.read_text("utf-8")))
for kind, rows in d.items():
if not rows:
continue
with open(f"watch_{kind}_{day}.csv", "w", newline="", encoding="utf-8-sig") as f:
w = csv.DictWriter(f, fieldnames=list(rows[0].keys()))
w.writeheader()
w.writerows(rows)
print(f"{kind}: {len(rows)} 条 → watch_{kind}_{day}.csv")
三条监控经验
- 查询词组固定,是可比性的前提。 每周加一个新词没问题,但加进去的词要从下周期开始对比,别中途替换------替换掉的词历史全废,新加的词没有昨天可比的基线。趋势分析的前提就是查询集不变。
- "新增"要看域名归属再决定要不要点。 新增一条
competitor.com/blog/new-feature-x是强信号;新增一条reddit.com/r/.../competitor-discussion是社区反应,也值得看;新增一条g2.com/...多半是评测目录页刷新,信息量低。脚本只给链接,判断哪条值得读是你的活。 - 位次变化比新增更早暴露动作。 竞品发了新功能,往往先是自己的 changelog 页在相关查询里位次上升,然后第三方才开始转载。所以"changelog 页从第 8 位升到第 2 位"这个信号,通常比"新增了一条新闻"来得更早。
成本账
5 个查询词 × 每天 1 次 = 5 credits/天,一个月 150 credits。按 $10/20k 的标准包算,一个月成本不到一分钱;100 次免费额度够跑 20 天。这大概是你能找到的最便宜的竞品监控方案------而且覆盖面比手动刷官网大。
FAQ
查询词里的竞品名要用官方全称吗? 用用户会搜的那个名字,不一定是工商全称。比如大家嘴上叫"XX云"、官网上写"XX Cloud",监控词用前者------你要的是模拟真实搜索行为,不是对齐官方命名。
hl/gl 怎么设? 跟你的目标市场走。盯国内市场用 hl=zh-CN、gl=cn;盯海外用默认 en/us。同一个竞品在不同市场的声量表现可能差很多,值得分市场各跑一组。
位次波动多大算异常? 首屏(前 10 条)内 ±2 位属正常抖动,超过 3 位或整条进出首屏值得点开看。这也是脚本里把"位次变化"单独出一张表的原因------新增可能天天有,位次大幅变化才是真信号。
organic 数组会为空吗? 会,它是可选字段("解析到自然结果时"才有)。脚本里用 data.get("organic", []) 兜底,空结果不报错,当"今天这组词没有相关页面"处理。
把 WATCH 换成你的竞品名单和动作词,先跑一周看噪声水平,再决定要不要加告警------大多数团队第一周就会发现,真正的信号一周就那么两三条。