问答

怎么拿到带时间戳的 YouTube 字幕,导出成 JSON 或 SRT?

简短回答

YouTube 视频字幕接口会把每一行字幕作为一个分段返回,带 start 和 end(单位秒),另附全文,每个视频 $0.004。JSON 可以直接存,也可以用十几行 Python 写成 SRT;时间戳不另外收费。

做播客切片的剪辑想找出嘉宾提到某个产品的所有地方,每处配一个能直接跳到那一秒的链接。光有文字稿不够,还得知道每句话是什么时候说的。YouTube 视频字幕在同一次调用里就把时间一起返回了。

JSON 长这样

字幕在响应的 data.item 里:

{
  "video_id": "dQw4w9WgXcQ",
  "lang": "en",
  "text": "We're no strangers to love ...",
  "segments": [
    { "start": 18.64, "end": 21.88, "text": "We're no strangers to love" },
    { "start": 22.64, "end": 26.92, "text": "You know the rules and so do I" }
  ]
}

时间是从视频开头算起的秒数。有些库给的是 duration,换算一下就是 end - start。

分段转成 SRT

import os, requests

body = requests.get(
    "https://api.okdata.online/v1/youtube/videos/transcript/get",
    headers={"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"},
    params={"id": "dQw4w9WgXcQ", "lang": "en"}, timeout=60,
).json()
segments = body["data"]["item"]["segments"]

def srt_time(sec):
    ms = int(round(sec * 1000))
    return f"{ms // 3_600_000:02}:{ms // 60_000 % 60:02}:{ms // 1000 % 60:02},{ms % 1000:03}"

with open("dQw4w9WgXcQ.srt", "w", encoding="utf-8") as f:
    for n, s in enumerate(segments, 1):
        f.write(f"{n}\n{srt_time(s['start'])} --> {srt_time(s['end'])}\n{s['text']}\n\n")

要 WebVTT 的话,文件开头写 WEBVTT,毫秒前面的逗号换成点。

生成跳到某一秒的链接

https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=18s 会从第 18 秒开始播放。把 start 向下取整,AI 从字幕里摘出的每一句引用后面都能挂一个可点的出处,摘要对不对,点一下就知道。

价格

任务 费用
一个视频,文字加时间 $0.004
100 期节目的存档 $0.40
1,000 个视频 $4.00

每份字幕都自带时间。没有字幕的视频返回 not_found,不扣费。

交付文件前要知道的事

  • 自动字幕的分段经常重叠,上一行还没结束下一行就开始了。播放器报错的话,把每段的 end 截到下一段的 start。
  • 分段是按 YouTube 切字幕的方式来的,都很短,和句子边界对不上。引用整句话之前,先把相邻分段拼起来。
  • 接口收的是 11 位视频 ID,不收链接。
  • 不返回样式、位置和说话人,只有文字和时间。

其他拿带时间字幕的办法

  • 在你的网络上 yt-dlp 没被拦的话,--write-subs --convert-subs srt 能直接写出文件。
  • 自己频道的视频,官方 Data API 可以通过 tfmt 下载 SRT 格式的字幕。
  • 视频没有字幕时,对你有权使用的音频跑 Whisper,也能得到带时间戳的文字。

整个频道批量处理的做法和费用见视频转文字方案。

更新于