用一个 API 监测微博热搜:一套实用工作流 | SandBase
搭一套微博热搜监测工作流:读榜、搜话题、给作者建档——一把 SandBase key,不用微博登录。

在微博上做社交聆听,归根到底是三个动作:看什么在热、拉大家就某话题在说什么、搞清楚是谁在说。这篇教程用 SandBase 微博 API 把这三个动作串成一套微博热搜监测工作流——你自己不用登录微博,也不用爬虫,但仍然需要一把 SandBase API key。端点参考只保证响应信封(id、status、model、outputs[0].data);下面出现的业务字段是示例结构、并非保证的 schema,所以字段名和数值都当作示例看,以真实响应为准核对。
如果你想先看完整的端点全景,从 微博公开数据 API hub 开始。这一篇是落地的工作流。
先说结论
- 三步:
hot-search(读榜)→realtime-search(搜话题)→user-basic-info(作者)。- 每次都是
POST /v1/api/weibo/<path>,一把SANDBASE_API_KEY;响应共用{ id, status, model, outputs }信封。- 把榜单上的话题关键词带进搜索,把
uid带进资料读取。- 只有信封(
id、status、model、outputs[0].data)是保证的;业务字段是示例——以真实响应为准核对。- 只是公开、只读数据;你自己不用登录微博,也不能发帖,但每次调用都要用一把 SandBase API key。
工作流全貌
| 步骤 | 端点 | 输入 | 你拿到 |
|---|---|---|---|
| 1. 读榜 | weibo/web-v2/hot-search | 无 | 排名的热门话题列表 |
| 2. 搜话题 | weibo/web-v2/realtime-search | query | 匹配的帖子 |
| 3. 给作者建档 | weibo/web-v2/user-basic-info | uid | 昵称、粉丝数 |
端点的 API 参考是每个参数名和响应路径的权威来源。
第 1 步 —— 读热搜榜
先写一个判 status 的帮助函数,再读实时榜:
import os
import requests
BASE = "https://api.sandbase.ai/v1/api/weibo"
HEADERS = {
"Authorization": f"Bearer {os.environ['SANDBASE_API_KEY']}",
"Content-Type": "application/json",
}
def call(path: str, payload: dict) -> dict:
resp = requests.post(f"{BASE}/{path}", headers=HEADERS, json=payload, timeout=90)
resp.raise_for_status()
body = resp.json()
if body.get("status") != "completed":
raise RuntimeError(body.get("error", {}).get("message", "request did not complete"))
return body["outputs"][0]["data"]
board = call("web-v2/hot-search", {}).get("realtime", [])
for item in board[:5]:
print(item.get("rank"), item.get("word"), item.get("num"))
在这个示例结构里,一条榜单项带一个排名关键词(word)和一个热度数字(num),realtime 是 data 下的那个列表。只有信封是保证的,所以代码用 .get() 防御式读取,而不是假设这些键一定存在。以一份真实响应为准核对字段名,因为榜单一直在变、业务字段也不是保证的 schema。
第 2 步 —— 搜一个热门话题
从榜上挑一个关键词,拉匹配的帖子。realtime-search 接一个 query,翻页则传一个 page 请求参数(整数,默认 1):
results = call("web-v2/realtime-search", {"query": board[0].get("word"), "page": 1})
# 示例结构把布局嵌在 parsed_data 下(results、result_count、search_stats);
# 读 schema 并看一份真实响应,对准你需要的帖子字段
parsed = results.get("parsed_data", {})
print(parsed.get("result_count"))
在这个示例结构里,realtime-search 的响应把布局嵌在 parsed_data 下(含 results、result_count、search_stats 这样的字段),但只有信封是保证的——迭代之前先看一份真实响应,弄清帖子字段和作者 id 实际在哪。要翻到下一页,递增 page 请求参数,而不是去跟响应体里的某个字段。
realtime-search 在 parsed_data 下返回一个结构化布局——迭代前先读 schema。
第 3 步 —— 给作者建档
对你在第 2 步浮现出的一个作者 id,附上账号上下文。user-basic-info 接一个 uid:
profile = call("web-v2/user-basic-info", {"uid": "1671109627"}).get("data", {})
print(profile.get("screen_name"), profile.get("followers_count_str"))
在这个示例结构里,资料读取把像 screen_name、followers_count_str、friends_count_str 和 descText 这样的字段嵌在一个 data 对象下。只有信封是保证的,所以代码用 .get() 而不是假设这些键一定存在。下面是一个示例响应结构——业务字段不是保证的 schema,请把字段名和数值当作示例,以一份真实响应为准核对:
{
"id": "dd90e409-dabe-4a0a-88f3-17ea1403b21c",
"status": "completed",
"model": "weibo/web-v2/user-basic-info",
"outputs": [
{
"data": {
"ok": 1,
"data": {
"screen_name": "…",
"followers_count_str": "…",
"friends_count_str": "…"
}
}
}
]
}
user-basic-info 在一个 data 对象下返回昵称和粉丝信号。
把它串起来
一次最小的监测过程长这样:
下面的代码对每个业务字段都用 .get() 读取,因为只有信封是保证的,示例字段在真实响应里可能缺失或叫别的名字:
board = call("web-v2/hot-search", {}).get("realtime", [])
report = []
for topic in board[:10]:
hits = call("web-v2/realtime-search", {"query": topic.get("word"), "page": 1}).get("parsed_data", {})
report.append({
"topic": topic.get("word"),
"popularity": topic.get("num"),
"result_count": hits.get("result_count"),
})
# 对你从 hits 里提取的作者 id,按 schema 调 user-basic-info
因为每次调用共用同一个信封和同一个 call 帮助函数,加重试或速率退避是一处改动的事。当你需要的不止这些读取时,查线上微博列表找到合适的端点,接入前先确认它的参数。
处理粗糙的边角
- 注意嵌套。
user-basic-info在一个data对象下返回载荷,realtime-search在parsed_data下。读准确的路径,别假设是顶层字段。 - 迭代前先看
realtime-search。 它的布局是结构化的,不是扁平列表——从真实响应里对准字段,翻页则递增page请求参数。 - 对
status分支。failed或timeout的请求带error而没有outputs。call帮助函数已经强制这一点。 - 尊重速率限制。 作为客户端韧性措施,遇到 HTTP 429 这类瞬时错误时用退避重试。
- 只是公开数据。 你自己不登录微博、不发帖,也拿不到私密/仅粉丝可见的内容——但每次调用都用一把 SandBase API key 鉴权。
为什么在 API 层做监测
你当然可以在浏览器里刷热搜页,但那给不了你结构化、可存储的数据。把这些调用排成定时任务,就把一个实时榜变成了可度量的信号:能做趋势的热度数字、能去重的话题、以及能按粉丝数加权的作者。因为调用返回的是命名的 JSON 字段,每一轮都能干净地落进一张表,再和上一轮做 diff——新的峰值、新的声音,以及平台在谈论内容的变化。这套工作流采集的是公开对话数据;做情感分析是你在其上另跑的一个分析步骤。
组合这套工作流
同样的统一信封让它可组合。把热搜话题换成任意关键词,再加第四次读取——比如某条帖子的评论——它就用同一个 call 帮助函数、同一套判状态和错误处理接进来。你也可以把中间那步铺开:对榜单前 N 个话题,各跑一次 realtime-search,把数量收进一张表,这样一次过程就给你一份”什么在热、每个话题承载多少讨论”的排名快照。因为这些读取共用一种结构,从一个快速脚本走到一个定时任务,基本上只是加个退避和一个存每轮结果的地方——读取逻辑不变。
常见问题
我需要微博登录或 OAuth 吗?
不需要。你用自己的 SANDBASE_API_KEY 向 SandBase 鉴权,这三次读取都不需要你这边有微博账号或 OAuth。但你仍然要提供一把 SandBase API key。
realtime-search 的结果怎么翻页?
下一次调用时带上 realtime-search 接受的分页请求参数,不要假设固定的每页大小。具体参数名以端点参考为准,迭代前先对着一份真实响应核对。
多久轮询一次热搜榜比较合适? 把这些调用当作尽力而为的读取,把它们错开;遇到 HTTP 429 这类瞬时错误时先退避再重试,别去猛打端点。做趋势的话,每隔几分钟排一次定时任务通常就够了。
下一步
你现在有了一套可复用的热搜监测工作流,建立在三次公开、只读的调用上。