视频号 API Python 教程:搜索、作品、账号和评论(2026)
在 Python 里用五个接口就够:视频号视频搜索、作品详情、账号搜索、账号作品和作品评论,每个都是带 API key 的普通 HTTPS GET 请求,不用登录微信。下面的示例一共 6 次调用,花费 $0.11;失败的调用不扣费。
更新于
视频号有没有能读别人视频的官方 API?没有。微信开放文档里视频号这一块,讲的是视频号小店、本地生活团购,以及视频号助手 API;视频号助手 API 读的是你自己账号的数据:直播记录、橱窗商品、留资、直播大屏和罗盘达人版的带货数据。小程序可以跳转或内嵌一条视频号视频,用的是从视频号助手或 App 里手动复制的 ID 或 token,作用是播放,不是返回数据。官方文档里没有任何接口能拿到别人账号的视频、数据或评论。
所以大多数用 Python 抓视频号的项目,最后都绕回到一个登录着的微信会话上:手机扫码,想办法让登录态别掉,读数据用的那个微信号还要自己承担被风控的风险。这篇走另一条路:每次调用就是一个 HTTPS GET,请求头里带 API key。不需要微信账号,不用 Cookie,不用扫码,也不用处理签名,Python 里只用到 requests。
分步操作
先在终端里设好 key:export OKDATA_API_KEY=okd_...。所有接口的返回结构都一样:成功时 code 是 "ok";列表接口的结果在 data.items,翻页信息在 page;单个对象的接口,结果在 data.item。
第一步:按关键词搜视频
视频号视频搜索的参数有 query,可选的 sort(默认 relevance,另有 latest、popular),以及可选的 published_within(day、week 或 half_year)。一次调用最多返回约 10 条视频,每次 $0.02:描述、发布时间、账号名称和头像、点赞数和封面。每条结果的 id 是 export/ 开头的加密 ID,会过期,想要的视频要在同一次运行里查详情。
curl -G "https://api.okdata.online/v1/wechat_channels/videos/search" -H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'query=露营装备' --data-urlencode 'sort=popular' --data-urlencode 'published_within=week'
第二步:查作品详情
视频号作品详情接受数字作品 ID、搜索结果的 export/ ID,或者用 url 传分享链接。每次 $0.02,返回数字 id、author.id 里的账号 ID、metrics.likes、metrics.comments、metrics.shares、metrics.favorites;加上 view=full,ext 里还有位置和时长。
curl -G "https://api.okdata.online/v1/wechat_channels/videos/get" -H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'url=https://weixin.qq.com/sph/AqR7tLm2Kd'
第三步:按名称找账号
视频号账号搜索的 query 填账号名称,走微信搜一搜,通常只返回最匹配的一个,每次 $0.02。返回的 id 是账号 ID,格式是 v2_…@finder。App 里显示的 sph 开头的视频号 ID 是另一回事,接口不认。
curl -G "https://api.okdata.online/v1/wechat_channels/users/search" -H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'query=三联生活周刊'
第四步:拉账号作品
视频号账号作品的 id 填 v2_…@finder,按从新到旧返回,每页约 15 条,每页 $0.02,每条带点赞、评论、转发和收藏。视频号的视频没有网页,所以作品的 url 是加密的视频文件,解密 key 在 ext.decode_key(需要 view=full)。
curl -G "https://api.okdata.online/v1/wechat_channels/users/videos/list" -H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'id=v2_060000231003b20faec8c353a18ebca650858991e19fab55aa5e12f6d5010f5e0eeaaafc3520@finder'
第五步:读评论
视频号作品评论要的是数字作品 ID(不是 export/ 那个),每页约 25 条一级评论,按热度排,每次 $0.015:text、author.name、likes、replies、published_at 和 ip_location。翻页时把上一次的 page.next_cursor 作为 cursor 传回去。
curl -G "https://api.okdata.online/v1/wechat_channels/videos/comments/list" -H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'id=14987320651142873906'
第六步:完整的 Python 脚本
所有调用都走同一个函数:检查 body["code"],遇到已删除的内容就跳过,遇到限流或上游繁忙就用同一个 Idempotency-Key 重试,所以重试不会重复扣费。翻页统一用一个带页数上限的生成器。结果写进 channels.json。
import json
import os
import time
import uuid
import requests
API = "https://api.okdata.online"
KEY = os.environ["OKDATA_API_KEY"]
COMMENT_PAGES = 2 # 每页一次调用
VIDEO_PAGES = 1 # 每页一次调用,约 15 条
class NotFound(Exception):
pass
def call(path, **params):
headers = {"Authorization": f"Bearer {KEY}", "Idempotency-Key": str(uuid.uuid4())}
for attempt in range(4):
body = requests.get(API + path, headers=headers, params=params, timeout=60).json()
if body["code"] == "ok":
return body
if body["code"] == "not_found":
raise NotFound(body["message"]) # 已删除或不公开:不扣费
if body.get("retry") in ("yes", "same_key"):
time.sleep(body.get("retry_after_seconds") or 2 ** attempt)
continue
raise RuntimeError(f"{body['code']}: {body['message']} (request {body['request_id']})")
raise RuntimeError(f"{path}: 重试 4 次仍然失败")
def paged(path, max_pages, **params):
cursor = None
for _ in range(max_pages):
body = call(path, **params, **({"cursor": cursor} if cursor else {}))
yield from body["data"]["items"]
if not body["data"]["items"] or not body["page"]["has_more"]:
return
cursor = body["page"]["next_cursor"]
def keyword_report(query):
hits = call("/v1/wechat_channels/videos/search", query=query, sort="popular",
published_within="week")["data"]["items"]
if not hits:
return None
video = call("/v1/wechat_channels/videos/get", id=hits[0]["id"])["data"]["item"]
comments = list(paged("/v1/wechat_channels/videos/comments/list", COMMENT_PAGES, id=video["id"]))
return {"hits": hits, "video": video, "comments": comments}
def account_report(name):
found = call("/v1/wechat_channels/users/search", query=name)["data"]["items"]
if not found:
return None
account = found[0]
videos = list(paged("/v1/wechat_channels/users/videos/list", VIDEO_PAGES, id=account["id"]))
return {"account": account, "videos": videos}
if __name__ == "__main__":
report = {}
try:
report["keyword"] = keyword_report("露营装备")
except NotFound:
report["keyword"] = None # 搜索之后、查详情之前,排第一的视频被删了
report["account"] = account_report("三联生活周刊")
with open("channels.json", "w", encoding="utf-8") as f:
json.dump(report, f, ensure_ascii=False, indent=2)
print("搜到视频:", len((report["keyword"] or {}).get("hits", [])),
"| 评论:", len((report["keyword"] or {}).get("comments", [])),
"| 账号作品:", len((report["account"] or {}).get("videos", [])))
跑一遍就是上面的示例,6 次调用。想拿得更多,把两个页数上限调大;账号作品读 10 页是 $0.20。
注意事项
- 哪个 ID 用在哪。 搜索给的是会过期的
export/ID;作品详情把它换成数字 ID,评论和回复都要数字 ID。账号在所有接口里都是v2_…@finder。 - 哪些是 null。 搜索结果没有评论、转发、收藏数,也没有账号 ID,查详情才补齐。播放量(
metrics.views)永远拿不到,因为视频号本身不公开。隐藏了粉丝数的账号,followers是 null。每个 null 字段及原因都写在meta.unavailable里。 - 精简返回。
fields=id,text,metrics.likes只保留你点名的字段,view=compact每个对象返回的字段更少。两者都不影响价格。 - 回复。 评论下面的楼中楼用视频号评论回复,参数是评论 ID 加数字作品 ID。
- 不收钱的情况。 已删除的视频、对不上的账号返回
not_found,不扣费;限流、上游繁忙和其他错误也一样不扣费。
如果不想写 Python,想在 Claude 或其他智能体里直接调这些接口,接上 MCP 服务即可。拿 key 和试用额度的步骤见快速开始。
示例花费
搜一次“露营装备”,查排第一的视频详情,按名称找一个账号并拉它最新一页作品,再读排第一的视频下两页评论
| 接口 | 调用次数 | 单价 | 小计 |
|---|---|---|---|
| 视频号视频搜索 | 1 | $0.02 | $0.02 |
| 视频号作品详情 | 1 | $0.02 | $0.02 |
| 视频号账号搜索 | 1 | $0.02 | $0.02 |
| 视频号账号作品 | 1 | $0.02 | $0.02 |
| 视频号作品评论 | 2 | $0.015 | $0.03 |
| 合计 | 6 | $0.11 |
按本页生成时的价格计算。失败的调用不扣费。
在你的 AI 里用(MCP)
先接好 MCP 服务,然后直接说你要什么。智能体会自己找到这些接口、看清价格,再用你的余额调用。
可以这样说在视频号搜最近一周的“露营装备”,打开最热的那条,给我它的数据和两页评论;再找到账号“三联生活周刊”,列出它最新的作品。
智能体第一次调用 call 工具时发送的内容
{
"endpoint": "wechat_channels.videos.search",
"params": {
"query": "露营装备推荐"
},
"idempotency_key": "<新的 UUID>"
}