yt-dlp 抓不到视频时:403、只有音轨、分片超时的分层排查
项目仓库:yt-dlp/yt-dlp(Unlicense,Python,更新很勤);命令行选项的完整说明在 wiki;需要自己编 ffmpeg 时用 yt-dlp/FFmpeg-Builds。
yt-dlp 报错信息往往只给一个笼统的结果,真正的原因分层在 TLS、JS 运行时、外部二进制、下载器分工和限速策略上。下面按失败形态拆,每种给出可复制的命令。
0. 先把失败归到四类
HTTP 403/Unable to download webpage:请求层就被挡了,多半和 TLS 指纹、UA、cookie 有关。- 只下到音轨或只下到视频,没有合流:ffmpeg 缺失或不可执行。
- 分片大量超时、速度长期低位:被限速或并发没开。
- 能取到页面信息但拿不到直链:缺 JS 运行时,或站点要 PO token。
先看 --verbose 的输出再动手,别凭猜测装包。
1. 403 与 TLS 指纹
一部分站点不看 UA,直接看 TLS 握手的指纹。解法是 impersonation:curl_cffi 是 curl-impersonate 的 Python 绑定(MIT),装带 extra 的版本:
pip install "yt-dlp[default,curl-cffi]"
注意发行版的差异:zipimport 版 yt-dlp 和 32 位 Windows 的 yt-dlp_x86 默认不包含 curl_cffi;.exe、yt-dlp_linux、yt-dlp_macos 这些构建里是带着的。也就是说,用 yt-dlp_x86.exe 在 32 位环境里排查 403,很可能怎么调都复现不出别人成功的结果。
装完仍然 403,按顺序确认三件事:
--verbose里实际发出去的 UA 是不是你预期的;- 日志里有没有 PO token 相关的提示(有的话不是 cookie 能解决的);
- 站点是否要登录态:
yt-dlp --cookies-from-browser chrome --verbose URL
Linux 上读 Chromium 系的 cookie 可能涉及 keyring 解密,解密失败时日志会明确报出来,不会静默降级。
2. YouTube 完整支持需要 JS 运行时
较近的版本把 YouTube 的签名与 nsig 处理挪到了 yt-dlp-ejs(Unlicense,内含 MIT/ISC 组件),它需要一个 JS 引擎来执行。推荐 deno,node.js / bun / QuickJS 也可以。缺这一环的表现不是硬报错,而是部分格式拿不到、或者只剩低清晰度——很容易被误判成"站点限制"。
顺带一句:ffmpeg 要的是二进制,不是 pip 上那个同名 Python 包。装错包时 ffmpeg -version 可能能跑,但 yt-dlp 调用的是另一套逻辑,症状见下一节。
3. 合并与切片
ffmpeg + ffprobe 属于 strong requirement,不是可选项。DASH 音视频分离的站点必须靠它合流;切片也依赖它:
yt-dlp -f "bv*+ba/b" URL
yt-dlp --download-sections "*10:15-inf" URL
yt-dlp --download-sections "intro" URL
--download-sections 在没有 ffmpeg 时直接不可用,所以"只下到一条轨"和"切不了段"经常是同一个根因。
分片并发和外部下载器是两件事,别混:
-N/--concurrent-fragments控制分片并发,默认是 1;--downloader aria2c只接管 http/ftp,dash/m3u8 的分片不走它。
yt-dlp --downloader aria2c --downloader-args "aria2c:-x 16 -k 1M" -N 4 URL
yt-dlp --downloader "dash,m3u8:native" URL
第二条是等价写法:只为 http/ftp 指定外部下载器,dash/m3u8 保持 native。想同时提速,就把 -N 调大,而不是指望 aria2c 去并发 m3u8 分片。
4. 重试与限速
默认值先记住:-R / --retries 为 10,--fragment-retries 为 10,--file-access-retries 为 3,三者都可以设成 infinite。
退避用 --retry-sleep [TYPE:]EXPR,EXPR 支持纯数字、linear=START[:END[:STEP]]、exp=START[:END[:BASE]],可以按类型给多次:
yt-dlp --retry-sleep linear=1::2 --retry-sleep fragment:exp=1:20 URL
限速有两个方向,容易搞反:
-r/--limit-rate是主动限速;--throttled-rate是反向阈值,低于它就判定自己被限速,会重新提取视频数据,默认阈值约 100K。
yt-dlp --throttled-rate 100K URL
相关的小开关:--buffer-size 默认 1024(字节),--resize-buffer 默认开启;--http-chunk-size 是实验性的,用于绕开按 chunk 计费的限速策略,非必要不开。
5. 断点与重复下载
长任务重跑最怕从头再来。用归档文件记录已下载的 id:
yt-dlp --download-archive archive.txt \
-o "%(uploader)s/%(title)s [%(id)s].%(ext)s" URL
模板里带上 %(id)s,归档和文件名才对得上。列表类任务可以加 --lazy-playlist 边解析边下,--playlist-random 打乱顺序;--no-... 那批开关大多是恢复默认行为,不用特意写。直播默认开 --hls-use-mpegts,中断后文件损坏的概率更低。
6. 什么时候不该用它
yt-dlp 的定位是"解析站点 → 拿直链 → 交给下载器"。纯 HTTP 文件用 curl / aria2;整站镜像用 wget --mirror;一批已知 URL 用 aria2c -i urllist.txt。把这些场景塞给 yt-dlp,只会多一层解析开销和一堆无关的报错。