编程 yt-dlp 报 403、只下到音轨、分片超时:从 TLS 指纹到 JS 运行时的分层排查

2026-10-28 00:04:53

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,按顺序确认三件事:

  1. --verbose 里实际发出去的 UA 是不是你预期的;
  2. 日志里有没有 PO token 相关的提示(有的话不是 cookie 能解决的);
  3. 站点是否要登录态:
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,只会多一层解析开销和一堆无关的报错。

复制全文 生成海报 下载工具 yt-dlp ffmpeg curl Shell

推荐文章

程序员茄子在线接单