跳到正文

Twitter 视频 API:获取任意 X 视频的 MP4 地址

Twitter 视频的 MP4 地址在帖子的媒体数据里:X 会把每个上传的视频编码成最多五种 MP4 规格,从 270p 到 1080p 甚至更高,并列出每个文件的地址和码率。

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

简短回答: 取码率最高的那个 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 列出的码率真实平均码率
270p480 × 270256 kbps约 91 kbps
360p640 × 360832 kbps约 233 kbps
720p1280 × 7202,176 kbps约 626 kbps
1080p1920 × 108010.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
The four MP4 files X served for one 82-second 1080p video, real size against listed bitrate 一段 82 秒的视频:X 提供的四个 MP4 文件 实际文件 预测 270p 列出 256 kbps 1.1 MB 2.6 MB 360p 列出 832 kbps 2.9 MB 8.5 MB 720p 列出 2,176 kbps 7.3 MB 22.2 MB 1080p 列出 10.4 Mbps 22.2 MB 105.7 MB 实心条:X 提供的文件。虚线框,预测:列出的码率 × 82 秒。 在 video.twimg.com 实测,2026 年 11 月 2 日。
一个 82 秒视频的 1080p 文件重 22.2 MB,大约是按其列出码率预测大小的五分之一。

实测显示:

  • 码率最高的就是最好的文件。 把 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。

  1. 获取密钥。 注册后,在控制台复制 API 密钥。前 100 次请求免费,无需绑卡。

  2. 发送帖子链接。 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
      }
    }
    
  3. 读取视频条目。 保留 type 为 video 且 link 位于 video.twimg.com 的 entity。链接里带 /tweet_video/ 路径的是 GIF。

  4. 下载文件。 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
某个账号的所有 GIFfrom: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 搜索运算符指南。下面的脚本会从第一页到最后一页跑完一条查询。

Downloading every video of an X account with Sorsa API 搜索推文 /search-tweets filter:native_video 每页约 20 条推文 读取 entities type: "video" 链接:MP4,有声音 链接中含 /tweet_video/ 就是 GIF 保存每个文件 <post id>_1.mp4 直接来自 video.twimg.com 记录 videos.csv id、日期、类型、 字节数、文件 next_cursor,直到 返回为空
一页搜索结果是一次请求;视频文件直接来自 X 的服务器,不消耗请求次数。
  1. 保存脚本。 它用 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:])
    
  2. 带上查询和文件夹运行。 python x_videos.py "from:northfield_video_lab filter:native_video" northfield 会把这个账号的视频保存到文件夹 northfield。返回 403 表示密钥缺失或请求次数已用完;429 表示一秒内请求超过 20 次,脚本会等一秒再重试。

  3. 随时可以再次运行。 磁盘上已有的文件会被跳过,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。设置你自己的时长和数量:

秒
个视频
转码档位每个视频全部视频上限
270p0.34 MB341 MB0.96 MB
360p0.87 MB874 MB3.1 MB
720p2.3 MB2.3 GB8.2 MB
1080p8.1 MB8.1 GB38.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 日的通知。

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

更新内容
  • 全文重写:实测 72 个 MP4 文件的规格和真实码率,用 Sorsa API 获取单条帖子、一份列表和整个账号视频的经过测试的脚本,作为 MP4 的 GIF,存储空间计算器,以及包含 X 自 11 月 22 日起媒体计费的成本。
  • 首次发布。