简介:一款面向流媒体爱好者的m3u8在线下载与提取工具,基于Python编写,用户只需提供M3U8链接,工具即可自动拉取全部TS分片,并借助ffmpeg合并为完整视频文件。工具采用多线程机制提升下载速度,适合需要离线观看高清网络视频的用户,也便于开发者学习流媒体协议与命令行工具的实现思路。压缩包共47个文件,仅1.68MB,以js和html前端交互脚本为主,配以css样式、png图片、txt说明文档,并包含php、rar等其他类型,涵盖网页端工具、用户脚本、播放器组件与基础配置,部署轻量、结构清晰,打开即可选用。已有5939人学习/下载,热度可观。内含可直接安装的用户脚本、HLS播放器组件及AES解密相关脚本,可抓取加密流并完成分片下载与本地合并,亦可作为二次开发参考,帮助理解M3U8协议、多线程并发、AES解密和视频合并的完整流程。
1. m3u8下载工具:解决的不只是视频保存,还有重定向与加密两道坎
当你在浏览器里点开某课程网站的视频,发现它返回的不是一个MP4地址,而是一个.m3u8播放列表,这意味着真正的视频被切成了成百上千个TS切片。市面上的m3u8在线下载工具不少,但大多数人在第一次用时都会翻车:工具提示“下载完成”,输出文件却打不开;或者下载到一半直接断掉,前面几十个切片全白费。问题通常不在工具本身,而在m3u8协议背后的防盗链、相对路径、AES-128加密,以及CDN的Token有效期。这篇文章会把m3u8的完整播放链路拆开讲清楚,落到ffmpeg和专用下载器的具体参数配置上,再把实际下载中容易踩的五个坑逐一说明。适合需要批量保存课程视频、活动回放、直播录像片段的开发者和运营同学。
2. m3u8播放链路拆解:从抓包到切片地址,搞清楚你真正要下载的东西
2.1 m3u8文件结构与EXTINF标签
m3u8本质上是一个UTF-8编码的文本播放列表,记录着视频切片的位置和播放顺序。用文本编辑器直接打开,能看到类似下面的内容:
#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:10 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-KEY:METHOD=AES-128,URI="key.key",IV=0x00000000000000000000000000000000 #EXTINF:9.75, segment_001.ts #EXTINF:9.88, segment_002.ts #EXTINF:9.66, segment_003.ts #EXT-X-ENDLIST逻辑说明:#EXTM3U是文件头,表示这是一个扩展M3U列表。#EXTINF后面跟的是切片的时长(秒)和文件名,下载工具会按照它们在文件中的顺序逐个拉取并拼接。#EXT-X-KEY是加密标记,如果存在,说明后续TS切片的数据是加密过的,必须拿到key才能解开。
参数说明:实际下载时最需要关注的是两个字段。一是切片路径是相对路径还是绝对路径,相对路径时需要补齐base_url,最常见的翻车点就在这里。二是#EXT-X-KEY里的URI和IV,它们决定了解密方式。METHOD=AES-128是当前最常见的加密方式,IV如果省略则默认使用MEDIA-SEQUENCE的值。
2.2 抓包定位真实m3u8地址
很多页面里的m3u8地址并不会直接写在HTML源码里,而是通过JavaScript动态拼出来的,甚至通过Blob URL加载。遇到这种情况,直接复制网页源码是找不到任何有用信息的。
我一般会这样做:打开浏览器F12开发者工具,切到Network面板,刷新页面并点击播放。然后在过滤框里先选“Fetch/XHR”,再输入m3u8搜索关键字。定位到返回类型为media或application/vnd.apple.mpegurl的请求,右键复制完整URL。
这个方法在绝大多数网页端播放器里都有效,因为无论播放器怎么封装,最终都要向服务器请求一次m3u8清单。有一点需要注意,有些平台返回的m3u8地址是短时效的,签名参数可能只有30分钟有效期。抓到了就立刻开始下载,不要去做别的事,否则过一段时间再跑,下载工具就会收到403。
2.3 切片下载与合并的基本逻辑
m3u8下载工具的职责本质上是三件事:读取播放列表、逐个下载TS切片、按顺序合并。如果遇到加密流,中间会多一步解密。不同工具的具体实现方式不同,但底层流程是一致的。
先理解这一步,后面配参数才不会懵。下面用ffmpeg做一个最简单的验证:
ffmpeg -i "https://example.com/path/playlist.m3u8" -c copy output.mp4逻辑说明:ffmpeg读取m3u8列表之后,会自动拉取其中引用的所有TS切片,按顺序拼接并封装成MP4。-c copy表示流复制,也就是不重新编码,直接拷贝视频流和音频流,速度很快,对CPU几乎没有压力。
参数说明:-i后面接的是m3u8地址;-c copy是核心参数,告诉ffmpeg不要转码。如果去掉这个参数,ffmpeg会把视频重新编码一遍,不仅慢,而且画质会有损失。做下载验证时,我建议始终保持-c copy。
3. 实战下载:ffmpeg与专用下载器的参数配置
3.1 ffmpeg方案:适合快速拿单个视频
ffmpeg确实是最通用的方案,几乎所有平台都能用,但它有两个明显的短板:多线程下载能力弱、断点续传基本靠运气。如果只是一个视频、地址新鲜、没有防盗链,那ffmpeg一行命令就能搞定。
ffmpeg -headers "Referer: https://example.com/" -user_agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" -i "https://example.com/path/playlist.m3u8" -c copy output.mp4逻辑说明:这里额外加上了-headers和-user_agent参数,用来伪装请求头。很多视频网站的CDN会校验Referer和User-Agent,如果直接裸请求,服务器会返回403,ffmpeg会报错退出。
参数说明:-headers可以指定任意HTTP请求头,格式是"key: value",多个请求头就写多个-headers参数。-user_agent单独设置浏览器UA,如果网站还有Cookie校验,可以再加上-headers "Cookie: xxx"。但这只是临时解决方案,遇到Cookie动态刷新的站点,ffmpeg方案基本就走不通了。
3.2 专用M3U8下载器:多线程、重试、解密一揽子解决
讲到真正用来干活的工具,我实际用下来最顺手的是开源的多线程m3u8下载器RE版。它的核心优势有三个:并发拉取TS切片、失败自动重试、自动解析#EXT-X-KEY完成AES-128解密。尤其是重试机制,直接解决了ffmpeg“一断就白下”的老大难问题。
基本用法如下:
m3u8dl -i "https://example.com/path/playlist.m3u8" --auto-select --del-after-done逻辑说明:--auto-select让工具自动从多个备选码率轨道里选择最合适的一个;--del-after-done表示合并完成后自动删除临时TS切片,避免磁盘空间被占满。
参数说明:--thread-count可以手动指定并发数,网络情况好的时候我习惯设成32,甚至64。如果网络不稳定,建议降到8或16,不然切片拉得太快反而容易触发CDN限速。输出文件名用-o指定,如果只是想下载,不合并,可以加--skip-merge,只保留TS文件。
3.3 key与AES-128解密:工具替你做了,但你自己得会检查
当m3u8清单里出现#EXT-X-KEY:METHOD=AES-128时,说明TS切片是被加密过的。专用下载器会自动去请求key文件并解密,不需要手动介入,但它能正确处理的前提是:key文件的地址和请求头都能拿到。
我遇到过一个非常典型的翻车场景:key文件在m3u8里写的相对路径key.key,实际完整地址是https://example.com/key.key,但那个站点同时配了重定向,下载器去请求时返回的是一段HTML错误页而不是二进制key文件。结果就是解密失败,所有切片合并出来都是花屏。
排查方法很简单:先用curl把key单独拉下来看大小和内容是不是正常的。如果key文件只有几十字节而且是明文文本,那基本正常;如果返回的是HTML标签,那一定是请求头或地址出了问题。这时候需要在下载器里手动指定--header参数,把Referer和UA带上去,确保请求key文件和请求m3u8时的身份一致。
4. 避坑与排查:m3u8下载翻车的五种现场
4.1 现象:下载到一半只有几十个ts,后面全断
这种是最常见的翻车现场。前几十个切片正常,后面开始报错,再往后直接失败。原因通常是CDN的签名Token有效期太短,前十分钟还能下载,后面地址里的expires参数过期,服务器直接断开连接。
解决:先确认m3u8地址是否带expires或sign之类的参数。如果有,说明是短时效链接,需要尽快下载,或者找到Token生成规则写脚本自动续期。对于直播流的实时m3u8,则要换用支持定时重连的工具,让它在切片地址失效前自动更新列表。
4.2 现象:输出mp4后画面正常但没声音
TS切片里可以封装多种音频编码,比较常见的是AAC,但也有不少平台用AC3或EAC3。-c copy直接复制容器后,某些播放器能解码视频,却解不了音频,表现出来就是画面正常、声音没有。
解决:用ffmpeg单独处理音频轨道,视频保持流复制不损失画质:
ffmpeg -i output.mp4 -c:v copy -c:a aac -b:a 192k output_fixed.mp4逻辑说明:-c:v copy保持视频流不重编码,-c:a aac把音频转成最通用的AAC格式。这个方案兼容性最好,导出的文件在任何播放器上都能正常播放。
参数说明:-b:a 192k是音频码率,如果原视频音质一般,128k也够用。整套处理只重编码音频,速度非常快,对画质零影响。
4.3 现象:ffmpeg报错403或416
403是服务器拒绝了请求,通常是请求头不完整。416是HTTP Range请求不被服务器接受,部分CDN不支持分段请求,或者对Range字段格式有严格要求。
解决:403用前面提到的-headers补Referer、UA、Cookie三个字段。416则发生在下载多线程并发时,部分工具默认会分片请求,服务器不接受就会出现这种状况。在专用下载器里,把并发线程数改为1,或者关闭“分段请求”选项,通常就能绕过去。
4.4 现象:解密失败或提示“无效的key”
原因有两个:一是key文件没下载成功,被防盗链拦截或地址错误;二是IV和m3u8里声明的IV不一致。还有一种状况是站点用了SAMPLE-AES加密,这种加密方式常规下载器支持不好。
解决:先用curl单独验证key文件能正常下载,再看m3u8里IV的格式。IV必须是0x开头的32位十六进制字符串,如果缺失或格式错误,需要在下载器里手动指定。SAMPLE-AES加密我基本直接放弃常规工具,改用支持这种方案的特定工具,硬用普通下载器只会浪费更多时间。
4.5 现象:下载速度快但磁盘占满
高速下载时同时写几百个临时TS文件,合并后又要读一遍,如果合并前没有清理,整个临时目录会持续膨胀。下载几十个视频之后,磁盘空间就被占满了。
解决:开启--del-after-done让工具合并完成后自动清理临时文件。同时建议把临时目录指定到独立分区,避免和系统盘抢空间:
m3u8dl -i "https://example.com/path/playlist.m3u8" --tmp-dir /data/tmp --del-after-done -o /data/video.mp4逻辑说明:--tmp-dir把切片临时文件放到空间更大的磁盘,合并完即删除,不污染系统盘。
参数说明:下载结束时如果发现临时目录还有残留,说明任务是被强制中断的。下次启动前先手动清理一遍残留,否则磁盘会在不知不觉中被占满。
5. 批量下载与播放列表参数:从单集到全集
5.1 地址规律判断与脚本化
如果目标是一个系列课程,而不是单个视频,手工复制每个m3u8地址会非常痛苦。实际项目中的m3u8地址多数有规律可循,比如同一个课程的不同分集,只是URL路径中的ID序号不同。
先手动下载两个分集的m3u8,对比URL差异,找到变化的那个部分。然后写一个循环脚本批量拉取:
for i in $(seq -w 1 30); do url="https://example.com/course/ep${i}/playlist.m3u8" m3u8dl -i "$url" --auto-select --del-after-done -o "video_${i}.mp4" done逻辑说明:seq -w 1 30会生成从01到30的序号,ep${i}直接拼进URL。脚本会依次下载每一集,输出文件名带序号,方便后续归档。
参数说明:-o参数指定输出文件路径。这里要留意,URL里的序号如果不是补零的连续数字,seq -w会失效,需要改用seq 1 30并把URL里的ep01改成ep1对应。
5.2 顶层m3u8与子m3u8的码率选择
部分平台返回的m3u8是“顶层索引”,里面不是TS切片路径,而是不同分辨率子流的子m3u8地址:
#EXTM3U #EXT-X-STREAM-INF:BANDWIDTH=1280000,RESOLUTION=720x404 720p/index.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=512000,RESOLUTION=480x270 480p/index.m3u8逻辑说明:如果直接用顶层地址下载,工具会按--auto-select的规则选择一个码率,通常是最高的那个。
参数说明:想固定下载某个清晰度,需要先手动解析顶层m3u8里的子流地址,然后直接指定子m3u8作为输入。这样就能避开自动选择不符合预期的坑。
5.3 列表驱动下载与断点续传
URL规律不规则的场景,可以把所有m3u8地址先粘贴到一个文本文件里,再逐行读取下载:
while read url; do m3u8dl -i "$url" --auto-select --del-after-done done < video_list.txt逻辑说明:while read逐行读取文件,每一行即一个m3u8地址。这种方式完全不受URL规律限制,适合从页面上批量复制出来的地址列表。
参数说明:如果video_list.txt里有空行或注释,read会把它们当成空字符串传入,建议先用grep -v '^#'过滤一下。更好的做法是在URL列表文件里同时保存标题,下载时用-o参数按标题命名,免得下载完再挨个重命名。
断点续传方面,在多线程下载器RE里,任务中断后重启时会检查本地已有的切片,跳过已经完成的文件。这个机制依赖完整的本地临时记录,所以不要随意删除临时目录里的文件,否则断点续传会失效。
6. 验证下载结果与文件完整性:低成本却必须做的一步
下载完成不等于任务结束。直接打开播放器看一眼,往往发现不了问题——某些TS切片损坏是隐性的,画面能放,但播到特定秒数会卡顿或花屏。这种问题在批量处理时尤其容易漏掉。
我的习惯是下载完立刻做两件事。第一,检查文件大小是否合理。一个标清视频下载出来只有几十MB,基本可以判断中途丢了切片。第二,用ffmpeg对文件做一次完整的解码校验:
ffmpeg -v error -i output.mp4 -f null - 2>&1 | grep -i error逻辑说明:这个命令让ffmpeg从头到尾解码整个视频文件,但不写入磁盘。任何解码错误都会输出到stderr,通过grep -i error筛选出来。没有错误时输出为空。
参数说明:-v error只显示error级别的日志,避免噪声;-f null表示输出到空设备,不生成文件;最后的-表示输出目标是stdout。批量校验时套一个循环,逐个视频检测,把错误日志汇总到一个文件里,检查效率会高很多。
从那以后,我每次批量下载完都会把校验强制走一遍,再进入剪辑或归档环节。这个习惯替我省掉的返工时间远超它本身的花费。你会需要它,希望帮到你。
本文还有配套的精品资源,点击获取