跳到正文

snscrape、Twint、twikit 和 twscrape:X 上还有什么能用

snscrape 和 Twint 在 2023 年就不再适用于 X,而且不会恢复;twikit 的最新版本自 2026 年 3 月 18 日 X 改版后一直失效;twscrape 仍然能用,但只能运行在你提供的已登录 X 账号上。

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

简短回答: 2026 年 11 月 2 日,snscrape 对 X 仍然返回 blocked (404),自 2023 年 6 月 30 日起就是如此;Twint 已归档;twikit 2.3.3 还停在 2025 年 2 月。想在不拿 X 账号冒险的前提下跑同样的任务,用 Sorsa API:POST /search-tweets 直接接受你原来的查询,每次请求约 20 条推文,每 1,000 条 $0.07 起,另有 100 次免费请求。

接口
POST /search-tweets
每页条数
每次请求约 20 条推文
价格
每 1,000 条 $0.07 起

#2026 年还有哪些 Twitter 爬取库能用

人们仍在安装来获取 X 数据的八个 Python 库里,两个仍在维护且能用,一个作为分叉能用,一个更新缓慢,四个已经失效或损坏。凡是还能用的库,都以 X 账号的身份登录,因为自 2023 年 6 月 30 日起,X 只对已登录用户显示搜索、完整时间线和粉丝列表。

下表是 2026 年 11 月 2 日 PyPI 和 GitHub 上的情况,以及各个库失效时打印的错误。

库最近发布状态需要你会看到的错误
snscrape2023-06-22Twitter 模块已失效不需要(未登录)blocked (404)
Twint2020-04-292023-03-30 归档不需要(未登录)Guest token not found
twikit2025-02-07自 2026-03-18 起损坏登录或 CookieKEY_BYTE indices
twifork2026-08-30twikit 的可用分叉浏览器 CookieCookie 过期
twscrape2026-08-25可用X 账号账号被锁、403
Scweet2026-10-22可用auth_token Cookie账号被锁
ntscraper2025-05-24随 Nitter 一起失效一个 Nitter 实例实例宕机
tweety2025-07-15更新缓慢一个 X 账号账号变成只读
  • snscrape

    最近发布
    2023-06-22
    状态
    Twitter 模块已失效
    需要
    不需要(未登录)
    你会看到的错误
    blocked (404)
  • Twint

    最近发布
    2020-04-29
    状态
    2023-03-30 归档
    需要
    不需要(未登录)
    你会看到的错误
    Guest token not found
  • twikit

    最近发布
    2025-02-07
    状态
    自 2026-03-18 起损坏
    需要
    登录或 Cookie
    你会看到的错误
    KEY_BYTE indices
  • twifork

    最近发布
    2026-08-30
    状态
    twikit 的可用分叉
    需要
    浏览器 Cookie
    你会看到的错误
    Cookie 过期
  • twscrape

    最近发布
    2026-08-25
    状态
    可用
    需要
    X 账号
    你会看到的错误
    账号被锁、403
  • Scweet

    最近发布
    2026-10-22
    状态
    可用
    需要
    auth_token Cookie
    你会看到的错误
    账号被锁
  • ntscraper

    最近发布
    2025-05-24
    状态
    随 Nitter 一起失效
    需要
    一个 Nitter 实例
    你会看到的错误
    实例宕机
  • tweety

    最近发布
    2025-07-15
    状态
    更新缓慢
    需要
    一个 X 账号
    你会看到的错误
    账号变成只读

两种规律解释了整张表。未登录读取 X 的库(snscrape、Twint,以及通过 Nitter 的 ntscraper)失去了数据来源,任何补丁都无法让它回来。需要登录的库,只有在它们的 X 账号保持活跃、代码又跟得上 X 网页应用的改动时,才能继续工作。X 网页应用在过去 12 个月里把内部搜索的查询 ID(query ID)改了 37 次。我们的怎么爬取 Twitter指南同样介绍了浏览器和官方 X API。

各个库何时停止读取 X 发布和 issue 日期来自 PyPI 和 GitHub,核对于 2026 年 11 月 2 日 2020 2021 2022 2023 2024 2025 2026 现在 Twint 已归档 访客令牌出错,2020 年 10 月 2023 年 3 月 30 日归档 snscrape 对 X 已失效 2023 年 6 月 30 日失效(#996) 最后一次发布早 8 天 ntscraper 随 Nitter 一起失效 最后一次发布 2025 年 5 月 24 日 Nitter 于 2026 年 10 月 9 日归档 twikit 上游已坏 最后一次发布 2025 年 2 月 7 日 2026 年 3 月 18 日失效(#408) twscrape 账号方式仍可用 2026 年 8 月 25 日的 0.20.1 需登录账号
所有未登录的库都没了。仍然能用的库,包括 twscrape,都运行在已登录的账号上。

#用一个 Sorsa API 请求替换库调用

对用过这些库的项目,用 Sorsa API,一款 Twitter(X)API 与爬虫:它用一个 ApiKey 请求头,以 JSON 返回同样的公开推文、用户资料和粉丝列表,无需 X 账号、Cookie 或代理;X 改动网页应用时,修复由我们负责,你的代码和响应结构都保持不变。搜索结果每 1,000 条 $0.07 起,粉丝每 1,000 个 $0.007 起,所有套餐(包括免费起步)都允许每秒 20 次请求。

四步就能迁完一个脚本:

  1. 获取密钥。注册后,在控制台复制 API 密钥。前 100 次请求免费,永不过期。

  2. **添加一个辅助函数。**这些函数代替原来的库导入。每个列表接口返回一页和一个 next_cursor;辅助函数会把 cursor 送回去,直到它返回为空。

    sorsa_helper.py
    import requests
    
    BASE = "https://api.sorsa.io/v3"
    HEADERS = {"ApiKey": "YOUR_API_KEY"}
    
    
    def pages(method, path, payload):
        """Call a Sorsa API list endpoint and yield every page."""
        payload = dict(payload)
        send = requests.get if method == "GET" else requests.post
        arg = "params" if method == "GET" else "json"
        while True:
            r = send(BASE + path, headers=HEADERS, timeout=30, **{arg: payload})
            r.raise_for_status()  # 403: key or quota, 429: over 20 requests/s
            page = r.json()
            yield page
            if not page.get("next_cursor"):
                return
            payload["next_cursor"] = page["next_cursor"]
    
    
    def items(method, path, payload, key, limit=None):
        """Yield tweets or users across pages, stopping at limit."""
        n = 0
        for page in pages(method, path, payload):
            for item in page.get(key) or []:
                yield item
                n += 1
                if limit and n >= limit:
                    return
    
    
    def search(query, limit=None, order="latest"):
        body = {"query": query, "order": order}
        return items("POST", "/search-tweets", body, "tweets", limit)
    
    
    def user_tweets(username, limit=None):
        body = {"username": username}
        return items("POST", "/user-tweets", body, "tweets", limit)
    
    
    def followers(username, limit=None):
        params = {"username": username}
        return items("GET", "/followers", params, "users", limit)
    
  3. **逐个替换调用。**选好你的库,以及你的脚本发出的调用;转换器会显示对应的请求。

    你使用的库
    之前:snscrape
    scraper = sntwitter.TwitterSearchScraper(
        "python lang:en")
    for tweet in scraper.get_items():
        print(tweet.rawContent)
    之后:Sorsa API
    for tweet in search("python lang:en"):
        print(tweet["full_text"])
    接口
    POST /search-tweets
    一次请求返回
    约 20 条推文
    Sorsa API 价格
    低至每 1,000 条推文 $0.07

    你的查询字符串原样可用: from:, since:, until:, lang: 和 min_faves: 的用法一致。设置 order 为 "latest" ,即可得到 snscrape 那样的最新优先顺序。

    每个库调用都对应一个 Sorsa API 接口。写入类调用和点赞没有对应的只读功能。

  4. **检查第一页。**每个响应都把作者的完整资料放在每条推文里面,所以 twscrape 和 twikit 为拿用户 ID 要做的第二次查询可以省掉了。

    响应200 OK
    {
      "tweets": [
        {
          "id": "2116173807613027825",
          "full_text": "Moved our nightly tweet pull off a dead library.",
          "created_at": "2026-10-30T14:22:07Z",
          "lang": "en",
          "likes_count": 214,
          "retweet_count": 37,
          "reply_count": 19,
          "quote_count": 6,
          "view_count": 18450,
          "conversation_id_str": "2116173807613027825",
          "user": {
            "id": "1592041833471827968",
            "username": "lena_ships_python",
            "display_name": "Lena Ships Python",
            "followers_count": 2310
          }
        }
      ],
      "next_cursor": "DAACCgACGW7xDmNAJxAKAAMZbvEOY0AnEAgABAAAAAEAAA"
    }
    

完整的调用对照表

这些表格覆盖了大多数脚本会发出的调用。每一行是一个 Sorsa API 请求;各个库的那几列,是它所替代的调用。需要登录的库放在最前面,因为它们的脚本还在运行。

任务Sorsa APItwikittwscrape
搜索推文POST /search-tweets(在新标签页打开)search_tweetsearch
某个用户的推文POST /user-tweets(在新标签页打开)get_user_tweetsuser_tweets
一份用户资料GET /info(在新标签页打开)get_user_by_screen_nameuser_by_login
粉丝GET /followers(在新标签页打开)get_user_followersfollowers
关注列表GET /follows(在新标签页打开)get_user_followingfollowing
一条推文POST /tweet-info(在新标签页打开)get_tweet_by_idtweet_details
按 ID 查 100 条推文POST /tweet-info-bulk(在新标签页打开)get_tweets_by_ids无
一条推文的回复POST /comments(在新标签页打开)get_tweet_by_idtweet_replies
转发者POST /retweeters(在新标签页打开)get_retweetersretweeters
搜索用户POST /search-users(在新标签页打开)search_usersearch_user
列表推文GET /list-tweets(在新标签页打开)get_list_tweetslist_timeline
趋势GET /trends(在新标签页打开)get_place_trendstrends
账号“关于”数据GET /about(在新标签页打开)无user_about

snscrape 和 Twint 覆盖的任务更少,每一项也都映射到同样的接口:

任务Sorsa APIsnscrapeTwint
搜索推文POST /search-tweetsTwitterSearchScraperrun.Search
话题标签POST /search-tweetsTwitterHashtagScraperc.Search 加 #tag
某个用户的推文POST /user-tweetsTwitterUserScraperc.Username
一份用户资料GET /infoTwitterUserScraper.entityrun.Lookup
粉丝GET /followers无run.Followers
关注列表GET /follows无run.Following
一条推文POST /tweet-infoTwitterTweetScraper无
列表推文GET /list-tweetsTwitterListPostsScraper无
趋势GET /trendsTwitterTrendsScraper无
  • 搜索推文

    Sorsa API
    POST /search-tweets
    snscrape
    TwitterSearchScraper
    Twint
    run.Search
  • 话题标签

    Sorsa API
    POST /search-tweets
    snscrape
    TwitterHashtagScraper
    Twint
    c.Search 加 #tag
  • 某个用户的推文

    Sorsa API
    POST /user-tweets
    snscrape
    TwitterUserScraper
    Twint
    c.Username
  • 一份用户资料

    Sorsa API
    GET /info
    snscrape
    TwitterUserScraper.entity
    Twint
    run.Lookup
  • 粉丝

    Sorsa API
    GET /followers
    snscrape
    无
    Twint
    run.Followers
  • 关注列表

    Sorsa API
    GET /follows
    snscrape
    无
    Twint
    run.Following
  • 一条推文

    Sorsa API
    POST /tweet-info
    snscrape
    TwitterTweetScraper
    Twint
    无
  • 列表推文

    Sorsa API
    GET /list-tweets
    snscrape
    TwitterListPostsScraper
    Twint
    无
  • 趋势

    Sorsa API
    GET /trends
    snscrape
    TwitterTrendsScraper
    Twint
    无

还有两个请求,在各库里没有值得单列一行的对应项。GET /info-batch(在新标签页打开) 一次请求最多返回 100 份资料,而各个库都是一个账号一个账号地查;GET /verified-followers(在新标签页打开) 替代 twscrape 的 verified_followers 和 twikit 的 get_user_verified_followers。

有两项任务没有只读的替代方案。谁点赞了一条帖子的列表(twikit 的 get_favoriters、Twint 的 --favorites),以及用户自己的点赞或书签,不是 Sorsa API 返回的公开数据。发帖、关注和私信(twikit 的 create_tweet、follow_user、send_dm)仍然交给官方 X API,因为 Sorsa API 在设计上是只读的,从不碰你的 X 账号。

#snscrape 为什么返回 blocked (404)

snscrape 对每次 Twitter 爬取都返回 blocked (404),因为它是未登录读取 X 的,而 X 在 2023 年 6 月 30 日停止向未登录访客提供搜索和时间线。维护者当天就提交了 issue #996(在新标签页打开),标题是“All Twitter scrapes are failing”;它至今未关闭,已有 161 条评论。

这个库会获取一个 guest token,也就是 X 曾经发给匿名访客的通行证,然后调用未登录网页所用的接口。登录在设计上就不在范围内:issue #270(在新标签页打开) 写明 snscrape“does not and will not support logging into social network accounts”,也就是不会支持登录社交网络账号。最后一个 PyPI 版本 0.7.0.20230622 在失效前八天发布,所以重装、换新的 Python 版本或使用开发分支,都没有任何改变。其他社交网络的模块是另一回事;Twitter 模块已经没有回头路。

大多数教程教的那个搜索循环,可以一行对一行地迁过来。你的查询字符串保留它的操作符:from:、since:、until:、lang: 和 min_faves: 在 query 字段里的用法完全一样。

import itertools
import snscrape.modules.twitter as sntwitter

query = "from:lena_ships_python since:2026-10-01"
scraper = sntwitter.TwitterSearchScraper(query)
for tweet in itertools.islice(scraper.get_items(), 100):
    print(tweet.date, tweet.likeCount, tweet.rawContent)

TwitterUserScraper("lena_ships_python") 变成 user_tweets("lena_ships_python"),TwitterHashtagScraper("yourtag") 变成 search("#yourtag")。我们的 Twitter 搜索操作符参考列出了 query 字段接受的每个操作符,可回溯到 2006 年的帖子。

#Twint:guest token 错误和归档

Twint 是彻底失效了:它的 GitHub 仓库在 2023 年 3 月 30 日被所有者归档,最后一个 PyPI 版本(2.1.20)发布于 2020 年 4 月 29 日,而且它读取 X 用的,正是 snscrape 失去的那个未登录 guest token。

它的故障在归档的几年前就开始了。RefreshTokenException: Could not find the Guest token in HTML 在 2020 年 10 月的 issue 里就出现了,而 2023 年 3 月 3 日提交的 issue #1433(在新标签页打开) 是归档前关于它的最后一份报告。人们引用的另一个错误 CRITICAL:root:twint.run:Twint:Feed:noData,意思是 Twint 解析的页面返回时没有它预期的数据。给 token.py 打补丁的分叉,在 2023 年 6 月撞上了同一堵登录墙。

Twint 的 Config 对象对应成普通参数。c.Search 和 c.Username 变成查询或用户名,c.Since 和 c.Until 以 since: 和 until: 的形式移进查询,c.Store_csv 则变成一个由你掌控的 CSV 写入器。

import twint

c = twint.Config()
c.Search = "python"
c.Since = "2026-10-01"
c.Limit = 100
c.Store_csv = True
c.Output = "tweets.csv"
twint.run.Search(c)

twint.run.Followers(c) 和 twint.run.Following(c) 变成 GET /followers 和 GET /follows,每页最多 200 个账号。想拿到超出 Twint 原来 3,200 条推文滚动上限的整条时间线,就是按日期范围搜索,我们的下载用户的全部推文指南会带你走一遍。

#twikit:2026 年 3 月的失效与 twifork

twikit 的最新版本 2.3.3 发布于 2025 年 2 月 7 日,自 2026 年 3 月 18 日 X 改版其网页应用以来,每次调用都会失败。Issue #408(在新标签页打开) 报告了 Couldn't get KEY_BYTE indices,至今未关闭;issue #425 又补充了一个 2026 年 4 月 23 日的 KeyError。

问题出在 twikit 与 X 通信的方式上。它以普通 X 用户的身份登录,调用 x.com 网页应用所用的内部 GraphQL 接口,每次调用都需要一个 x-client-transaction-id 请求头,其值由 X 下发的一段脚本计算得出。X 改了这段脚本之后,twikit 的解析器就再也匹配不上了。上游仓库有 160 个未解决的 issue 和 pull request,此后一直没有发布新版本。

有一个分叉在延续这份代码。2026 年 8 月 30 日发布的 twifork(在新标签页打开) 2.4.0 保留了 from twikit import Client 这一导入方式,并修复了 2026 年的这些故障,它的 README 把局限说得很直白:密码登录“cannot be made to work”,即无法做到可用,而访客访问“is closed on X's side; use cookies”,即已被 X 一侧关闭,请改用 Cookie。要运行它,就得从某个 X 账号的浏览器会话里导出 auth_token 和 ct0 Cookie,并时刻留意这个账号会不会被锁。

像 search_tweet("python", "Latest") 这样的 twikit 搜索,变成对辅助函数的一次调用:

迁移后:Sorsa API
from sorsa_helper import search

for t in search("python", limit=20):
    print(t["created_at"], t["user"]["username"], t["full_text"])

twikit 的 'Top' 对应 "order": "popular",'Latest' 对应 "latest"。Cookie 文件、asyncio 循环,以及它们背后的账号,全都不需要了。

#twscrape:能用,但要你提供 X 账号

twscrape 在 2026 年仍然能用:0.20.1 版本发布于 2026 年 8 月 25 日,仓库在 10 月 31 日又有更新。它的 README(在新标签页打开) 开门见山地说明了前提:它“requires authorized X/Twitter accounts”,也就是需要经过授权的 X/Twitter 账号,通过含有 auth_token 和 ct0 的浏览器 Cookie 添加。

这个库运行的是一个账号池,所以池里的每个账号都有被锁定的风险。

实际中会出现三类故障:

  • **账号被锁或登出。**账号池里没有活跃账号时,它会等待,或抛出 NoAccountError。
  • **Cloudflare 拦截。**未关闭的 issue #337(在新标签页打开)(2026 年 9 月 12 日)在 user_by_id 上记录了 Blocked by Cloudflare: 403。
  • **X 网页应用的改动。**X 会给内部 GraphQL 调用添加新的功能开关(flag),一旦其中某个变成必填项,twscrape 就会抛出 GqlFeaturesOutdatedError,直到新版本跟上。

twscrape 的 user_by_login、user_tweets 和 followers 调用,变成对辅助函数的两次调用:

迁移后:Sorsa API
from sorsa_helper import followers, user_tweets

tweets = list(user_tweets("lena_ships_python", limit=100))
fans = list(followers("lena_ships_python", limit=1000))

不需要查用户 ID,因为 POST /user-tweets 和 GET /followers 直接接受用户名。1,000 个粉丝每页 200 个,五次请求就拿到了。

#twscrape、twikit 和 snscrape 怎么比

三者之中,只有 twscrape 能直接用官方版本运行,twikit 只能通过它的分叉运行,snscrape 则无法为 X 修复;今天它们没有一个能脱离 X 账号运行。决定替代方案的标准是:现在能不能用,需要你提供什么,你的代码能否一直跑下去,一次请求返回多少,以及 1,000 条结果花多少钱。

标准Sorsa APItwscrapetwikitsnscrape
今天在 X 上能用吗能能通过 twifork不能
是否需要 X 账号不需要需要一个账号池需要一个,用 Cookie不需要,但已失效
X 有变动时由我们负责修复等新版本发布等分叉打补丁永远不会修复
每次请求的推文数约 20 条;按 ID 查 100 条约 20 条约 20 条过去约 20 条
账号是否有风险从不池里的每一个提供 Cookie 的那个账号无
接入一个 API 密钥账号、Cookie、代理导出 Cookie什么都不用,什么也返回不了
每 1,000 条推文的价格$0.07 起账号、代理、时间账号、时间免费,没有数据
  • 今天在 X 上能用吗

    Sorsa API
    能
    twscrape
    能
    twikit
    通过 twifork
    snscrape
    不能
  • 是否需要 X 账号

    Sorsa API
    不需要
    twscrape
    需要一个账号池
    twikit
    需要一个,用 Cookie
    snscrape
    不需要,但已失效
  • X 有变动时

    Sorsa API
    由我们负责修复
    twscrape
    等新版本发布
    twikit
    等分叉打补丁
    snscrape
    永远不会修复
  • 每次请求的推文数

    Sorsa API
    约 20 条;按 ID 查 100 条
    twscrape
    约 20 条
    twikit
    约 20 条
    snscrape
    过去约 20 条
  • 账号是否有风险

    Sorsa API
    从不
    twscrape
    池里的每一个
    twikit
    提供 Cookie 的那个账号
    snscrape
    无
  • 接入

    Sorsa API
    一个 API 密钥
    twscrape
    账号、Cookie、代理
    twikit
    导出 Cookie
    snscrape
    什么都不用,什么也返回不了
  • 每 1,000 条推文的价格

    Sorsa API
    $0.07 起
    twscrape
    账号、代理、时间
    twikit
    账号、时间
    snscrape
    免费,没有数据

如果一条数据管道下个月还得跑,选 Sorsa API:搜索操作符和这些库一样,任务也一样,搜索每次请求约 20 条推文,按 ID 批量查询每次 100 条,所有套餐都是每秒 20 次请求,也没有会被锁的 X 账号。它自 2022 年起投入生产,累计处理请求超 60 亿次,最初叫 TweetScout API。

#迁移你的代码读取的字段

Sorsa API 的字段名用下划线命名,并把作者的完整资料嵌套在 user 里,所以迁移只要重命名十来个属性,其他一切不变。下表给出各个库里的旧名字,以及取代它的字段。

Sorsa API 字段snscrape、twscrapetwikitTwint
id(字符串)ididid
created_at(ISO 8601)datecreated_atdatetime
full_textrawContenttexttweet
user.usernameuser.usernameuser.screen_nameusername
user.display_nameuser.displaynameuser.namename
likes_countlikeCountfavorite_countlikes_count
retweet_countretweetCountretweet_countretweets_count
reply_countreplyCountreply_countreplies_count
quote_countquoteCountquote_count无
view_countviewCountview_count无
conversation_id_strconversationId无conversation_id
quoted_statusquotedTweetquote无
  • id(字符串)

    snscrape、twscrape
    id
    twikit
    id
    Twint
    id
  • created_at(ISO 8601)

    snscrape、twscrape
    date
    twikit
    created_at
    Twint
    datetime
  • full_text

    snscrape、twscrape
    rawContent
    twikit
    text
    Twint
    tweet
  • user.username

    snscrape、twscrape
    user.username
    twikit
    user.screen_name
    Twint
    username
  • user.display_name

    snscrape、twscrape
    user.displayname
    twikit
    user.name
    Twint
    name
  • likes_count

    snscrape、twscrape
    likeCount
    twikit
    favorite_count
    Twint
    likes_count
  • retweet_count

    snscrape、twscrape
    retweetCount
    twikit
    retweet_count
    Twint
    retweets_count
  • reply_count

    snscrape、twscrape
    replyCount
    twikit
    reply_count
    Twint
    replies_count
  • quote_count

    snscrape、twscrape
    quoteCount
    twikit
    quote_count
    Twint
    无
  • view_count

    snscrape、twscrape
    viewCount
    twikit
    view_count
    Twint
    无
  • conversation_id_str

    snscrape、twscrape
    conversationId
    twikit
    无
    Twint
    conversation_id
  • quoted_status

    snscrape、twscrape
    quotedTweet
    twikit
    quote
    Twint
    无

对于大型代码库,可以先用一个小适配器,在你迁移其余部分时继续沿用旧的属性名。它把每条 Sorsa API 推文包装成一个对象,用 snscrape 和 twscrape 的名字来回应:

adapter.py
from datetime import datetime
from types import SimpleNamespace


def as_snscrape(t):
    """A Sorsa API tweet under snscrape/twscrape attribute names."""
    u = t["user"]
    return SimpleNamespace(
        id=int(t["id"]),
        url=f"https://x.com/{u['username']}/status/{t['id']}",
        date=datetime.fromisoformat(t["created_at"].replace("Z", "+00:00")),
        rawContent=t["full_text"],
        lang=t.get("lang"),
        likeCount=t["likes_count"],
        retweetCount=t["retweet_count"],
        replyCount=t["reply_count"],
        quoteCount=t["quote_count"],
        viewCount=t.get("view_count"),
        user=SimpleNamespace(
            username=u["username"],
            displayname=u["display_name"],
            followersCount=u["followers_count"],
        ),
    )

之后 for tweet in map(as_snscrape, search(query)): 就能让旧的循环体原封不动地继续工作。Sorsa API 里的 ID 是字符串,所以适配器按 snscrape 当年的样子把它们转回整数。

各个库如何访问 X,以及什么挡住了它 库 如何读取 X 什么挡住了它 snscrape Twint 未登录的访客令牌, 即 X 给匿名访客的通行证 2023 年 6 月 30 日关闭: 搜索需要登录 ntscraper 公开的 Nitter 实例, 转发 X 页面 Nitter 于 2026 年 10 月 9 日 归档 twikit, twifork twscrape, Scweet 发往 x.com 网页应用的 登录账号 cookie 账号被锁, x.com 每次改动都会失效 Sorsa API 一个 ApiKey 请求头, 返回 JSON,每页约 20 条推文 不需要 X 账号, 没有可锁的东西
未登录的路线都关闭了。已登录的路线在你的账号还在时能用;API 密钥则完全不带任何 X 账号。

#同样的任务要花多少钱

在 Sorsa API 上,搜索得到的推文每 1,000 条 $0.07 起,而官方 X API 每 1,000 条帖子 $5.00,还需要开发者账号、OAuth 和预付额度。这些库不收费;它们花的是 X 账号、代理,以及每次 X 改版其网页应用时耗掉的工时。

推文数

官方 X API

$5,000

通过搜索获取 100 万 条推文

每条帖子 $0.005

Sorsa API

$70 起

通过搜索获取 100 万 条推文

每 1,000 条 $0.07 起

官方 X API 的按量付费价格(在新标签页打开)每月读取 300 万条帖子后就停止;超过这个数只有 Enterprise 合同。按 ID 每 100 个一批查询推文,能把 Sorsa API 的价格降到每 1,000 条 $0.014,粉丝列表则是每页 200 个,每 1,000 个 $0.007 起。失败的请求从不计费。

#今天就在 Sorsa API 上运行你旧的 snscrape 查询

snscrape 和 Twint 已经没了,还能用的库需要 X 尚未锁定的 X 账号。想让 Twint、snscrape、twikit 或 twscrape 的任务在没有这种风险的情况下继续运行,就把它迁到 Sorsa API:一个密钥,沿用你现有的搜索查询,每次请求约 20 条推文,每 1,000 条 $0.07 起。粘贴上面的辅助函数,换掉一个调用,你的 100 次免费请求会返回约 2,000 条推文,用来对照旧脚本的输出。

#常见问题

2026 年 twikit 还在维护吗?

上游没有:twikit 的最新版本是 2025 年 2 月 7 日的 2.3.3,自 2026 年 3 月 18 日 X 改版后,每次调用都会失败并报“Couldn't get KEY_BYTE indices”(issue #408,至今未关闭)。2026 年 8 月 30 日发布的社区分叉 twifork 2.4.0 修复了这个故障,保留了 twikit 的导入方式,但只能配合从已登录 X 账号导出的 Cookie 使用。

没有 X 账号,twscrape 还能用吗?

不能。twscrape 在 2026 年能用,版本是 2026 年 8 月 25 日的 0.20.1,但它的 README 写明需要经过授权的 X 账号,通过含有 auth_token 和 ct0 的 Cookie 添加。它运行在一个账号池上,其中任何一个都可能被 X 锁定。

有能用于 Twitter 的 snscrape 分叉吗?

没有任何分叉能让它在 X 上复活。snscrape 是未登录读取 X 的,而自 2023 年 6 月 30 日起,X 只对已登录用户返回搜索和时间线,所以任何给 guest token 打补丁的分叉,结局仍是“blocked (404)”。维护者在 issue #270 里排除了登录,所以要修复,就得围绕已登录账号把这个库重写一遍。

我的 snscrape 或 Twint 搜索查询还能继续用吗?

能。Sorsa API 的搜索接受 X 自己的查询语法,所以带有 from:、since:、until:、lang:、min_faves: 和 filter: 的字符串,在 POST /search-tweets 的 query 字段里无需改动就能用。把 "order" 设为 "latest",就是 snscrape 返回的最新优先顺序;设为 "popular" 则对应“热门”标签,结果每页约 20 条,并附带一个 cursor。

获取 Twitter 数据,snscrape 的最佳替代方案是什么?

要像 snscrape 那样采集公开推文,又不用 X 账号,最好的替代方案是 Sorsa API:搜索操作符相同,搜索每次请求约 20 条推文,每 1,000 条 $0.07 起;按 ID 批量查询每次 100 条推文,每 1,000 条 $0.014 起;所有套餐都是每秒 20 次请求。它只返回公开数据,从不索要你的 X 登录信息或 Cookie,每个新账号都有 100 次免费请求。

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

更新内容
  • 首次发布。