作者:Sorsa 编辑部

更新于 2026 年 7 月:加入了 100 次免费请求的起步选项、把列表定价围绕每 1,000 份资料费率重新表述,并重建了官方 X API 对比。X 社区可用性重新核查。

要点 一个 X 列表是一个最多 5,000 个账号、带专属时间线的公开精选群组。一个列表 API 在单次调用里返回每个成员、每个订阅者,和来自那些成员的一条合并推文信息流。轮询一个列表取代轮询每个账号,对一个 50 账号的观察列表,把请求量削减大约 50 倍。

X 列表是平台上最被低估的数据源之一。一个维护良好的列表是一份手工精选的名册:一位分析师的一组金融科技创始人、一位记者的一组战地记者、一家交易所的一组加密 KOL。有人已经替你做过受众研究,由此产生的列表可作为一个单一对象查询。

那个工作流背后的接口过去只在官方 X API 里,如果你受得了 OAuth 2.0、每月帖子读取配额,以及对持续监控不可扩展的定价,那它是可行的。替代性 Twitter/X API Sorsa API 通过一个单个 ApiKey 请求头之后的三个接口暴露列表:没有 OAuth、没有应用审查,且每个套餐固定的每秒 20 次请求。因为 /list-members 每次请求返回最多 200 份资料,列表提取在固定套餐上从每 1,000 份资料 $0.01 起,所以下面的模式在规模上保持便宜。战略要点(查什么、一个列表何时胜过原始轮询、如何思考成本)是通用的,代码则是你能照原样跑的朴素 Python。

目录

什么是一个 X 列表,能从中拉什么? {#what-is-an-x-list-and-what-can-you-pull-from-it}

一个 X 列表是最多 5,000 个账号的公开或私密集合,带一条只显示其成员帖子的时间线。任何人都能创建一个,任何有访问权的人都能订阅。通过一个 API,你能从一个公开列表提取两种不同的受众:成员和订阅者。

这两个群组预示不同的东西,而且两者都可提取:

  • 成员是列表上的账号。他们是策划者认为值得追踪的人。
  • **订阅者(列表的粉丝)**是选择关注这个列表来阅读的用户。他们主动选择加入了那个话题。

私密列表不通过任何 API(官方或第三方)可及。下面的一切都假设列表是公开的,且在一个登出的浏览器里打开时能解析。

为什么轮询一个列表而非每个账号? {#why-poll-a-list-instead-of-each-account}

轮询一个列表把许多逐账号请求塌缩成一个。列表之所以对工程、而不只是对策划重要,原因就是请求量。

假设你追踪 50 个账号,比如一个金融科技板块观察列表,并每 10 秒轮询每一个。那是每个周期 50 次请求、每天 8,640 个周期,也就是每天 43.2 万次请求、一个月大约 1300 万。没有任何提供方的任何套餐是为那个而建的。

构建一个同样 50 个账号的列表,改为轮询一条单一推文信息流。在同样的 10 秒间隔上,每个周期一次请求,是每天 8,640 次请求、一个月约 25.9 万。你抓到同样的帖子,往往延迟还更低,因为列表时间线在 X 侧被激进地缓存。

做法每周期请求每天(10 秒轮询)每月(10 秒轮询)
逐账号时间线拉取、50 账号50432,000~13,000,000
单一列表信息流调用18,640~259,000

一次列表调用取代 50 次逐账号调用,这是一个随观察列表扩展的 50 倍削减:一个 200 账号的列表就是 200 倍削减。

实际上你很少需要一个 10 秒的节奏。每 30 秒轮询一个列表,是一个月约 8.6 万次请求,舒舒服服落在 Sorsa 的 Pro 套餐($199 换 10 万次请求)之内。这是我们与跑Twitter 和 X 上社交聆听的客户搭建的实时监测数据管道里的主导模式。

三个列表接口 {#the-three-list-endpoints}

Sorsa 暴露三个列表接口,全都通过 next_cursor 分页。当游标回来为 null 或缺失时,你到达了末尾。

接口返回每请求最佳用途
GET /v3/list-members成员资料最多 200受众提取、列表审计
GET /v3/list-followers列表的订阅者最多 200发现对一个话题感兴趣的人
GET /v3/list-tweets来自成员的合并信息流最多 20监控、内容和情感分析

对受众研究,/list-followers 往往比 /list-members 更有用:成员是策划者挑的,订阅者则自我认定为对话题感兴趣。如果你还需要每个账号自己的粉丝和关注图,那是一个单独的作业,由粉丝和关注列表接口覆盖,而不是这里的列表接口。

列表 API 返回什么? {#what-does-the-list-api-return}

列表接口返回干净 JSON,对嵌套的作者资料不单独计费。/list-members/list-followers 返回一个完整资料对象的 users 数组加一个 next_cursor/list-tweets 返回一个 tweets 数组加一个 next_cursor,每条推文还无额外成本地内联携带完整作者资料。

这些是每个成员或订阅者资料对象上的主要字段:

字段类型含义
idstring稳定的数字用户 ID
usernamestring不带 @ 的用户名
display_namestring资料显示名
descriptionstring简介文本
locationstring资料里的位置
followers_countinteger粉丝数
followings_countinteger用户关注的账号
tweets_countinteger总帖子
verifiedboolean认证徽章
protectedboolean私密账号
created_atstring账号创建日期(ISO 8601)
bio_urlsarray简介里找到的 URL

一条 /list-tweets 响应里的每条推文携带文本、指标和作者。主要字段:

字段类型含义
idstring推文 ID
full_textstring完整帖子文本
created_atstring发布日期(ISO 8601)
langstring检测到的语言代码
likes_countinteger点赞
retweet_countinteger转推
reply_countinteger回复
quote_countinteger引用帖
view_countinteger浏览
is_replyboolean帖子是否是一条回复
is_quote_statusboolean它是否引用另一条帖子
userobject完整作者资料(与上面相同的字段)
entitiesarray附带的媒体和链接

一条精简的 /list-tweets 响应看起来像这样:

json
{
  "tweets": [
    {
      "id": "1782368585664626774",
      "full_text": "Shipping the new pricing today.",
      "created_at": "2026-05-18T10:30:00Z",
      "lang": "en",
      "likes_count": 200,
      "retweet_count": 50,
      "reply_count": 10,
      "view_count": 10000,
      "is_reply": false,
      "is_quote_status": false,
      "user": {
        "id": "44196397",
        "username": "founder",
        "display_name": "A Founder",
        "followers_count": 100000,
        "verified": true,
        "created_at": "2009-06-02T20:12:29Z"
      },
      "entities": []
    }
  ],
  "next_cursor": "DAABCgAB..."
}

因为作者资料内嵌在每条推文里,一次单一列表信息流调用,同时给你内容和背后的人,无需第二次查找,也不按资料收费。完整字段定义在列表和社区文档里。

X 列表在监控之外有什么用? {#what-are-x-lists-good-for-beyond-monitoring}

在实时监测之外,列表还支持几种研究模式,而这些模式否则会需要远更多的工作:

小众专家发现。 记者和分析师精选带像“AI 安全研究者”或“DeFi 创始人”这样名字的列表。成员名册是一份专家审核过的短名单。拉它一次,按粉丝数或近期互动排序,你就在几分钟里有一份触达目标列表。

受众重叠分析。 拉同一小众里两个竞争列表的成员。交集显示共识的选择;差集显示每个策划者的盲点。这比从零跑竞品分析快得多。

板块级情感。 每天拉一个 100 账号行业列表的信息流,把文本推过任意情感模型,并绘制滚动平均。你不用先做任何账号发现,就得到一个信号。

受众继承。 拉一个由受尊敬策划者维护的行业列表的订阅者。这些是选择加入了话题的人,是一个比一次通用粉丝爬取干净得多的在 Twitter 上找合格线索起点。

关于 X 社区的一点说明 {#a-note-on-x-communities}

X 社区是基于话题的、选择加入的群组:成员选择加入,这让名册成为一个强烈的兴趣信号,而不是一个策划者的挑选。Sorsa 通过 /community-members/community-tweets/community-search-tweets 暴露这三个接口,全都遵循与列表接口相同的分页模式,都是 POST。

这里有个状态说明很要紧。X 在 2026 年 4 月宣布计划退役社区,援引不到 0.4% 账号的使用率和平台垃圾的不成比例份额,据 TechCrunch 报道,同时对原始截止日期做了一次延长。此后时间线又变动了,但截至 2026 年 6 月,社区和社区接口仍返回数据。把这个功能当作有风险:如果你要构建任何耐久的东西,就建在列表上,列表没有被安排移除。如果你现在需要提取一个社区,模式和下面的列表代码完全相同,用带 community_idcommunity_link 的 POST。

Twitter 列表 API vs 官方 X API {#twitter-list-api-vs-the-official-x-api}

官方 X API 确实暴露列表接口。用哪个大多取决于你需要多少量、以及你愿意维护多少 OAuth。Sorsa API 是我们的产品,下面的对比用的是你能在 X 的开发者文档和我们自己的 X API 定价拆解里核验的数字。在投入之前对着你自己的工作负载测试任何提供方。

Sorsa API官方 X API
计费模型按请求计费(1 次调用 = 1 次请求)每抓取资源、按量付费
每次调用列表资料单次请求里最多 200按返回的资料计费
读密集列表拉取的成本从每 1,000 份资料 $0.01 起按资源收费、随量攀升
一条列表信息流里的作者资料免费包含作为一次单独用户读取计费
搭建单个 API 密钥、几分钟就绪第一方接入
写访问无(只读)有发帖和私信
社区接口有(有风险,见上面说明)可用

核心差别是计费单位。Sorsa 每次调用收一次请求,不管回来多少资料或推文,所以一个列表页里最多 200 份资料、以及一条列表信息流里内嵌的作者资料,都没有额外花费。官方 X API 把那些每一个都作为一次单独资源读取计费,这正是让持续列表监控成本累加的原因。在读密集列表工作负载上,Sorsa 跑得便宜最高 50 倍。速率限制拆解覆盖为什么持续轮询是两个模型分歧最大之处。

裁决:

  • 读密集的列表提取和监控: Sorsa。按请求计费的定价,加上每次调用最多 200 份资料,让持续轮询保持便宜,而一个单个 API 密钥就足以起步。
  • 发帖、私信、Ads API 或过滤流式: 官方 X API,因为那些是 Sorsa 不提供的第一方写入和流式能力。

如何设置一个你能监控的列表 {#how-to-set-up-a-list-you-can-monitor}

你只能从已存在的列表拉数据;在这一点上,每个 API 都是只读的。要设置一个你能监控的列表,在 X 网页界面里做一次:

  1. 去 x.com/lists 并选“创建新列表”。
  2. 把列表标为公开。私密列表任何人都不能通过 API 访问。
  3. 加最多 5,000 个账号。你能粘用户名、搜索,或批量导入。
  4. 从 URL 复制数字列表 ID:在 https://x.com/i/lists/1234567890 里,ID 是 1234567890
  5. 以你的延迟预算允许的任何间隔对着那个 ID 轮询列表信息流。

列表不必是你的才可查询。如果别人的公开列表已经覆盖你的话题,就从他们的 URL 抓 ID。如果你在构建一条私密监控数据管道,不想你追踪的账号在你的主身份下暴露,就用一个通用名字在一个单独账号下创建列表。列表保持公开,这样 API 能访问,但不绑定到你的真实用户名。

代码:在 Python 里拉列表数据 {#code-pulling-list-data-in-python}

示例用带 requests 的朴素 Python。没有 SDK,没有认证折腾。示例假设 Python 3.9 或更新,以及一个环境变量里的 API 密钥。每个分页接口返回 next_cursor;当游标为 null 或缺失时,就结束了。

python
import os
import time
import requests

API_KEY = os.environ["SORSA_API_KEY"]
BASE = "https://api.sorsa.io/v3"
HEADERS = {"ApiKey": API_KEY}

提取列表成员

python
def get_list_members(list_id, max_pages=50):
    """从一个公开 X 列表取回成员资料。每页最多 200。"""
    members, cursor = [], None

    for _ in range(max_pages):
        params = {"list_id": list_id}
        if cursor:
            params["next_cursor"] = cursor

        r = requests.get(f"{BASE}/list-members", headers=HEADERS, params=params, timeout=30)
        r.raise_for_status()
        data = r.json()

        members.extend(data.get("users", []))
        cursor = data.get("next_cursor")
        if not cursor:
            break
        time.sleep(0.1)

    return members


members = get_list_members("1234567890")
print(f"Pulled {len(members)} members")

for m in members[:5]:
    bio = (m.get("description") or "")[:60]
    print(f"@{m['username']} ({m['followers_count']:,} followers): {bio}")

一个完全填满的 5,000 成员列表约需 25 次请求来提取,因为这个接口每次调用返回最多 200 份资料。

提取列表订阅者

订阅者(关注列表来阅读的人,而不是列表上的成员)用 list_link 参数,它接受完整 URL 或只是数字 ID。

python
def get_list_followers(list_link, max_pages=50):
    """订阅一个公开 X 列表的用户。"""
    followers, cursor = [], None

    for _ in range(max_pages):
        params = {"list_link": list_link}
        if cursor:
            params["next_cursor"] = cursor

        r = requests.get(f"{BASE}/list-followers", headers=HEADERS, params=params, timeout=30)
        r.raise_for_status()
        data = r.json()

        followers.extend(data.get("users", []))
        cursor = data.get("next_cursor")
        if not cursor:
            break
        time.sleep(0.1)

    return followers


subs = get_list_followers("https://x.com/i/lists/1234567890")
print(f"{len(subs)} accounts subscribe to this List")

从一个列表拉推文

这是监控接口:每次调用约 20 条推文,跨所有成员按时间顺序排序。

python
def get_list_tweets(list_id, max_pages=10):
    """来自一个列表所有成员的近期推文,合并信息流。"""
    tweets, cursor = [], None

    for _ in range(max_pages):
        params = {"list_id": list_id}
        if cursor:
            params["next_cursor"] = cursor

        r = requests.get(f"{BASE}/list-tweets", headers=HEADERS, params=params, timeout=30)
        r.raise_for_status()
        data = r.json()

        tweets.extend(data.get("tweets", []))
        cursor = data.get("next_cursor")
        if not cursor:
            break
        time.sleep(0.1)

    return tweets


feed = get_list_tweets("1234567890", max_pages=20)
print(f"Collected {len(feed)} tweets")

for t in feed[:5]:
    likes = t.get("likes_count", 0)
    print(f"@{t['user']['username']} ({likes} likes): {t['full_text'][:80]}")

对持续监控,以适合你延迟预算的任何间隔在一个 cron 或 asyncio 循环上跑这个。每 30 到 60 秒轮询对交易信号之外的一切都绰绰有余。

导出到 CSV

python
import csv

def export_users_to_csv(users, path):
    fields = ["id", "username", "display_name", "description",
              "followers_count", "tweets_count", "verified", "location"]

    with open(path, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=fields)
        writer.writeheader()
        for u in users:
            writer.writerow({
                "id": u.get("id", ""),
                "username": u.get("username", ""),
                "display_name": u.get("display_name", ""),
                "description": (u.get("description") or "").replace("\n", " "),
                "followers_count": u.get("followers_count", 0),
                "tweets_count": u.get("tweets_count", 0),
                "verified": u.get("verified", False),
                "location": u.get("location", ""),
            })

    print(f"Wrote {len(users)} rows to {path}")


export_users_to_csv(get_list_members("1234567890"), "members.csv")

同样的模式对订阅者有效。对推文,把字段列表换成 idfull_textcreated_atlikes_countretweet_count,和 user 用户名。

重试和速率限制处理

任何你按计划跑的东西都需要最少的错误处理。固定的 Sorsa 速率限制是每秒 20 次请求。如果你超过,就得到一个 429;退避并重试。

python
def request_with_retry(method, url, max_attempts=5, **kwargs):
    for attempt in range(max_attempts):
        r = requests.request(method, url, **kwargs)

        if r.status_code == 429:
            time.sleep(2 ** attempt)
            continue

        if r.status_code >= 500:
            time.sleep(1 + attempt)
            continue

        r.raise_for_status()
        return r

    raise RuntimeError(f"Failed after {max_attempts} attempts: {url}")

把这个放进上面任何函数里 requests.get 的位置。对长跑作业,在页之间记录游标,这样你能在失败时恢复,而不重做工作。更多模式在优化 API 使用里。

这在实战中是什么样 {#what-this-looks-like-in-practice}

我们合作过的一个小分析团队,约十人,为一个交易席位构建信号,一直在通过单独轮询每个账号来监控大约 120 个加密 KOL。逐账号做法在官方 API 上既贵又反应慢。把同样的账号搬进一个单一公开列表、轮询一条信息流,就把每个周期 120 次逐账号拉取替换成了一次,这是 120 倍的请求量削减。它还让他们比等聚合的第三方情感追踪器更早读到语气转变。数据成本遵循任何读密集团队在关掉官方 API 时看到的一般模式:同样的覆盖,便宜最高 50 倍。这个胜利是结构性的,不是一个把戏:一条列表信息流,而不是 120 条时间线。

开始上手 {#getting-started}

从 Sorsa 控制台抓一个 API 密钥,把它指向一个你已经在 X 上关注的列表,几分钟就能开始收集结构化数据。每个新密钥含 100 次免费请求,一次性、无需绑卡,足够在你投入之前拉最多 2 万份列表成员资料,或跑一个监控循环。API Playground 让你先不写代码就测试每个接口;定价套餐是固定价,列表提取从每 1,000 份资料 $0.01 起,每个层级都是同样的每秒 20 次请求。如果你在离开官方 X API、想要一份逐接口映射,迁移指南走一遍那些对应关系。

常见问题 {#faq}

你能从一个私密 X 列表提取成员吗?

不能。私密 X 列表不通过任何 API(官方或第三方)可访问。列表必须公开,而且它的 URL 必须在一个登出的浏览器里打开时能解析。任何声称能拉私密列表数据的人,要么弄错了,要么打算滥用一个登录的账号。本指南里描述的一切都假设一个公开列表。

你能提取的最大 X 列表大小是多少?

X 把列表封顶在 5,000 个成员。Sorsa list-members 接口以每次请求最多 200 份资料分页,所以一个完整的 5,000 成员列表约需 25 次调用来端到端提取。除了 5,000 成员平台限制本身外没有隐藏上限。

你如何从一个列表的 URL 找到列表 ID?

X 列表 URL 看起来像 https://x.com/i/lists/1234567890,其中末尾的数字值是列表 ID。一些较老的 URL 用 x.com/username/lists/slug 形式;打开那个链接会重定向到数字版本,由此产生的 URL 里的数字,就是你传给 API 的 ID。

X 社区通过 API 还管用吗?

截至 2026 年 6 月,管用。X 在 2026 年 4 月宣布计划退役社区,援引低使用率和高垃圾;最初宣布的截止点此后又移动了,但这个功能和社区接口仍返回数据。把社区当作有风险,把耐久的监控建在列表上,列表没有被安排移除。

轮询一个列表比每个账号调用一次 API 更高效吗?

是,这也是列表对工程重要的主要原因。构建一个公开列表并轮询一条单一推文信息流,取代每个周期每个账号一次请求。在 Sorsa 上,对一个 50 账号的观察列表,这比单独轮询每个账号大约少 50 倍请求,而且这个节省随列表上的账号数扩展。

你能从一个列表拿到历史推文、而不只是近期的吗?

一条列表推文信息流返回其成员的近期合并时间线,回溯到那条时间线可得的最远处。对一个特定账号的深度历史,改拉那个账号自己的时间线;在 Sorsa 上,user-tweets 接口回溯翻页到一个账号最早的帖子,没有 3,200 推文上限。列表是为监控的,逐账号拉取是为存档的。

拉列表数据相比官方 X API 花多少钱?

Sorsa 每次 API 调用只收一次请求,不管回来多少资料或推文,所以列表提取在固定套餐上从每 1,000 份资料 $0.01 起,而每个新密钥含 100 次免费请求先试。官方 X API 在按量付费下按抓取的资源计费,所以一次返回许多用户和推文的单一列表读取按项收费。在读密集列表工作负载上,Sorsa 跑得便宜最高 50 倍。

来自旧 Twitter v1.1 时代的列表 ID 还管用吗?

管用,只要列表仍公开且在网页上加载。在 Twitter v1.1 时代创建的列表 ID 在当前 X 平台上、以及在像 Sorsa 这样的第三方 API 上仍有效。Twitter 到 X 的更名没有使现有列表 ID 失效,也没有改变它们的数字格式。


审校:Keksich(Sorsa 创始人,X API 研究者)

本指南取材于我们团队运营 Sorsa 列表和社区接口的亲手工作、实时的 Sorsa API v3 文档,以及 X 自己的开发者文档。X 社区退役时间线取材于 TechCrunch;社区可用性在 X 上直接核查。定价和速率限制对比对照我们的 2026 X API 定价指南和官方 X 开发者定价页重新核验。最后核验于 2026 年 7 月 6 日。