# 怎么每小时抓一次微博热搜，存成历史数据？

> 自己攒一份微博热搜历史：每小时调用一次，按时间、排名、热度存下来。一个月要花多少钱、能直接放进 cron 的脚本，以及容易踩的坑。

网页版：https://okdata.online/zh/answers/weibo-hot-search-hourly-archive/

**简短回答：**每小时调用一次微博热搜，把每一行连同抓取时间追加进文件或数据表。每次快照就是一次调用，$0.002，一个月每小时一次共 720 次，合计 $1.44。接口本身不保存历史，所以你的历史库从开始抓的那天算起。

做传播研究的人想统计一个话题在榜上待了几个小时，品牌团队想证明上周二晚上的活动冲到过第 3 名，都需要同一样东西：过去某个时刻的热搜榜长什么样。微博不提供这个，最实际的办法就是自己定时拍快照。[微博热搜](/zh/apis/weibo/trends/list/)调一次就返回整张榜，所以一个每小时跑一次的定时任务、二十来行代码，就能攒出一份干净的时间序列。

## 不同采样频率的费用

| 采样频率 | 每月调用次数 | 每月费用 |
|---|---|---|
| 每小时一次 | 720 | $1.44 |
| 每 30 分钟一次 | 1,440 | $2.88 |
| 每 10 分钟一次 | 4,320 | $8.64 |

算话题在榜时长和最高排名，每小时一次就够了。那种上榜二十分钟就掉下去的话题，只有 10 分钟一次才抓得到。

## 放进 cron 的脚本

```python
import csv, os, datetime, requests

hour = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H")
r = requests.get(
    "https://api.okdata.online/v1/weibo/trends/list",
    headers={
        "Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}",
        "Idempotency-Key": f"weibo-hot-{hour}",
    },
    params={"fields": "rank,name,heat"},
    timeout=30,
).json()
if r["code"] != "ok":
    raise SystemExit(f"{r['code']}: {r['message']}")

taken = r["meta"]["fetched_at"]
with open("weibo_hot.csv", "a", newline="", encoding="utf-8") as f:
    w = csv.writer(f)
    for row in r["data"]["items"]:
        w.writerow([taken, row["rank"], row["name"], row["heat"]])
```

crontab 里写一行 `0 * * * * python3 /opt/weibo_hot.py` 就行。幂等键按小时生成，同一个小时里 cron 万一跑了两次，第二次直接回放已经存好的榜单，不再扣费。

## 容易踩的坑

- 推广位被过滤掉的地方，排名会跳号。排名不连续不代表数据缺了。
- 有些行的 `heat` 是 null。这一行照样存，排名依然有效。
- 调用失败（比如返回 `upstream_busy`）不扣费。一分钟后重试一次，别直接丢掉这一小时；实在没拿到的小时也记一笔，分析时才知道哪里有空档。
- 同一个话题在发酵过程中，名字常常会改几个字。统计在榜时长时，匹配要宽松一点。

## 什么时候换别的办法

- 需要开始抓之前的数据？自己拍快照没法补历史。GitHub 上有几个开源项目已经把热搜榜存了好几年，先看看它们的时间范围和采样频率是否符合你的研究。
- 商业舆情系统会卖带图表的历史热搜数据。需要好几年的回溯、又完全不想写代码时，花这笔钱是值得的。

跨平台的榜单怎么一起用，见[趋势研究方案](/zh/solutions/trend-research/)；所有接口的价格在[价格页](/zh/pricing/)。

## 用到的接口

- [微博热搜](https://okdata.online/zh/apis/weibo/trends/list/) `weibo.trends.list`：$0.002/次 · 每页约 50 条榜单

更新于 2026-11-12
