Twitter 视频 API:获取任意 X 视频的 MP4 地址
Twitter 视频的 MP4 地址在帖子的媒体数据里:X 会把每个上传的视频编码成最多五种 MP4 规格,从 270p 到 1080p 甚至更高,并列出每个文件的地址和码率。
简短回答: 取码率最高的那个 MP4;GIF 就是一个无声的 MP4。官方 X API 只有在加上 media.fields=variants 时才会列出各种规格,自 2026 年 11 月 22 日起,每 1,000 条视频帖子 $10.00。Sorsa API 通过 POST /tweet-info-bulk 返回每条帖子的视频链接,每次请求 100 条帖子,每 1,000 条 $0.014 起,100 次免费请求可以覆盖前 1 万条。
- 接口
POST /tweet-info-bulk- 每页条数
- 每次请求 100 条帖子
- 价格
- 每 1,000 条 $0.014 起
#X 如何存储视频:规格与码率
X 从不提供作者上传的原文件。它会把每个视频重新编码成一组 MP4 文件,每种尺寸一个,外加一个 HLS 播放列表(一个 .m3u8 索引,视频播放器用它在播放过程中切换尺寸)。每个 MP4 都是带声音的完整文件,所以任何一个都可以单独下载和播放。想保存单条帖子的话,免费的 Twitter 视频下载器粘贴链接就能保存文件;本指南讲的是如何用代码拿到这些文件。
2026 年 11 月 2 日,我们读取了 2017 年到 2026 年 23 条公开帖子的规格列表,并实测了 X 为它们提供的 72 个 MP4 文件。X 为每个文件列出的码率是上限,真实文件的码率只有它的三分之一到五分之一:
| 规格 | 画面尺寸,像素 | X 列出的码率 | 真实平均码率 |
|---|---|---|---|
| 270p | 480 × 270 | 256 kbps | 约 91 kbps |
| 360p | 640 × 360 | 832 kbps | 约 233 kbps |
| 720p | 1280 × 720 | 2,176 kbps | 约 626 kbps |
| 1080p | 1920 × 1080 | 10.4 Mbps | 约 2,172 kbps |
270p
- 画面尺寸,像素
- 480 × 270
- X 列出的码率
- 256 kbps
- 真实平均码率
- 约 91 kbps
360p
- 画面尺寸,像素
- 640 × 360
- X 列出的码率
- 832 kbps
- 真实平均码率
- 约 233 kbps
720p
- 画面尺寸,像素
- 1280 × 720
- X 列出的码率
- 2,176 kbps
- 真实平均码率
- 约 626 kbps
1080p
- 画面尺寸,像素
- 1920 × 1080
- X 列出的码率
- 10.4 Mbps
- 真实平均码率
- 约 2,172 kbps
实测显示:
- 码率最高的就是最好的文件。 把 MP4 条目按码率排序,取最上面的那个。类型为
application/x-mpegURL的播放列表条目没有码率,它是索引,不是文件。 - 尺寸取决于画面形状。 竖屏视频是 320 × 568 到 1080 × 1920,方形视频是 320 × 320 到 1080 × 1080,还有一个 1936 × 1548 的上传多出了第五个文件,码率 25.1 Mbps。
- 不是每个 1080p 的上传都有 1080p 文件。 在 2025 年和 2026 年 7 个 1920 × 1080 的上传里,有两个只到 720p,2022 年以前的大多数帖子最高也只有 720p。
- 播放列表把声音和画面分开。 其中的视频流是无声的;音频是单独的轨道,码率为 32、64 和 128 kbps,有些视频还带字幕。
GIF 更简单:X 只保留一个无声、循环播放的 MP4,尺寸就是 GIF 本身的尺寸,没有其他规格,也没有播放列表。
#用 Sorsa API 获取视频的 MP4 地址
Sorsa API 是一款 Twitter(X)API 与爬虫,返回的每条帖子都附带它的媒体:每个视频、GIF 和照片,都是帖子 entities 列表中的一项,带有 type、直接的 link 和一张 preview 图片。请求头里的一个 API 密钥,取代了官方 X API 要求的开发者账号和 OAuth。
-
获取密钥。 注册后,在控制台复制 API 密钥。前 100 次请求免费,无需绑卡。
-
发送帖子链接。
POST /tweet-info(在新标签页打开) 在tweet_link里接受帖子 URL 或纯 ID。终端 curl -X POST "https://api.sorsa.io/v3/tweet-info" \ -H "ApiKey: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"tweet_link": "https://x.com/northfield_video_lab/status/1984519203377641472"}'响应200 OK { "id": "1984519203377641472", "created_at": "2026-10-31T16:04:11Z", "full_text": "First ride on the new gravel loop.", "entities": [ { "type": "video", "link": "https://video.twimg.com/amplify_video/1984519110025023488/vid/avc1/480x270/Qm3vTb8xLwK2pRfA.mp4?tag=21", "preview": "https://pbs.twimg.com/amplify_video_thumb/1984519110025023488/img/Hx2LkP9aQwErT0bn.jpg" } ], "user": { "username": "northfield_video_lab", "display_name": "Northfield Video Lab", "media_count": 214 } } -
读取视频条目。 保留
type为video且link位于 video.twimg.com 的 entity。链接里带/tweet_video/路径的是 GIF。 -
下载文件。 MP4 是 X 服务器上的普通 HTTPS 文件:不需要密钥,不需要 Cookie,也不计请求次数。
import requests API = "https://api.sorsa.io/v3/tweet-info" HEADERS = {"ApiKey": "YOUR_API_KEY"} def video_links(post): r = requests.post(API, headers=HEADERS, json={"tweet_link": post}, timeout=60) r.raise_for_status() # 403: no key, or no requests left tweet = r.json() for e in tweet.get("entities") or []: if e.get("type") == "video" and "video.twimg.com" in e["link"]: yield tweet["id"], e["link"] links = video_links("1984519203377641472") for n, (post_id, link) in enumerate(links, 1): with open(f"{post_id}_{n}.mp4", "wb") as f: f.write(requests.get(link, timeout=120).content)
这个 link 是一个带声音、哪里都能播放的 MP4。2026 年 11 月 2 日,我们用基于 Sorsa API 的免费下载器处理了两个视频,两个链接都是 X 的 270p 规格。对其中 82 秒的那个来说,文件只有 1.1 MB:用于预览、转录、抽帧和大规模存档已经足够轻。GIF 的链接是它唯一的文件,所以拿到的就是完整文件。
preview 还可以充当全尺寸画面:给它加上 ?format=jpg&name=orig(先去掉 .jpg),X 就会按上传的原始尺寸返回这一帧,我们的一个测试帖子是 1936 × 1548 像素。照片以 type 为 photo 出现在同一个列表里;如何获取每张原始尺寸的照片,无论是一条帖子还是整个账号,见推特图片抓取工具指南。
要处理一批帖子,在 tweet_links 里向 POST /tweet-info-bulk(在新标签页打开) 发送最多 100 个链接或 ID。响应是 {"tweets": [...]},每条帖子都带同样的 entities,整批只算一次请求:每 1,000 条帖子 $0.014 起。
#下载账号或搜索结果里的所有视频
搜索会帮你找出带视频的帖子。X 的搜索运算符 filter:native_video 保留带有上传到 X 的视频的帖子,card_name:animated_gif 则保留 GIF。POST /search-tweets(在新标签页打开) 每次请求返回约 20 条匹配的帖子,搜索可回溯到 2006 年。
| 任务 | 查询 |
|---|---|
| 某个账号的所有视频 | from:northfield_video_lab filter:native_video |
| 某个账号的所有 GIF | from:northfield_video_lab card_name:animated_gif |
| 一个月内某个话题的视频 | "gravel racing" filter:native_video since:2026-10-01 until:2026-11-01 |
| 只要热门视频 | #bikepacking filter:native_video min_faves:1000 |
| 视频和 YouTube 链接 | trail build filter:videos |
某个账号的所有视频
- 查询
from:northfield_video_lab filter:native_video
某个账号的所有 GIF
- 查询
from:northfield_video_lab card_name:animated_gif
一个月内某个话题的视频
- 查询
"gravel racing" filter:native_video since:2026-10-01 until:2026-11-01
只要热门视频
- 查询
#bikepacking filter:native_video min_faves:1000
视频和 YouTube 链接
- 查询
trail build filter:videos
所有运算符及示例,见 Twitter 搜索运算符指南。下面的脚本会从第一页到最后一页跑完一条查询。
-
保存脚本。 它用
next_cursor(标记下一页从哪里开始的令牌)给搜索翻页,直到 cursor 返回为空。它把每条帖子的视频和 GIF 写入<帖子 ID>_<n>.mp4,并在videos.csv中记录每个文件。x_videos.py import csv import os import subprocess import sys import time import requests API = "https://api.sorsa.io/v3/search-tweets" HEADERS = {"ApiKey": "YOUR_API_KEY"} def search(body): while True: r = requests.post(API, headers=HEADERS, json=body, timeout=60) if r.status_code == 429: # over 20 requests a second: wait time.sleep(1) continue r.raise_for_status() # 403: no key, or no requests left return r.json() def videos(tweet): """(kind, link) for every video and GIF in a post.""" for e in tweet.get("entities") or []: link = e.get("link") or "" if e.get("type") == "video" and "video.twimg.com" in link: yield ("gif" if "/tweet_video/" in link else "video"), link def save(link, path): with requests.get(link, stream=True, timeout=120) as r: r.raise_for_status() with open(path, "wb") as f: for chunk in r.iter_content(1 << 16): f.write(chunk) def save_hd(post_url, n, path): """The post's highest-bitrate MP4 through yt-dlp; False if yt-dlp fails.""" cmd = ["yt-dlp", "-f", "best[protocol=https]", "--playlist-items", str(n), "-o", path, post_url] done = subprocess.run(cmd, capture_output=True).returncode == 0 return done and os.path.exists(path) def run(query, folder, hd=False): os.makedirs(folder, exist_ok=True) state = os.path.join(folder, "cursor.txt") body = {"query": query, "order": "latest"} if os.path.exists(state): # resume a stopped run body["next_cursor"] = open(state).read().strip() log_path = os.path.join(folder, "videos.csv") with open(log_path, "a", newline="", encoding="utf-8") as f: log = csv.writer(f) while True: page = search(body) for t in page.get("tweets", []): for n, (kind, link) in enumerate(videos(t), 1): path = os.path.join(folder, f"{t['id']}_{n}.mp4") if os.path.exists(path): continue url = f"https://x.com/{t['user']['username']}/status/{t['id']}" if not (hd and kind == "video" and save_hd(url, n, path)): save(link, path) log.writerow([t["id"], t["created_at"], kind, os.path.getsize(path), path]) cursor = page.get("next_cursor") if not cursor: break body["next_cursor"] = cursor with open(state, "w") as s: s.write(cursor) if os.path.exists(state): os.remove(state) if __name__ == "__main__": run(sys.argv[1], sys.argv[2], hd="--hd" in sys.argv[3:]) -
带上查询和文件夹运行。
python x_videos.py "from:northfield_video_lab filter:native_video" northfield会把这个账号的视频保存到文件夹northfield。返回 403 表示密钥缺失或请求次数已用完;429 表示一秒内请求超过 20 次,脚本会等一秒再重试。 -
随时可以再次运行。 磁盘上已有的文件会被跳过,cursor 在每页之后保存。中断的运行可以接着上次的位置继续,重新运行也只会增加新视频。
整个账号的视频只需很少的请求:按每页约 20 条帖子,一个有 300 个视频的账号大约是 15 次请求,因为搜索只返回带视频的帖子。想把文本和其他所有帖子字段导入电子表格,见如何下载某个用户的全部推文。
#获取帖子的 720p 或 1080p 文件
要获取帖子的 720p 或 1080p 文件,把帖子链接交给开源命令行下载工具 yt-dlp,它无需 X 登录即可读取公开帖子。下面的格式筛选会挑出码率最高的 MP4:
yt-dlp -f "best[protocol=https]" -o "%(id)s.%(ext)s" "https://x.com/northfield_video_lab/status/1984519203377641472"
在上面的脚本里加上 --hd,它就会对每个视频都这样处理,yt-dlp 失败时则退回使用 API 返回的链接。在我们 82 秒的测试视频上,yt-dlp 2026.10.26 选中了 1920 × 1080 的文件。用 -F 运行时,它的格式表把这个文件列为约 100 MiB,因为格式表是用标出的码率乘以时长估算的;实际下载的文件只有 22.2 MB。yt-dlp 每次只从你自己的 IP 地址获取一条帖子,所以批量查找交给 Sorsa API,yt-dlp 只负责下载你需要的高清文件。
须知
官方 X API 可以在一次响应里返回完整的规格列表,但前提是你主动请求。在帖子查询中加上
expansions=attachments.media_keys和media.fields=variants,每个视频就会出现在includes.media中,并带有一个由bit_rate、content_type和url组成的variants数组。这需要开发者账号和 OAuth,而且从 2026 年 11 月 22 日起,响应中的每个媒体对象在 $0.005 的帖子读取费之外,还要另收 $0.005。
#API 里的 Twitter GIF
X 上发布的 GIF 会以 MP4 的形式返回,因为 X 在发布时会把每个 GIF 转成一个简短、无声、循环播放的视频。它的链接位于 video.twimg.com/tweet_video/,X 不保留其他尺寸,这一个文件就是现存的最佳副本。在 X 自己的数据里,它的类型是 animated_gif,码率为 0;在 Sorsa API 的 entities 里,它是一个 video,链接带有 /tweet_video/ 路径。
要把它转回 .gif 文件,用 ffmpeg 加一遍调色板处理,这样颜色会比较干净:
ffmpeg -i 1211797914437259264_1.mp4 \
-vf "fps=15,split[a][b];[a]palettegen[p];[b][p]paletteuse" \
-loop 0 1211797914437259264.gif
文件会大得多:在我们的测试里,一个 83 KB 的 MP4 变成了 1.76 MB 的 GIF,像素同为 498 × 272,是原来的 21 倍。存储和播放器用 MP4 即可,只有页面或聊天需要时才生成 GIF。只想下载单个 GIF、不写代码的话,免费的 Twitter GIF 下载器根据帖子链接就能保存。
#成本:请求次数和存储空间
在 Sorsa API 上,一条帖子不管带什么媒体,价格都一样。按 ID 查询的帖子每 1,000 条 $0.014 起,每次请求 100 条;通过搜索找到的帖子每 1,000 条 $0.07 起,每次请求约 20 条。视频文件从 X 的服务器下载,不消耗请求次数。在官方 X API 上,每个视频都通过媒体扩展返回,自 2026 年 11 月 22 日起,X 对扩展对象按标准费率计费(在新标签页打开)。一条视频帖子就是帖子 $0.005 加上它的媒体 $0.005:每 1,000 条 $10.00。
| 获取视频链接的方式 | 需要什么 | 每 1,000 条视频帖子的成本 |
|---|---|---|
| Sorsa API,按 ID 查询帖子 | 一个 API 密钥 | $0.014 起 |
| Sorsa API,搜索 | 一个 API 密钥 | $0.07 起 |
| 官方 X API | 开发者账号和 OAuth | 自 2026 年 11 月 22 日起 $10.00 |
Sorsa API,按 ID 查询帖子
- 需要什么
- 一个 API 密钥
- 每 1,000 条视频帖子的成本
- $0.014 起
Sorsa API,搜索
- 需要什么
- 一个 API 密钥
- 每 1,000 条视频帖子的成本
- $0.07 起
官方 X API
- 需要什么
- 开发者账号和 OAuth
- 每 1,000 条视频帖子的成本
- 自 2026 年 11 月 22 日起 $10.00
官方 X API
$10,000
100 万 条视频帖子
每条视频帖子 $0.010,自 11 月 22 日起
Sorsa API
$14 起
100 万 条视频帖子
每 1,000 条 $0.014 起
便宜 714 倍
官方 X API 的按量付费价格(在新标签页打开)同样在每个计费周期读取 300 万条帖子后封顶,超过之后 X 只出售 Enterprise 合同。Sorsa API 所有套餐都是每秒 20 次请求,所以每批 100 条帖子,每秒能查询 2,000 条视频帖子,失败的请求从不收费。
对视频存档来说,存储才是更大的开销,而且它取决于规格,远比取决于数量更甚。按我们实测的真实平均码率,1,000 个三十秒的视频,270p 约占 0.3 GB,720p 约 2.3 GB,1080p 约 8.1 GB。设置你自己的时长和数量:
| 转码档位 | 每个视频 | 全部视频 | 上限 |
|---|---|---|---|
| 270p | 0.34 MB | 341 MB | 0.96 MB |
| 360p | 0.87 MB | 874 MB | 3.1 MB |
| 720p | 2.3 MB | 2.3 GB | 8.2 MB |
| 1080p | 8.1 MB | 8.1 GB | 38.9 MB |
每个视频:各档位的实测码率中位数(91、233、626 和 2,172 kbps)。上限:X 公布的码率(256、832 和 2,176 kbps,以及 10.4 Mbps)乘以时长。
每个视频的大小来自 2026 年 11 月 2 日在 X 服务器上测得的 63 个 MP4 文件的真实平均码率;上限使用 X 公布的码率。
#开始用代码拉取 X 视频
要用代码获取 X 视频和 GIF 的 MP4 地址,用 Sorsa API:一次请求最多返回 100 条帖子及每个视频的链接,每 1,000 条 $0.014 起。搜索能找到某个账号或话题回溯到 2006 年的每个视频,而且完全不会牵涉你的 X 账号。复制脚本,填上你的密钥,100 次免费请求就能返回你前 1 万条视频帖子的链接。
#常见问题
官方 X API 能返回 Twitter 视频的 URL 吗?
能。在帖子查询或搜索里加上 expansions=attachments.media_keys 和 media.fields=variants,includes.media 中的每个视频就会列出它的 MP4 规格,附带 bit_rate 和 url;取码率最高的那个。缺少这两个参数的话,只能拿到一张预览图。它需要开发者账号和 OAuth,而且自 2026 年 11 月 22 日起,每个媒体对象会在 $0.005 的帖子读取费之外再加 $0.005。
获取 Twitter 视频 URL 该用哪个 API?
用 Sorsa API。POST /tweet-info-bulk 每次请求最多返回 100 条帖子,附带每个视频的 MP4 链接和预览图,每 1,000 条帖子 $0.014 起。官方 X API 自 2026 年 11 月 22 日起,每 1,000 条视频帖子收费 $10.00。Sorsa API 只需一个 API 密钥,不用开发者账号和 OAuth,能通过搜索找到回溯到 2006 年的视频,所有套餐都是每秒 20 次请求。
为什么我下载的 Twitter 视频看起来很模糊?
很可能你保存的是较小的规格之一。X 把每个视频保存为最多五个 MP4 文件,从 270p 到 1080p 甚至更高,有些工具和 API 会交出第一个或最轻的那个。要选列表中码率最高的 MP4。如果最好的文件仍然是 720p,说明这次上传没有生成 1080p 规格:我们核对的 2025 年和 2026 年的 1080p 上传里,7 个中有 2 个只到 720p。
能下载私密账号或已删除帖子里的视频吗?
不能。受保护账号的帖子只有它批准的粉丝才能看到,所以没有任何 API 能返回其中的视频,Sorsa API 也不例外,而这类请求从不收费。已删除的帖子会从 X 的搜索和查询中消失,所以也没有 API 能列出它们;只有删除前保存的副本才留得住视频。
下载 X 上的视频合法吗?
合法。为研究、内容审核或存档而保存公开视频,是合法且常见的做法。版权仍然属于每个视频的制作者,所以在发布或转售这些文件之前,要先征得所有者的许可。Sorsa API 通过自己的 API 读取公开帖子,所以你的 X 账号不会参与其中。
#我们如何核实
2026 年 11 月 2 日,我们读取了 X 为 23 条公开视频和 GIF 帖子(时间跨度 2017 年到 2026 年)公布的规格列表,并实测了其中 75 个 MP4 文件里 video.twimg.com 实际提供的 72 个。对其中一个视频,我们还读取了它的 HLS 播放列表,并在未登录状态下用 yt-dlp 2026.10.26 列出了它的全部格式。我们用基于 Sorsa API 的免费下载器处理了其中三条帖子,查看它返回的链接。脚本是对着一个提供这些真实链接的 API 替身运行的,ffmpeg 那一行则在一个真实的 GIF 文件上运行过。接口和字段取自在线 Sorsa API 参考文档;X 的媒体字段和价格取自当天阅读的 docs.x.com 和 X 在 2026 年 10 月 23 日的通知。