怎么按关键词搜 X(推特)帖子并导出
先用 X 帖子搜索按查询词一页页收集帖子,再用 X 帖子详情按 ID 或链接重新读取单条帖子。下面的示例一共 8 次调用,花费 $0.0109;失败的调用不扣费。
更新于
要做的事:想把 X 上关于某个产品、品牌或话题的帖子拉下来,变成能排序、能转给同事的一行行数据。查询词就写你会在 X 搜索框里输入的那一句,一页页往下翻,留下有用的帖子。过一天再把其中最突出的几条读一遍,看它们有没有继续扩散。最后得到一个 JSON Lines 文件,每条帖子有正文、作者、发布时间、链接,以及浏览、点赞、回复、转发和收藏数。
不需要 X 账号,不用申请开发者应用,也不用 Cookie。每次调用就是带着 key 发一个 HTTPS 请求。
分步操作
第一步:搜索
调用X 帖子搜索,query 填查询词。查询词会原样交给 X 自己的搜索,所以搜索框支持的语法这里都能用:"精确短语"、OR、-排除词、from:用户名、lang:en、since:2026-11-05、until:2026-11-12、min_faves:50、-filter:replies。常用语法见X 高级搜索语法能不能通过 API 用。sort 可选 latest(默认,对应 X 的“最新”标签)或 top(对应“热门”标签)。
一次调用返回约 20 条帖子,每次 $0.002,用多少语法都是这个价。每条帖子有 id、url、text、lang、published_at、author(含 username、name、followers、verified)和 metrics:views(浏览)、likes(点赞)、comments(回复)、reposts(转发)、favorites(书签收藏)。metrics.shares 始终为 null,因为 X 不公开这个数。
curl -G "https://api.okdata.online/v1/x/posts/search" \
-H "Authorization: Bearer $OKDATA_API_KEY" \
--data-urlencode 'query="standing desk" lang:en since:2026-11-05 -filter:replies' \
--data-urlencode 'sort=latest' \
--data-urlencode 'fields=id,url,text,published_at,author.username,metrics'
查询词一定要用 --data-urlencode,引号、冒号和空格都得编码。要下一页,就把 page.next_cursor 原样作为 cursor 传回去;page.has_more 为 false 时停下。加 view=full 每条帖子会多出 ext.quotes(引用数)、ext.is_reply 和 ext.conversation_id,价格不变。
第二步:重新读取单条帖子
X 帖子详情接收帖子的 id 或链接 url,返回同样结构的帖子,每次 $0.0003。两种用法:同事甩给你的帖子链接;已经拿到、想刷新数据的帖子。帖子发出后一两天内浏览量还会一直涨,读第二次就能看出哪些还在传播。
curl -G "https://api.okdata.online/v1/x/posts/get" \
-H "Authorization: Bearer $OKDATA_API_KEY" \
-d id=1988412365027741953 \
-d fields=id,metrics.views,metrics.likes,metrics.reposts
已删除的帖子,或者作者已把账号设为受保护,会返回 not_found,不扣费。
第三步:用 Python 串起来
下面的脚本最多收集 MAX_PAGES 页写进 posts.jsonl,并记下浏览量最高的 3 条帖子的 ID。一天后带 recheck 参数再跑一次,就会把这 3 条重新读一遍。
import json
import os
import sys
import requests
API = "https://api.okdata.online"
HEADERS = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}
QUERY = '"standing desk" lang:en since:2026-11-05 -filter:replies'
MAX_PAGES = 5 # 每页一次调用
def get(path, **params):
body = requests.get(API + path, headers=HEADERS, params=params, timeout=60).json()
if body["code"] != "ok":
raise RuntimeError(f"{body['code']}: {body['message']} (charged: {body['charged']})")
return body
def collect():
seen, cursor = {}, None
for _ in range(MAX_PAGES):
body = get("/v1/x/posts/search", query=QUERY, sort="latest", **({"cursor": cursor} if cursor else {}))
for p in body["data"]["items"]:
seen[p["id"]] = p
if not body["page"]["has_more"]:
break
cursor = body["page"]["next_cursor"]
with open("posts.jsonl", "w", encoding="utf-8") as f:
for p in seen.values():
f.write(json.dumps(p, ensure_ascii=False) + "\n")
top = sorted(seen.values(), key=lambda p: p["metrics"]["views"] or 0, reverse=True)[:3]
json.dump([p["id"] for p in top], open("watch.json", "w"))
print(len(seen), "posts saved")
def recheck():
for post_id in json.load(open("watch.json")):
item = get("/v1/x/posts/get", id=post_id)["data"]["item"]
print(post_id, item["metrics"]["views"], item["metrics"]["likes"], item["url"])
recheck() if sys.argv[1:] == ["recheck"] else collect()
用 id 做键的字典会自动去重,按日期分段、窗口有重叠时尤其有用。
注意事项
- 只有公开帖子。 受保护账号的帖子,无论搜索还是按 ID 取,都不会返回。
- 时间跨度长的时候。 要拉一个月以上,就按周或按天拆成多次查询,用
since:、until:加sort=latest。分段小,哪天漏了一眼就能看出来。 - X 官方 API。 X 自己的 API 按用量计费。它的价格页写的是每返回一条帖子收半美分,也就是 1,000 条 5 美元,每个月度账期最多读 300 万条;同一个 UTC 自然日内重复读已付费的帖子不再收费。X 的搜索文档写明,近 7 天搜索对所有开发者开放,可回溯到 2006 年的全量搜索面向按量付费和企业客户。如果你还要发帖、回复,或者需要和 X 直接签合同,就用官方的。
- 重试不会重复扣费。 每次调用带一个
Idempotency-Key请求头。24 小时内同样的请求配同样的 key,会直接拿回上次的结果,meta.replayed为true,不再扣费。
和 X 官方 API 的费用对比,见2026 年 X API 怎么收费。想让 AI 助手替你写查询、跑查询,接上 MCP 服务即可。
示例花费
取 5 页过去一周关于升降桌(standing desk)的最新英文帖子,一天后再读一次浏览量最高的 3 条
按本页生成时的价格计算。失败的调用不扣费。
在你的 AI 里用(MCP)
先接好 MCP 服务,然后直接说你要什么。智能体会自己找到这些接口、看清价格,再用你的余额调用。
可以这样说在 X 上搜 "standing desk",只要近 7 天的英文帖子,不要回复,按最新排序,取 5 页。整理成一张表:作者、正文、浏览、点赞、转发和链接。然后重新读一次浏览量最高的 3 条,告诉我浏览量涨了多少。
智能体第一次调用 call 工具时发送的内容
{
"endpoint": "x.posts.search",
"params": {
"query": "\"claude code\" lang:zh"
},
"idempotency_key": "<新的 UUID>"
}