snscrape、Twint、twikit 和 twscrape:X 上还有什么能用
snscrape 和 Twint 在 2023 年就不再适用于 X,而且不会恢复;twikit 的最新版本自 2026 年 3 月 18 日 X 改版后一直失效;twscrape 仍然能用,但只能运行在你提供的已登录 X 账号上。
简短回答: 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 上的情况,以及各个库失效时打印的错误。
| 库 | 最近发布 | 状态 | 需要 | 你会看到的错误 |
|---|---|---|---|---|
| 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 账号 | 账号变成只读 |
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_tokenCookie- 你会看到的错误
- 账号被锁
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。
#用一个 Sorsa API 请求替换库调用
对用过这些库的项目,用 Sorsa API,一款 Twitter(X)API 与爬虫:它用一个 ApiKey 请求头,以 JSON 返回同样的公开推文、用户资料和粉丝列表,无需 X 账号、Cookie 或代理;X 改动网页应用时,修复由我们负责,你的代码和响应结构都保持不变。搜索结果每 1,000 条 $0.07 起,粉丝每 1,000 个 $0.007 起,所有套餐(包括免费起步)都允许每秒 20 次请求。
四步就能迁完一个脚本:
-
获取密钥。注册后,在控制台复制 API 密钥。前 100 次请求免费,永不过期。
-
**添加一个辅助函数。**这些函数代替原来的库导入。每个列表接口返回一页和一个
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) -
**逐个替换调用。**选好你的库,以及你的脚本发出的调用;转换器会显示对应的请求。
你使用的库之前:snscrapescraper = sntwitter.TwitterSearchScraper( "python lang:en") for tweet in scraper.get_items(): print(tweet.rawContent)之后:Sorsa APIfor 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 接口。写入类调用和点赞没有对应的只读功能。
-
**检查第一页。**每个响应都把作者的完整资料放在每条推文里面,所以 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 API | twikit | twscrape |
|---|---|---|---|
| 搜索推文 | POST /search-tweets(在新标签页打开) | search_tweet | search |
| 某个用户的推文 | POST /user-tweets(在新标签页打开) | get_user_tweets | user_tweets |
| 一份用户资料 | GET /info(在新标签页打开) | get_user_by_screen_name | user_by_login |
| 粉丝 | GET /followers(在新标签页打开) | get_user_followers | followers |
| 关注列表 | GET /follows(在新标签页打开) | get_user_following | following |
| 一条推文 | POST /tweet-info(在新标签页打开) | get_tweet_by_id | tweet_details |
| 按 ID 查 100 条推文 | POST /tweet-info-bulk(在新标签页打开) | get_tweets_by_ids | 无 |
| 一条推文的回复 | POST /comments(在新标签页打开) | get_tweet_by_id | tweet_replies |
| 转发者 | POST /retweeters(在新标签页打开) | get_retweeters | retweeters |
| 搜索用户 | POST /search-users(在新标签页打开) | search_user | search_user |
| 列表推文 | GET /list-tweets(在新标签页打开) | get_list_tweets | list_timeline |
| 趋势 | GET /trends(在新标签页打开) | get_place_trends | trends |
| 账号“关于”数据 | GET /about(在新标签页打开) | 无 | user_about |
搜索推文
- Sorsa API
- POST /search-tweets(在新标签页打开)
- twikit
- search_tweet
- twscrape
- search
某个用户的推文
- Sorsa API
- POST /user-tweets(在新标签页打开)
- twikit
- get_user_tweets
- twscrape
- user_tweets
一份用户资料
- Sorsa API
- GET /info(在新标签页打开)
- twikit
- get_user_by_screen_name
- twscrape
- user_by_login
粉丝
- Sorsa API
- GET /followers(在新标签页打开)
- twikit
- get_user_followers
- twscrape
- followers
关注列表
- Sorsa API
- GET /follows(在新标签页打开)
- twikit
- get_user_following
- twscrape
- following
一条推文
- Sorsa API
- POST /tweet-info(在新标签页打开)
- twikit
- get_tweet_by_id
- twscrape
- tweet_details
按 ID 查 100 条推文
- Sorsa API
- POST /tweet-info-bulk(在新标签页打开)
- twikit
- get_tweets_by_ids
- twscrape
- 无
一条推文的回复
- Sorsa API
- POST /comments(在新标签页打开)
- twikit
- get_tweet_by_id
- twscrape
- tweet_replies
转发者
- Sorsa API
- POST /retweeters(在新标签页打开)
- twikit
- get_retweeters
- twscrape
- retweeters
搜索用户
- Sorsa API
- POST /search-users(在新标签页打开)
- twikit
- search_user
- twscrape
- search_user
列表推文
- Sorsa API
- GET /list-tweets(在新标签页打开)
- twikit
- get_list_tweets
- twscrape
- list_timeline
趋势
- Sorsa API
- GET /trends(在新标签页打开)
- twikit
- get_place_trends
- twscrape
- trends
账号“关于”数据
- Sorsa API
- GET /about(在新标签页打开)
- twikit
- 无
- twscrape
- user_about
snscrape 和 Twint 覆盖的任务更少,每一项也都映射到同样的接口:
| 任务 | Sorsa API | snscrape | Twint |
|---|---|---|---|
| 搜索推文 | POST /search-tweets | TwitterSearchScraper | run.Search |
| 话题标签 | POST /search-tweets | TwitterHashtagScraper | c.Search 加 #tag |
| 某个用户的推文 | POST /user-tweets | TwitterUserScraper | c.Username |
| 一份用户资料 | GET /info | TwitterUserScraper.entity | run.Lookup |
| 粉丝 | GET /followers | 无 | run.Followers |
| 关注列表 | GET /follows | 无 | run.Following |
| 一条推文 | POST /tweet-info | TwitterTweetScraper | 无 |
| 列表推文 | GET /list-tweets | TwitterListPostsScraper | 无 |
| 趋势 | GET /trends | TwitterTrendsScraper | 无 |
搜索推文
- 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 搜索,变成对辅助函数的一次调用:
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 调用,变成对辅助函数的两次调用:
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 API | twscrape | twikit | snscrape |
|---|---|---|---|---|
| 今天在 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、twscrape | twikit | Twint |
|---|---|---|---|
id(字符串) | id | id | id |
created_at(ISO 8601) | date | created_at | datetime |
full_text | rawContent | text | tweet |
user.username | user.username | user.screen_name | username |
user.display_name | user.displayname | user.name | name |
likes_count | likeCount | favorite_count | likes_count |
retweet_count | retweetCount | retweet_count | retweets_count |
reply_count | replyCount | reply_count | replies_count |
quote_count | quoteCount | quote_count | 无 |
view_count | viewCount | view_count | 无 |
conversation_id_str | conversationId | 无 | conversation_id |
quoted_status | quotedTweet | quote | 无 |
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 的名字来回应:
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 当年的样子把它们转回整数。
#同样的任务要花多少钱
在 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 次免费请求。
#我们如何核实
2026 年 11 月 2 日,我们阅读了 snscrape、Twint、twikit、twifork、twscrape、Scweet、ntscraper、tweety 和 Nitter 的 PyPI 发布历史和 GitHub 仓库状态,以及上面引用的各个 issue。同一天,我们从 GitHub 上各个库的源码里取了它们的方法名和属性名。这里的每个 Sorsa API 接口、参数和字段都与线上 API 参考一致;请求是照着它写的,我们没有把这些库的代码拿到 x.com 上运行过。
来源
- snscrape issue #996: All Twitter scrapes are failing(在新标签页打开)
- snscrape issue #270: Support for authentication(在新标签页打开)
- snscrape on PyPI(在新标签页打开)
- Twint repository (archived)(在新标签页打开)
- Twint issue #1433: Could not find the Guest token in HTML(在新标签页打开)
- twikit issue #408: ClientTransaction broken as of March 18, 2026(在新标签页打开)
- twikit on PyPI(在新标签页打开)
- twifork README(在新标签页打开)
- twscrape README(在新标签页打开)
- twscrape issue #337: user_by_id blocked by Cloudflare(在新标签页打开)
- Scweet on PyPI(在新标签页打开)
- ntscraper README(在新标签页打开)
- Nitter repository (archived)(在新标签页打开)
- X API pay-per-use pricing (docs.x.com)(在新标签页打开)
- Sorsa API reference, OpenAPI
- Search operators (Sorsa API docs)(在新标签页打开)