问答
yt-dlp 提示要登录确认不是机器人,不用 Cookie 怎么拿 YouTube 字幕?
简短回答
只要文字和数据的话,干脆别下载:YouTube 视频字幕接口返回带时间戳的字幕,$0.004;YouTube 视频详情返回标题、简介、标签、播放和点赞,$0.004。不用 Cookie,不用登录账号,请求也不从你服务器的 IP 发出。
一个每晚跑的任务,在 VPS 上执行 yt-dlp --write-auto-subs --skip-download,给研究语料收字幕。某天早上,所有视频都报 Sign in to confirm you're not a bot。常见的解法是加 --cookies-from-browser,可 yt-dlp 的维护者自己都讨论过,要提醒用户这些 Cookie 对应的账号可能被封。为了拿字幕把一个真实的 Google 账号押上去,不划算。
大多数字幕任务其实用不到视频文件,要的只是文字和几项视频信息,这两样都不用下载就能拿到。
yt-dlp 的输出分别用什么替代
| yt-dlp 给的 | 换成 | 价格 |
|---|---|---|
.vtt / .srt 字幕 |
YouTube 视频字幕 | $0.004 |
title、description、tags、view_count、like_count、duration |
YouTube 视频详情 | $0.004 |
| 两样都要,100 个视频 | 200 次调用 | {{cost:youtube.videos.get100+youtube.videos.transcript.get100}} |
视频详情里,标签放在 hashtags 字段。加 view=full 能拿到 ext.duration_ms 时长。
请求发到 okdata,你的 VPS 不再直接访问 YouTube,所以你这边不会再碰到人机验证,也不用维护 Cookie 和代理。上游偶尔出问题时返回 upstream_failed,不扣费,隔一会儿重试即可;24 小时内带同一个 Idempotency-Key 重试,也不会重复收费。
照 yt-dlp 的样子写出 .vtt 文件
import os, requests
API = "https://api.okdata.online/v1"
H = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}
def ts(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}"
def save_vtt(video_id, lang="en"):
body = requests.get(f"{API}/youtube/videos/transcript/get", headers=H,
params={"id": video_id, "lang": lang}, timeout=60).json()
if body["code"] != "ok":
print(video_id, body["code"]) # not_found 表示没有字幕,不扣费
return
t = body["data"]["item"]
cues = [f"{ts(s['start'])} --> {ts(s['end'])}\n{s['text']}" for s in t["segments"]]
with open(f"{video_id}.{t['lang']}.vtt", "w", encoding="utf-8") as f:
f.write("WEBVTT\n\n" + "\n\n".join(cues) + "\n")
save_vtt("dQw4w9WgXcQ")
放弃了什么
- 拿不到媒体文件。任务要的是视频或音频本身,这条路替代不了 yt-dlp。
- 每次调用返回一条字幕轨,视频有你指定的
lang就优先给那种语言,以返回的lang为准。 - 不区分作者上传的字幕和自动字幕。
- 没有字幕的视频返回
not_found,不扣费;这里不做语音转文字。 - 这个接口只收
id,不收链接。
哪些时候还是 yt-dlp 合适
- 必须要媒体文件。换到家里的网络上跑 yt-dlp,或者接受 Cookie 的风险,用一个小号。
- 量小、偶尔跑,从住宅 IP 发请求一般能通过验证。
- 自己频道的字幕,从 YouTube Studio 或官方 Data API 拿就行,视频本来就是你的。
整批视频的做法和费用见视频转文字方案。
更新于