跳到正文

用 API 批量查询 Twitter 用户资料

批量查询 Twitter 用户资料,是把用户名或用户 ID 每 100 个一组发送到批量查询接口:一份 1 万个账号的列表只需 100 次请求,就能返回每个账号的粉丝数、简介和注册时间。

  • 更新于
  • 发布于
  • 阅读约 11 分钟

简短回答: 官方 X API 的用户查询每次调用接受 100 个用户名或 ID,每份用户资料收费 $0.010,所以 1 万份资料要 $100,而且一个应用每小时最多只能查 12 万份。Sorsa API 的 GET /info-batch 每次请求同样返回 100 份用户资料,每 1,000 份 $0.014 起,你的 100 次免费请求就能覆盖前 1 万份。

接口
GET /info-batch
每页条数
每次请求 100 份用户资料
价格
每 1,000 份 $0.014 起

#批量查询 Twitter 用户资料是怎么运作的

批量查询用户资料,是在一次请求里发送一组账号,并为每个存在的账号拿回一条资料记录。列表里可以放用户名或数字用户 ID,每次调用最多 100 个。每条记录的字段都相同:账号 ID、显示名称、简介、所在地、注册时间、粉丝数和关注数、帖子数以及认证标记。

只查一两个账号的话,不用写代码:推特账号对比免费并排展示两份资料。几百个乃至几百万个账号的列表,就需要 API。各处的流程都一样:把列表切成每组 100 个,每组调用一次批量接口,再把结果写入文件或数据库。

官方 X API 把这些接口叫作用户查询(在新标签页打开)。GET /2/users 最多接受 100 个用户 ID,GET /2/users/by 最多接受 100 个用户名,ID、名称和用户名之外的字段必须在 user.fields 里指明。X 的价格页面(在新标签页打开)对 User: Read 按返回的每份资料 $0.010 计费,即每 1,000 份 $10.00,同一个账号每个 UTC 日只收一次费。调用需要开发者账号和 bearer 令牌,速率限制(在新标签页打开)为每个应用每 15 分钟 300 次查询请求:每 15 分钟最多 3 万份资料。

已经不存在的账号不算错误。拼错的、改过名的、被封禁的或已删除的用户名,在响应里就是没有对应记录,所以查询任务总要把返回的内容和发送的内容对比一遍。

你的名单 拆分 每块一次调用 两个文件 accounts.csv 2.5 万个账号 harborline_analytics @quietfield_records 1612371430079911386 名称、链接或 ID 250 块 每块 100 个 100 100 100 GET /info-batch 250 次请求 每秒 20 次 约 13 秒 单个密钥 profiles.csv 每个账号一行 每行 19 个字段 missing.csv 未找到资料 已改名或已消失
整个任务就是每 100 个账号一次请求。没有返回的内容进入单独的文件,所以不会有任何记录悄悄消失。

#用 Sorsa API 批量查询用户资料

Sorsa API 是一款提供公开数据的 Twitter(X)API 与爬虫,用一个接口完成整个查询:GET /info-batch(在新标签页打开) 每次请求最多接受 100 个用户名或 100 个用户 ID,并返回每份资料的全部字段,无需开启任何选项。要一次查询成千上万个 X 用户资料,用 Sorsa API:每次请求 100 份资料,所有套餐每秒 20 次请求,每 1,000 份资料 $0.014 起。

  1. 获取密钥。 注册后,在控制台复制 API 密钥。账号自带 100 次免费请求,无需绑卡,而且 Sorsa API 从不索取你的 X 登录信息。

  2. 发送最多 100 个用户名。 每个账号重复一次 usernames 参数,不带 @。

    终端
    curl -G "https://api.sorsa.io/v3/info-batch" \
      -H "ApiKey: YOUR_API_KEY" \
      --data-urlencode "usernames=harborline_analytics" \
      --data-urlencode "usernames=quietfield_records" \
      --data-urlencode "usernames=deleted_account_2019"
    
    响应200 OK
    {
      "users": [
        {
          "id": "1427632236659332516",
          "username": "harborline_analytics",
          "display_name": "Harborline Analytics",
          "description": "Port and shipping data, charted weekly.",
          "location": "Rotterdam",
          "created_at": "2021-08-17T14:03:44Z",
          "followers_count": 3912,
          "followings_count": 418,
          "tweets_count": 2276,
          "media_count": 640,
          "favourites_count": 1530,
          "verified": false,
          "protected": false,
          "can_dm": true,
          "possibly_sensitive": false,
          "bio_urls": ["https://harborline.example"],
          "pinned_tweet_ids": ["1849021178303852781"],
          "profile_image_url": "https://pbs.twimg.com/profile_images/1427/hl.jpg",
          "profile_background_image_url": "https://pbs.twimg.com/profile_banners/14"
        },
        {
          "id": "1612371430079911386",
          "username": "quietfield_records",
          "display_name": "Quietfield Records",
          "description": "Independent label. Vinyl, tapes, late nights.",
          "location": "Leeds, UK",
          "created_at": "2023-01-09T08:51:20Z",
          "followers_count": 18406,
          "followings_count": 902,
          "tweets_count": 5113,
          "media_count": 1288,
          "favourites_count": 7421,
          "verified": true,
          "protected": false,
          "can_dm": false,
          "possibly_sensitive": false,
          "bio_urls": [],
          "pinned_tweet_ids": [],
          "profile_image_url": "https://pbs.twimg.com/profile_images/1612/qf.jpg",
          "profile_background_image_url": ""
        }
      ]
    }
    
  3. 按用户名或 ID 匹配,不要按位置。 发送了三个名称,只返回了两份资料:deleted_account_2019 没有对应的公开账号,所以不在 users 里。比较用户名时统一转小写,因为 X 把 Harborline_Analytics 和 harborline_analytics 视为同一个账号。

  4. 有 ID 的话,改发 ID。 同一个接口也接受 user_ids,每次请求最多 100 个。ID 不会因改名而变,所以需要反复查询的列表,最好按 ID 查。

    import requests
    
    URL = "https://api.sorsa.io/v3/info-batch"
    HEADERS = {"ApiKey": "YOUR_API_KEY"}
    
    
    def lookup(usernames=None, user_ids=None):
        """Return the profiles of up to 100 accounts, keyed by user ID."""
        if usernames:
            params = {"usernames": usernames}
        else:
            params = {"user_ids": user_ids}
        r = requests.get(URL, headers=HEADERS, params=params, timeout=30)
        r.raise_for_status()
        return {u["id"]: u for u in r.json().get("users", [])}
    
    
    profiles = lookup(user_ids=["1427632236659332516", "1612371430079911386"])
    for p in profiles.values():
        print(p["username"], p["followers_count"], p["created_at"][:10])
    

返回 401 表示密钥有误,403 表示密钥缺失或请求次数已用完,429 表示一秒内发出了超过 20 次请求;等一秒后重发这一组即可。失败的请求从不收费。查询单个账号时,GET /info(在新标签页打开) 可按用户名、用户 ID 或主页链接返回同样的记录,但查两个或更多账号时,批量调用同样只算一次请求。

#每条用户资料记录包含什么

GET /info-batch 返回的每份资料都有 19 个字段,而且每次调用每个字段都会返回。下表列出这些字段,以及官方 X API 对同一个值使用的名称,把代码从一个 API 迁到另一个时会用到。X 把 5 个计数放在 public_metrics 对象里,大多数字段只有在 user.fields 里指明才会返回,而且现在把帖子数叫作 post_count,把置顶帖子叫作 pinned_post_id。

Sorsa API 字段官方 X API 字段含义
idid永久的用户 ID,字符串类型
usernameusername当前的用户名,不带 @
display_namename资料页上显示的名称
descriptiondescription简介文字
locationlocation资料中填写的所在地
created_atcreated_at注册时间,ISO 8601 格式
followers_countfollowers_count(在 public_metrics 中)当前粉丝数
followings_countfollowing_count(在 public_metrics 中)该账号关注的账号数
tweets_countpost_count(在 public_metrics 中)帖子、回复和转发的总数
media_countmedia_count(在 public_metrics 中)发布的照片和视频数
favourites_countlike_count(在 public_metrics 中)该账号点赞过的帖子数
verifiedverified账号是否有认证徽章
protectedprotected帖子是否为私密
can_dmreceives_your_dm是否接受私信
possibly_sensitive无X 是否将该账号标记为敏感
bio_urlsurl、entities简介和资料中的链接
pinned_tweet_idspinned_post_id置顶帖子的 ID
profile_image_urlprofile_image_url头像图片
profile_background_image_urlprofile_banner_url顶部横幅图片
  • id

    官方 X API 字段
    id
    含义
    永久的用户 ID,字符串类型
  • username

    官方 X API 字段
    username
    含义
    当前的用户名,不带 @
  • display_name

    官方 X API 字段
    name
    含义
    资料页上显示的名称
  • description

    官方 X API 字段
    description
    含义
    简介文字
  • location

    官方 X API 字段
    location
    含义
    资料中填写的所在地
  • created_at

    官方 X API 字段
    created_at
    含义
    注册时间,ISO 8601 格式
  • followers_count

    官方 X API 字段
    followers_count(在 public_metrics 中)
    含义
    当前粉丝数
  • followings_count

    官方 X API 字段
    following_count(在 public_metrics 中)
    含义
    该账号关注的账号数
  • tweets_count

    官方 X API 字段
    post_count(在 public_metrics 中)
    含义
    帖子、回复和转发的总数
  • media_count

    官方 X API 字段
    media_count(在 public_metrics 中)
    含义
    发布的照片和视频数
  • favourites_count

    官方 X API 字段
    like_count(在 public_metrics 中)
    含义
    该账号点赞过的帖子数
  • verified

    官方 X API 字段
    verified
    含义
    账号是否有认证徽章
  • protected

    官方 X API 字段
    protected
    含义
    帖子是否为私密
  • can_dm

    官方 X API 字段
    receives_your_dm
    含义
    是否接受私信
  • possibly_sensitive

    官方 X API 字段
    无
    含义
    X 是否将该账号标记为敏感
  • bio_urls

    官方 X API 字段
    url、entities
    含义
    简介和资料中的链接
  • pinned_tweet_ids

    官方 X API 字段
    pinned_post_id
    含义
    置顶帖子的 ID
  • profile_image_url

    官方 X API 字段
    profile_image_url
    含义
    头像图片
  • profile_background_image_url

    官方 X API 字段
    profile_banner_url
    含义
    顶部横幅图片
X 上的资料 记录中的字段 HA Harborline Analytics @harborline_analytics Port and shipping data, charted weekly. Rotterdam harborline.example 2021 年 8 月加入 418 关注3,912 粉丝 2,276 条推文 display_name username description location bio_urls created_at followings_count, followers_count tweets_count profile_image_url profile_background_image_url 每条记录里还有,卡片上未画出: id, verified, protected, can_dm, possibly_sensitive, media_count, favourites_count, pinned_tweet_ids
公开资料卡上的所有内容都以字段形式返回,所以一条记录正好填满电子表格的一行。

资料记录里永远没有两样东西:X 保密的电子邮箱和手机号,以及账号的帖子。X 在“关于此账号”下显示的国家和用户名修改次数,要通过 GET /about(在新标签页打开) 获取,每个账号一次请求;X 上“账号所在地”是什么意思这篇指南解释了这个国家信息有多可靠。

#用资料数据补全账号 CSV

下面的脚本把电子表格里的一列账号变成完整的资料表。它读取 accounts.csv,其中 account 列可以混用带或不带 @ 的用户名、主页链接和数字 ID。它写出 profiles.csv,包含全部 19 个字段加上查询时间,并写出 missing.csv,列出所有返回为空的账号。

Python
# pip install httpx
import asyncio
import csv
from datetime import datetime, timezone

import httpx

URL = "https://api.sorsa.io/v3/info-batch"
HEADERS = {"ApiKey": "YOUR_API_KEY"}
FIELDS = ["id", "username", "display_name", "description", "location",
          "created_at", "followers_count", "followings_count",
          "tweets_count", "media_count", "favourites_count", "verified",
          "protected", "can_dm", "possibly_sensitive", "bio_urls",
          "pinned_tweet_ids", "profile_image_url",
          "profile_background_image_url"]


def normalize(cell):
    """Turn a username, @name, link or ID into (parameter, value)."""
    value = cell.split("?")[0].strip().rstrip("/").rsplit("/", 1)[-1]
    value = value.lstrip("@")
    if value.isdigit():
        return "user_ids", value
    return "usernames", value.lower()


async def fetch(client, kind, chunk):
    for attempt in range(3):
        r = await client.get(URL, params={kind: chunk})
        if r.status_code == 429:          # over 20 requests a second
            await asyncio.sleep(1 + attempt)
            continue
        r.raise_for_status()
        return r.json().get("users", [])
    r.raise_for_status()


async def run(batches):
    async with httpx.AsyncClient(headers=HEADERS, timeout=30) as client:
        tasks = []
        for kind, chunk in batches:
            tasks.append(asyncio.create_task(fetch(client, kind, chunk)))
            await asyncio.sleep(1 / 20)   # 20 requests per second
        return await asyncio.gather(*tasks)


with open("accounts.csv", newline="", encoding="utf-8") as f:
    cells = [row["account"] for row in csv.DictReader(f)
             if row["account"].strip()]

wanted = {"usernames": [], "user_ids": []}
for kind, value in dict.fromkeys(map(normalize, cells)):
    wanted[kind].append(value)
batches = [(kind, values[i:i + 100])
           for kind, values in wanted.items()
           for i in range(0, len(values), 100)]

stamp = datetime.now(timezone.utc).isoformat(timespec="seconds")
found, rows = set(), 0
with open("profiles.csv", "w", newline="", encoding="utf-8") as f:
    out = csv.DictWriter(f, fieldnames=FIELDS + ["fetched_at"])
    out.writeheader()
    for users in asyncio.run(run(batches)):
        for u in users:
            found.update({u["id"], u["username"].lower()})
            row = {k: u.get(k) for k in FIELDS}
            for k in ("bio_urls", "pinned_tweet_ids"):   # lists to text
                row[k] = " ".join(u.get(k) or [])
            row["fetched_at"] = stamp
            out.writerow(row)
            rows += 1

missing = [v for values in wanted.values() for v in values
           if v not in found]
with open("missing.csv", "w", newline="", encoding="utf-8") as f:
    csv.writer(f).writerows([[v] for v in missing])
print(rows, "profiles;", len(missing), "not found")

一份 2.5 万个账号的列表,会拆成 250 次请求,约 13 秒跑完。在电子表格里打开 profiles.csv 时,要把 id 保持为文本:Excel 对数字只保留 15 位,而用户 ID 最长有 19 位。Python 版 Twitter API 指南里有更多重试和存储的写法,只需要把列表转换成 ID 的场景,见用用户名查 Twitter 用户 ID指南。

#刷新列表并追踪变化

用户资料查询是一张快照:每次运行记录的是那一刻的各项计数,所以按计划重复查询同一份列表,就能把快照变成历史。首次运行之后,按 profiles.csv 的 id 列去查这些账号。ID 永远不变,所以改过名的账号仍然能返回,只是换成了新的用户名。

按 ID 对比两份快照,就能看出粉丝增长、改名和消失的账号:

Python
import csv


def load(path):
    with open(path, newline="", encoding="utf-8") as f:
        return {row["id"]: row for row in csv.DictReader(f)}


old = load("profiles-2026-11-01.csv")
new = load("profiles-2026-11-02.csv")

for user_id, now in new.items():
    then = old.get(user_id)
    if then is None:
        continue                        # added to the list since
    if now["username"] != then["username"]:
        print(f"renamed: @{then['username']} is now @{now['username']}")
    gained = int(now["followers_count"]) - int(then["followers_count"])
    if gained:
        print(f"@{now['username']}: {gained:+,} followers")

gone = sorted(old.keys() - new.keys())
print(len(gone), "accounts no longer returned:", gone[:10])

某个账号不再返回,说明它在上次运行之后被封禁、删除或变得不可用。对线索列表或创作者名单做每日快照,是两家 API 成本差距拉开最快的地方,因为 X 每个 UTC 日都对每份资料重新计费,而 Sorsa API 是对每 100 个一组的请求计费。下面规划一下刷新:

10K
多久查询一次
官方 X API,每月
$3,000
300K 次用户资料读取,每次 $0.010;X 每个 UTC 日都会重新计一次用户资料的费用。
Sorsa API,每月
低至 $4.20
3,000 次请求,每次 100 份用户资料,按每 1,000 次请求 $1.40 计,即最大套餐的费率。

3,000 次请求/月可放进 Starter 套餐的 10K 次请求/月额度。单次运行需要 100 次请求:以每秒 20 次请求计约 5 秒,而官方 X API 每 15 分钟 300 次查询,可在一个窗口内完成。

选择名单规模和刷新频率;两张卡片都显示一个月的费用。

要先找出值得关注的账号,如何在推特上获客这篇指南会从 X 搜索中建立线索列表,而 Twitter 粉丝 API 每页返回任意账号的 200 个粉丝,每个都已附带完整资料。

#批量查询用户资料的成本和耗时

在官方 X API 上,批量查询每 1,000 份资料收费 $10.00;在 Sorsa API 上每 1,000 份 $0.014 起,因为 Sorsa API 按 100 个一组的请求收费,而不是按其中的每份资料收费。

待查询的资料数

官方 X API

$10,000

100 万 份用户资料

每份资料 $0.010

Sorsa API

$14 起

100 万 份用户资料

每 1,000 份 $0.014 起

便宜 700 多倍

时间是第二个差别。官方 X API 允许一个应用每 15 分钟发送 300 次查询请求,所以即使每次调用 100 个,查 100 万份资料也要约 8 小时 20 分钟。Sorsa API 所有套餐(包括免费账号)都是每秒 20 次请求:每秒 2,000 份资料。下表把四种列表规模下的两家并排放在一起:

资料数Sorsa API 成本,起Sorsa API 耗时官方 X API 成本官方 X API 耗时
1 万$0.14约 5 秒$100一个 15 分钟窗口内
10 万$1.40约 50 秒$1,000约 50 分钟
50 万$7.00约 4 分钟$5,000约 4 小时
100 万$14.00约 8 分钟$10,000约 8 小时 20 分钟
  • 1 万

    Sorsa API 成本,起
    $0.14
    Sorsa API 耗时
    约 5 秒
    官方 X API 成本
    $100
    官方 X API 耗时
    一个 15 分钟窗口内
  • 10 万

    Sorsa API 成本,起
    $1.40
    Sorsa API 耗时
    约 50 秒
    官方 X API 成本
    $1,000
    官方 X API 耗时
    约 50 分钟
  • 50 万

    Sorsa API 成本,起
    $7.00
    Sorsa API 耗时
    约 4 分钟
    官方 X API 成本
    $5,000
    官方 X API 耗时
    约 4 小时
  • 100 万

    Sorsa API 成本,起
    $14.00
    Sorsa API 耗时
    约 8 分钟
    官方 X API 成本
    $10,000
    官方 X API 耗时
    约 8 小时 20 分钟

“起”的价格是最大套餐的费率,每 1,000 次请求 $1.40;在最小的 Starter 套餐上,1,000 份资料为 $0.049。所有套餐的计费方式相同:一次请求最多返回 100 份资料,失败的请求从不收费。

须知

请求要尽量发满一组。一次请求带 3 个账号和带 100 个账号,费用一样,所以每个账号单独发一次请求的任务,要多花 100 倍的钱。

#查询你的前 1 万份用户资料

批量查询用户资料,说到底就是每 100 个账号一次请求。在官方 X API 上,这一次请求要 $1.00,而且发完 300 次后就得等一个 15 分钟的窗口。要用资料数据补全 X 账号列表,选 Sorsa API:GET /info-batch 每次请求返回 100 份完整资料,每 1,000 份 $0.014 起,每秒 20 次请求,只需一个密钥,不用开发者账号。新账号的 100 次免费请求就能查询你的前 1 万份用户资料。

#常见问题

批量查询 Twitter 用户资料该用哪个 API?

用 Sorsa API,一款 Twitter(X)API 与爬虫:它的 GET /info-batch 接口每次请求返回 100 份完整资料,每 1,000 份 $0.014 起,而官方 X API 为每 1,000 份 $10.00。所有套餐每秒 20 次请求,只需一个 API 密钥,不用开发者账号和 OAuth,每次调用都返回全部 19 个资料字段。新账号送 100 次免费请求,足够查 1 万份资料。

一次请求最多能查多少个 Twitter 用户资料?

最多 100 个。Sorsa API 的 GET /info-batch 每次请求接受 100 个用户名或 100 个用户 ID,官方 X API 的 GET /2/users/by 和 GET /2/users 也是同样的 100 个。一份 1 万个账号的列表,在两家 API 上都要 100 次调用。区别在于价格和速度:每 100 份资料,官方 X API 是 $1.00,Sorsa API 是 $0.0014 起;官方 X API 每 15 分钟 300 次调用,Sorsa API 每秒 20 次。

有没有免费批量查询 Twitter 用户资料的办法?

官方 X API 没有免费额度:从第一次调用起,每份资料就收费 $0.010。Sorsa API 给每个新账号 100 次免费请求,永不过期,无需绑卡;通过 GET /info-batch 可以覆盖 1 万份资料。一次只查一两个账号的话,免费的推特账号对比工具无需注册就能展示完整资料。

为什么我的批量查询结果里缺少一些账号?

批量查询只返回它找到的账号。拼错、改名、被封禁或已删除的用户名,背后没有公开资料,所以会被从响应里略去,而不是让请求失败。请按用户 ID 或小写用户名匹配结果,把其余的写入单独的列表,改过名的账号则用它们的用户 ID 重新查询。

能批量获取账号的国家或电子邮箱吗?

国家可以,邮箱不行。Sorsa API 的 GET /about 会返回 X 在“关于此账号”下显示的国家、用户名修改次数和最近一次修改的日期,每个账号一次请求。电子邮箱和手机号在 X 上是私密的,所以不管是 Sorsa API 还是官方 X API,任何用户资料查询都不会返回它们。

#我们如何核实

2026 年 11 月 2 日,我们阅读了在线 Sorsa API 参考文档中 /info-batch、/info 和 /about 的条目,本页上的每个请求和字段都据此写成。我们没有带密钥运行它们:示例响应使用虚构账号,格式与参考文档的响应一致。同一天,我们阅读了 docs.x.com 上 X 的用户查询、价格和速率限制页面,了解官方 X API 的接口、价格和限制,并据这些数字算出表中的成本和耗时。

Sorsa API 团队撰写。 我们开发和运营 Sorsa API,这是只读的 Twitter/X API 与爬虫,2022 年起运行于生产环境(前身为 TweetScout API),累计处理请求超 60 亿次。 关于 Sorsa API

更新内容
  • 首次发布。