一个返回 JSON、支持 X 搜索运算符的免费 Twitter 搜索 API

一个返回 JSON、支持 X 搜索运算符的免费 Twitter 搜索 API
Unif Cookbooks team
Unif Cookbooks team

更新于

无需 API 密钥,从脚本或 AI Agent 以 JSON 搜索近期公开 X 帖子:端点、可用的搜索运算符、游标分页和限制。

一句话总结:GET https://unifapi.com/tools/x/search?q=<query> 以 JSON 返回匹配查询的公开 X 帖子。它免费使用,无需登录、无需账号、无需 API 密钥,按访客限流。X 的搜索运算符在 q 里都能用:from:、to:、since:、until:、min_faves:、min_retweets:、filter:media、filter:links、-filter:replies、lang: 和带引号的短语。结果每页 20 条,最新在前,带 nextCursor 翻页。免费限额是每位访客每 10 分钟 20 个单位,写在 X-RateLimit-* 响应头里;一次搜索计 2 个单位,因为它是上游开销最大的调用,所以相当于 10 次搜索。不加日期时拿到的是最新的帖子;加上 since: 和 until:,同一个搜索可以回溯到 2006 年。

人们想不用账号从 X 拿到的东西里,搜索是唯一没有好的免费答案的那一个。链接预览 API(FxTwitter、vxTwitter)只读单条帖子。syndication 端点只读单条帖子。Nitter 有搜索,但大多数公共 Nitter 实例已经消失或因法律原因被封。剩下的选择要么是带付费层的开发者账号,要么是用无头浏览器驱动 x.com/search,又慢又脆弱,还违反服务条款。

本文说的是这个免费搜索端点能做什么、怎么查询,以及它的边界在哪。

请求

curl -s "https://unifapi.com/tools/x/search?q=from%3Anasa%20filter%3Amedia"
{
  "query": "from:nasa filter:media",
  "posts": {
    "items": [
      {
        "id": "2107566197579341846",
        "text": "After delivering science and supplies to the @Space_Station earlier this year, Northrop Grumman's Cygnus XL cargo spacecraft is scheduled to depart on Friday…",
        "createdAt": "2026-10-06T20:18:32.000Z",
        "url": "https://x.com/NASA/status/2107566197579341846",
        "author": { "handle": "NASA", "name": "NASA", "verified": true, "followers": 92373839 },
        "metrics": {
          "likes": 2195,
          "reposts": 302,
          "replies": 114,
          "quotes": 20,
          "bookmarks": 104,
          "views": 1520159
        },
        "media": [
          {
            "kind": "photo",
            "url": "https://pbs.twimg.com/media/…jpg",
            "width": 1920,
            "height": 1280
          }
        ]
      }
    ],
    "hasMore": true,
    "nextCursor": "DAACCgACHUAq4qFAJxAKAAMd…"
  }
}

同一个请求在给人看的页面上是 https://unifapi.com/tools/x-search?q=from:nasa filter:media,给这个页面 URL 加上 &format=json 就返回上面的 JSON。换成 format=md,或发送 Accept: text/markdown,则以 Markdown 返回帖子,比 JSON 更适合塞进模型的上下文窗口。

可用的运算符

查询会原样传给 X 的搜索,所以 X 为自家搜索框写明的运算符在这里都能用。下面是我们最常用的几个:

运算符示例作用
from:from:nasa某个账号发的帖子
to:to:nasa回复给某个账号的帖子
@handle@nasa提及某个账号的帖子
#tag#Formula1带某个话题标签的帖子
"phrase""crew-12"精确短语
since: / until:since:2026-10-01日期范围(按整天)
min_faves:min_faves:100至少 N 个赞
min_retweets:min_retweets:50至少 N 次转发
filter:mediafrom:nasa filter:media只要带照片或视频的帖子
filter:linksfilter:links只要带链接的帖子
-filter:replies#Formula1 -filter:replies排除回复
-filter:retweetsfrom:nasa -filter:retweets排除转发
lang:lang:ja语言代码
ORnasa OR esa任一词

它们可以组合。"NASA 最近一周发的、至少 100 个赞、带照片、不含回复的帖子"写成:

from:nasa since:2026-09-30 min_faves:100 filter:media -filter:replies

Twitter 高级搜索页面为其中最常用的五个(账号、日期、点赞、媒体、回复)各提供一个筛选项,并显示它们拼出的查询,那正是 API 收到的同一个字符串。

最新,而非热门

X 的搜索有两种排序:"热门"(Top)混合相关性和时间,会毫不犹豫地把一条 2009 年的帖子排在最前;"最新"(Latest)严格按时间倒序。免费端点请求的是"最新"。对于监控、对某个事件的反应,以及任何带 since: 边界的查询,这正是你想要的。如果你要的是"本周关于某话题点赞最多的帖子",就自己按 metrics.likes 给"最新"结果排序,或者加上 min_faves: 砍掉长尾。

翻页

免费 API 里每个列表都是 { items, hasMore, nextCursor }。要继续,把 cursor 传回去:

curl -s "https://unifapi.com/tools/x/search?q=%23Formula1&cursor=DAACCgACHUAq4qFAJxAKAAMd…"

cursor 是不透明字符串,不要解析。hasMore 为 true 当且仅当 nextCursor 有值。一页搜索是 20 条帖子,所以三次请求大约读到 60 条,花掉你 20 个单位里的 6 个。

限额,就在响应里

HTTP/2 200
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 16
X-RateLimit-Reset: 1791357984

免费层是每位访客每 10 分钟 20 个单位,所有 /tools/x/* 端点共享,一次搜索计 2 个。用完时,回答是一个带 Retry-After 的 429,响应体是 JSON,写明到哪里解除上限:

{
  "error": {
    "type": "rate_limited",
    "message": "Free limit of 20 requests per 10 minutes reached. Retry after 412s, or use a UnifAPI workspace key (pay as you go) for uncapped access.",
    "retryAfterSeconds": 412,
    "upgrade": "https://unifapi.com/apis/twitter"
  }
}

守规矩的智能体会在决定翻页之前先读 X-RateLimit-Remaining,并按 Retry-After 休眠,而不是循环重试。

它不做什么

  • 相关性。 结果只按从新到旧排列。旧帖子可以用日期找到(from:jack until:2006-04-01 返回 2006 年 3 月的帖子),但没有什么会把一段时间里最好的帖子排在前面,而且 X 按它自己的时区划分 since:/until: 的日期边界,所以一个日期范围前后可能各多出几个小时。
  • 受保护账号。 只返回公开帖子。
  • 计数。 没有"共匹配多少条帖子"的数字;X 的搜索不提供这个。
  • 保障。 免费层是共享基础设施,按访客设上限。需要大体量或 SLA 的工作流应转到计量 API,那里字段名相同。

二十行写一个监控循环

import requests, time

BASE = "https://unifapi.com/tools/x/search"
seen = set()

def poll(query):
    r = requests.get(BASE, params={"q": query}, headers={"Accept": "application/json"})
    if r.status_code == 429:
        time.sleep(int(r.headers.get("Retry-After", "60")))
        return []
    r.raise_for_status()
    fresh = [p for p in r.json()["posts"]["items"] if p["id"] not in seen]
    seen.update(p["id"] for p in fresh)
    return fresh

while True:
    for post in poll('"unifapi" -filter:replies'):
        print(post["createdAt"], post["author"]["handle"], post["metrics"]["likes"], post["url"])
    time.sleep(600)

每 10 分钟一次搜索是 20 个免费单位里的 2 个;这个循环永远不会触到限额,但它照样处理了 429 的情况。

常见问题

2026 年还有免费的 Twitter 搜索 API 吗?

有,就是这个:免费使用,无需登录、无需 API 密钥,按访客限流,每 10 分钟最多搜索 10 次。官方 X API 没有免费的搜索层,它的免费套餐只允许发帖。

Twitter 高级搜索运算符能用吗?

能。查询原样传给 X 的搜索,所以 from:、since:、until:、min_faves:、filter:media、-filter:replies、lang: 和带引号的短语都能用。

搜索能回溯多久?

可以回溯到 2006 年。不加日期时先拿到最新的帖子;加上 since: 和 until: 就能跳到某个时间段,例如 from:jack until:2006-04-01。

能以 Markdown 而不是 JSON 拿结果吗?

能。加上 format=md 或发送 Accept: text/markdown。Markdown 渲染会逐条列出帖子的作者、正文、指标和 URL。