
最近一段时间不少朋友都在折腾“网课视频本地保存”这件事但大多数人卡在了同一个地方视频明明可以在线流畅播放开发者工具里却找不到一个直接的mp4链接。仔细翻一下 Network 面板满屏都是.m3u8和一堆.ts分片地址直接保存下来又打不开。这篇文章不讲玄学只讲可落地的方案。我会从 m3u8 协议基础开始完整梳理“如何获取有效的 m3u8 地址”“如何用 ffmpeg 和专用工具下载合并”“常见报错怎么排查”这几个关键环节。无论你是做音视频开发的工程师还是想把已购课程备份到本地的学习者都可以按照这篇文章的步骤走通全流程。1. m3u8 是什么为什么在线课程都喜欢用它1.1 m3u8 并不是视频文件很多新手第一次看到 m3u8 时会下意识认为它是一种视频格式。实际上m3u8 是一个文本文件里面记录的只是一系列视频分片的地址和播放规则。你可以把它理解成一份“歌单”分片文件才是真正的“歌曲”。一个典型的 m3u8 文件内容大概是这样的#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:10 #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:10.0, https://cdn.example.com/video/segment_000.ts #EXTINF:10.0, https://cdn.example.com/video/segment_001.ts #EXT-X-ENDLIST播放器拿到这个文件后会按照列表里的顺序逐个请求.ts分片然后拼接成完整的视频播放出来。整个过程看起来像是“边下边播”这就是 HLSHTTP Live Streaming协议的基本工作方式。1.2 HLS 协议解决了什么问题HLS 是苹果公司提出的一套流媒体传输协议核心思路不难理解不把一整段视频一次性发给用户而是把视频切成若干个小分片每个分片通常只有几秒到十几秒播放器逐个下载并连续播放。这种设计带来了几个明显的好处支持直播和点播尤其是直播场景播放器可以实时拉取新增的分片。支持多码率自适应播放器可以根据当前网速切换清晰度。CDN 缓存命中率更高小分片更容易被边缘节点缓存。断点续播更友好下次播放时可以直接从某个分片继续。正是因为这些特性大量在线教育平台、视频网站、小程序视频课程都采用了 HLS/m3u8 方案来分发内容。1.3 在线课程偏爱 m3u8 的另一个原因除了技术上的优势m3u8 方案还有一个让内容方比较安心的点它天然不支持“右键另存为”。用户看到的播放地址是一个 m3u8 播放列表而不是直接的视频文件地址这就在一定程度上增加了下载门槛。不过也要说清楚门槛只对普通用户有效。m3u8 本身是开放的协议标准凡是能播放的视频流理论上也能通过常规技术手段下载合并。这里需要明确一个前提本文讨论的是“把自己有权访问、有权离线使用的视频保存到本地”不涉及绕过任何付费鉴权、版权保护系统的行为。1.4 先讲清楚“解密”到底指什么很多人搜索“视频课程解密”这个词实际上会遇到两层不同的含义第一层是 HLS 传输加密即 m3u8 文件里写了#EXT-X-KEY标签分片用 AES-128 或 AES-256 加密播放器需要拿到密钥文件才能解密播放。这类解密是 ffmpeg 等工具自动完成的属于正常流程。第二层是商业 DRM 版权保护比如 Widevine、FairPlay这类技术会彻底加密视频内容并且绑定了播放器环境普通工具根本无法处理。本文只会涉及第一层也就是 HLS 自身的 AES 加密分片下载这也是绝大多数网课 m3u8 视频的真实情况。对于 DRM 保护的内容不该下载也没有必要去研究绕过方法。2. 环境准备与工具选择在实际动手之前先把需要用到的环境和工具准备好。下面以 Windows 系统为示例环境macOS 和 Linux 的差异我会在对应位置说明。2.1 安装 ffmpegffmpeg 是整个下载流程里最重要的命令行工具它支持直接读取 m3u8 文件、下载分片、解密、合并输出一步到位。Windows 下安装流程打开 ffmpeg 官网下载页面选择 Windows 对应的 release 版本。下载压缩包后解压到某个目录例如D:\ffmpeg。将D:\ffmpeg\bin添加到系统环境变量 PATH 中。打开命令提示符输入ffmpeg -version如果能正常输出版本信息说明安装成功。macOS 下安装要简单得多推荐直接使用 Homebrewbrew install ffmpegLinux 发行版一般也可以直接用包管理器安装比如 Ubuntu/Debiansudo apt update sudo apt install ffmpeg版本不需要追求最新能用稳定版就行。不同版本的 ffmpeg 参数基本兼容本文中的命令在较新版本上都能正常运行。2.2 准备浏览器开发者工具获取 m3u8 地址是后续所有步骤的前提而最常用的工具就是 Chrome 或 Edge 自带的开发者工具。打开开发者工具的方式很简单在视频播放页面按F12或者在页面任意位置右键选择“检查”。日常主要用到 Network网络面板用来观察页面发出的所有 HTTP 请求。2.3 两个可选的下载工具除了 ffmpeg下面两个工具在 m3u8 视频下载场景中同样很有名N_m3u8DL-RE专为 m3u8/mp-dash 下载而生的命令行工具支持多线程下载、自动解密、自动合并遇到时间较长的大文件时优势非常明显。lux原 annie主打“自动解析视频页面”输入一个播放页面地址它会自动找出页面里的视频流地址并下载。这两个工具更新速度都很快建议直接去各自的 GitHub Releases 页面下载对应版本不要用第三方网站转载的旧版本。3. 读懂 m3u8 索引文件是排错的基础很多人在下载 m3u8 视频时遇到问题根本原因是没看懂 m3u8 内容。这一节把 m3u8 里最常见的标签解释清楚。3.1 m3u8 的常见标签标签含义#EXTM3U文件头固定值表示这是一个 m3u8 播放列表#EXT-X-VERSION协议版本号常见为 3#EXT-X-TARGETDURATION单个分片的最大时长单位秒#EXT-X-MEDIA-SEQUENCE第一个分片的序号直播流常用#EXTINF后面分片的时长单位秒下一行是对应的分片地址#EXT-X-KEY分片加密信息包含加密方法和密钥地址#EXT-X-STREAM-INF多码率变体信息这里面嵌套了子 m3u8 地址#EXT-X-ENDLIST文件结尾有它说明是点播流没有则是直播流理解这些标签有什么实际价值举一个例子如果你看到下载命令执行后报错“m3u8 文件里没有有效的分片地址”大概率是下载了一个只有多码率信息的父 m3u8而不是真正包含分片列表的子 m3u8。这时候就需要进入#EXT-X-STREAM-INF后面的子 m3u8 地址继续下载。3.2 带 AES 加密的 m3u8 长什么样下面是一个带 AES-128 加密的 m3u8 片段#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:8 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-KEY:METHODAES-128,URIhttps://cdn.example.com/key/encrypt.key,IV0x9f7c... #EXTINF:8.0, https://cdn.example.com/video/seg_000.ts #EXTINF:8.0, https://cdn.example.com/video/seg_001.ts #EXT-X-ENDLIST注意#EXT-X-KEY这一行METHODAES-128说明分片文件用 AES-128 算法加密URI指向密钥文件的地址IV是初始向量。ffmpeg 在下载这类 m3u8 时会自动读取#EXT-X-KEY信息请求密钥文件然后解密分片。整个过程不需要你手动编写加解密脚本。但如果密钥文件地址本身需要登录 cookie 或特定请求头ffmpeg 可能会请求失败这时候就需要额外给 ffmpeg 带上请求头参数。3.3 多码率 m3u8 的处理当视频有多种清晰度时播放器请求到的第一个 m3u8 可能长这样#EXTM3U #EXT-X-STREAM-INF:BANDWIDTH2500000,RESOLUTION1280x720 https://cdn.example.com/video/720p/index.m3u8 #EXT-X-STREAM-INF:BANDWIDTH1200000,RESOLUTION854x480 https://cdn.example.com/video/480p/index.m3u8这种情况下直接把这个 URL 交给 ffmpeg它通常会自动选择码率最高的子流进行下载。如果你希望指定清晰度可以先打开父 m3u8 地址手动找到对应码率的子 m3u8 URL再传给下载命令。4. 如何拿到有效的 m3u8 播放地址获取 m3u8 地址是整个下载流程中最需要细心的一步。下面按从简单到复杂的顺序介绍几种方法。4.1 方法一浏览器开发者工具最常用以 Chrome 浏览器为例打开视频播放页面先不要立即播放。按F12打开开发者工具切换到 Network 面板。在筛选框中输入m3u8或者选择 Fetch/XHR 类型筛选。点击页面上的播放按钮。观察 Network 面板中新增的请求找到类型为media或fetch、名称以.m3u8结尾的请求。右键该请求选择 Copy再选择 Copy link address。拿到地址后建议先用 VLC 播放器验证一下这个地址是否有效。打开 VLC选择“打开网络串流”粘贴地址如果能正常播放说明这个地址状态可用。这里有一个常见误区有些人一边开着视频一边打开开发者工具结果发现 Network 面板里并没有 m3u8 请求。原因是很多播放器在页面初始化时就完成了 m3u8 请求或者在视频真正开始播放之前网络请求已经被清理掉了。正确做法是先打开开发者工具再播放视频。4.2 方法二刷新页面时快速筛选如果视频是自动播放的你可能来不及打开 Network 面板。这种情况下可以先刷新页面让页面重新加载再快速在筛选框中输入m3u8。页面刷新后所有资源请求都会重新发起m3u8 请求自然也会出现在列表里。如果请求很多还可以结合时间线观察。Network 面板上方有一个录制按钮和清除按钮在刷新页面之前先点击清除确保列表里只有最新一轮请求。4.3 方法三抓包工具调试自己的设备在调试手机 App 或小程序内嵌页面时浏览器开发者工具就不太好用了这时候可以使用 Charles 或 Fiddler 这类抓包工具。基本思路是在电脑上安装 Charles/Fiddler开启 HTTPS 抓包功能。手机和电脑连到同一个局域网手机设置代理指向电脑 IP。安装并信任 Charles 的 SSL 证书。在 App/小程序里播放视频然后在抓包工具里筛选m3u8。需要特别说明的是抓包工具请只用于调试你自己设备上、你有权访问的网络请求不要用来做任何越权采集。很多小程序的视频请求都带签名和过期时间即使抓到了地址脱离原环境的请求也大概率会失败。4.4 方法四小程序场景下的技术分析回到标题里提到的“小程序视频课程”场景。微信小程序里播放的视频本质上走的还是 HTTP(S) 网络请求m3u8 地址同样会出现。如果你通过抓包工具或小程序开发者工具观察到了 m3u8 请求这里有几个技术现象值得了解小程序播放器可能会对 m3u8 URL 做中转或签名处理直接复制 URL 并不能下载。部分小程序的视频域名限制在微信公众平台配置的白名单内请求时还需要携带特定请求头。有些平台会把密钥文件地址和分片地址设为短期有效过期后下载就会失败。对于这种情况常规处理方式是保证下载请求环境与播放环境一致也就是带上正确的User-Agent、Referer、Cookie等请求头。但这里必须强调如果你是课程的合法购买者为了离线学习而下载这是个人合理使用如果地址本身需要特殊权限或存在鉴权隔离请不要尝试通过绕过机制去获取不属于你的内容。5. 使用 ffmpeg 下载 m3u8 视频拿到 m3u8 地址后接下来的核心操作就在 ffmpeg 这里了。5.1 最基础的下载命令打开命令行Windows 下是 CMD 或 PowerShell执行ffmpeg -i https://example.com/video/index.m3u8 -c copy output.mp4参数说明-i指定输入文件也就是 m3u8 的 URL。-c copy表示流复制也就是不重新编码直接把原始数据拷贝到输出文件。这样做速度极快而且画质无损耗。output.mp4是输出文件名可以自定义。这是最简单、最常用的命令。但注意很多在线课程站点会做防盗链校验直接拿这个命令下载往往会返回 403 错误。5.2 带上 Referer 和 User-Agent 下载防盗链的校验原理并不复杂服务器检查请求头里的Referer如果来源不在允许列表内就拒绝返回数据。有些服务器还会校验User-Agent禁止非浏览器客户端的访问。带请求头的 ffmpeg 命令如下ffmpeg -user_agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 -headers Referer: https://example.com/course/123\r\n -i https://example.com/video/index.m3u8 -c copy output.mp4这里有两个细节值得留意-headers参数要放在-i之前否则不生效。Referer末尾必须包含\r\n这是 HTTP 协议头的标准换行。有些平台还会校验 Origin同样可以加进去ffmpeg -user_agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 -headers Referer: https://example.com/\r\nOrigin: https://example.com\r\n -i https://example.com/video/index.m3u8 -c copy output.mp4如果还需要携带 Cookie可以继续在-headers中追加ffmpeg -headers Referer: https://example.com/\r\nCookie: sessionidyour_cookie_value\r\n -i https://example.com/video/index.m3u8 -c copy output.mp4这里的 Cookie 必须来自你自己登录后的浏览器会话。5.3 先输出 TS 再转 MP4解决封装失败问题用-c copy直接输出 mp4 时有时会报错或者生成的文件无法播放。这通常跟视频流的编码参数有关比如某些 HLS 流里的音频编码格式不适合直接封装进 mp4。一个更稳妥的方法是先保存为 TS 格式再做一次重新封装。TS 是一种非常“宽容”的容器格式几乎所有 HLS 流都能直接封装成 TS。ffmpeg -user_agent Mozilla/5.0 -headers Referer: https://example.com/\r\n -i https://example.com/video/index.m3u8 -c copy output.ts拿到 output.ts 后再执行一次封装转换ffmpeg -i output.ts -c copy -movflags faststart output.mp4-movflags faststart的作用是把 mp4 文件里的索引信息移动到文件头部这样视频文件放到网页中时可以先加载少量数据就能开始播放也方便在手机上快速预览。5.4 先下载分片到本地再用 concat 合并有时候视频源地址不稳定直接让 ffmpeg 在线下载会导致中途失败。更稳妥的做法是先把所有.ts分片和 m3u8 文件下载到本地再通过文件列表合并。第一步把 m3u8 里的分片地址批量下载下来。如果分片数量不多可以直接用浏览器或下载工具逐个下载。如果分片数量很多建议写一个简单的脚本。这里以 Python 为例说明下载逻辑import requests base_url https://cdn.example.com/video/ segments [segment_000.ts, segment_001.ts, segment_002.ts] headers { User-Agent: Mozilla/5.0, Referer: https://example.com/ } for seg in segments: resp requests.get(base_url seg, headersheaders, timeout10) with open(seg, wb) as f: f.write(resp.content) print(fdone: {seg})第二步创建一个concat.txt文件内容按以下格式填写file segment_000.ts file segment_001.ts file segment_002.ts第三步执行 concat 合并ffmpeg -f concat -safe 0 -i concat.txt -c copy output.mp4注意 Windows 路径问题。如果 ts 文件路径包含反斜杠建议统一改成正斜杠否则某些版本会解析报错。5.5 直播流的下载方式直播 m3u8 和点播 m3u8 最大的区别是文件末尾没有#EXT-X-ENDLIST。ffmpeg 下载直播流时会一直等待新的分片生成不会自动停止。如果要录制一段时长的直播可以用-t参数限制录制时间ffmpeg -t 00:30:00 -i https://example.com/live/index.m3u8 -c copy live.mp4这条命令会录制前 30 分钟。也可以不加-t等需要停止时在命令行按下Ctrl C手动中断。6. 使用专用下载工具提升效率ffmpeg 是通用方案但在某些场景下使用专用工具会更高效。6.1 N_m3u8DL-REm3u8 下载的利器N_m3u8DL-RE 比 ffmpeg 更加聚焦 m3u8 下载场景它支持多线程并发下载分片速度更快自动识别并处理 AES 加密解密下载完成后自动合并输出节省手动操作。基本用法N_m3u8DL-RE https://example.com/video/index.m3u8 --save-dir ./download --tmp-dir ./temp --auto-select参数说明--save-dir指定最终文件的保存目录。--tmp-dir指定临时分片文件的存放目录。--auto-select自动选择最佳画质。如果下载的 m3u8 需要请求头可以先用文本文件保存请求头再通过--header参数指定N_m3u8DL-RE https://example.com/video/index.m3u8 --header headers.txtheaders.txt 的格式一般是User-Agent: Mozilla/5.0 Referer: https://example.com/6.2 lux自动解析页面视频地址lux 适合这样一个场景你手上只有一个播放页面的 URL还没有找到 m3u8 地址。lux 会自动分析页面源码提取可用视频流然后交给下载器下载。基本用法lux -i https://example.com/course/123如果页面需要登录可以先在浏览器中把 Cookie 导出成文件再传给 luxlux -c cookie.txt -i https://example.com/course/123不过 lux 对第三方网站的适配依赖于站点结构如果站点改版解析可能失败。6.3 什么时候不适合用专用工具专用工具虽然方便但也有局限遇到动态签名有效期极短的链接时工具可能还没来得及下载完链接就失效了遇到自定义加密方案时工具也会无能为力。这种情况下还是回到 ffmpeg 抓取当前有效地址以最快速度完成下载比较靠谱。7. 常见问题与排查思路这一节把 m3u8 视频下载中最常见的问题汇总成表并给出排查方向。问题现象常见原因解决思路下载返回 403 Forbidden缺少 Referer 或 User-Agent防盗链拦截补全请求头保持与播放环境一致下载返回 404 Not Foundm3u8 地址是动态签名的已过期重新打开页面抓取新的 m3u8 地址报错 Invalid data found when processing inputm3u8 地址不对或网络中断检查地址是否有效替换为完整可访问的子 m3u8输出 mp4 失败或无法播放音视频编码与 mp4 容器冲突先输出 TS 再转 MP4或用-movflags faststart加密流下载后花屏/报解密失败key 地址需要特殊请求头给 ffmpeg 或下载工具添加 Cookie/Referer分片下载到一半中断网络不稳定或服务器限速改用支持多线程断点续传的 N_m3u8DL-REconcat 合并时报错文件列表格式不正确检查路径斜杠、引号、文件名是否与磁盘一致下载出的视频时长比源视频短播放器请求的 m3u8 可能是测试片段重新抓取播放过程中最新的 m3u8 地址7.1 403 Forbidden 的完整排查步骤403 是 m3u8 下载里最高频的报错。按下面的顺序排查即可确认访问这个 m3u8 地址时是否处于同一个网络环境有时校内网、局域网资源需要特定 IP。在浏览器无痕窗口中打开 m3u8 地址如果能播放说明地址本身有效只差请求头。复制浏览器请求头里的 Referer 和 User-Agent添加到 ffmpeg 命令中。如果仍然 403观察浏览器请求里是否还有其他自定义请求头比如Origin、Cookie继续补充。如果所有请求头都补上了仍 403大概率服务器的鉴权逻辑是动态 token 或者绑定 IP 的这种情况建议放弃直接下载。7.2 mp4 输出失败的替代方案很多情况下-c copy直接输出 mp4 会失败原因是 HLS 流里的音频轨可能是AAC-LC或HE-AAC而 mp4 封装对某些音频配置支持不佳。不必纠结原因最直接的处理办法是先封装成 TSffmpeg -i https://example.com/video/index.m3u8 -c copy output.ts然后再统一转成 mp4ffmpeg -i output.ts -c copy output.mp4这样两步操作基本不会遇到封装失败的问题。7.3 加密流解密失败的判断方法下载加密的 m3u8 时如果执行命令后出现类似下面的日志[hls 0000025f...] Opening https://cdn.example.com/key/encrypt.key for reading说明 ffmpeg 正在尝试读取密钥文件。如果随后报错或者文件解码异常通常是密钥文件请求被拦截。此时可以用单独的curl命令测试密钥地址是否能正常访问curl -I https://cdn.example.com/key/encrypt.key -H Referer: https://example.com/ -H User-Agent: Mozilla/5.0如果返回 403 或 404就需要在 ffmpeg 命令中补充请求头信息。8. 从工具到工程下载脚本与最佳实践当你需要下载的不是一个视频而是一整个课程目录时手动一条条执行命令显然太低效。这一节提供一个脚本化下载的思路。8.1 编写批量下载批处理脚本Windows 环境下可以写一个简单的.bat脚本循环处理 URL 列表。比如建立一个urls.txt文件每行一个 m3u8 地址和一个输出文件名用逗号分隔https://example.com/video/chapter1/index.m3u8,chapter1.mp4 https://example.com/video/chapter2/index.m3u8,chapter2.mp4再写一个批处理文件download.batecho off chcp 65001 nul for /f tokens1,2 delims, %%i in (urls.txt) do ( echo 正在下载 %%j ffmpeg -user_agent Mozilla/5.0 -headers Referer: https://example.com/\r\n -i %%i -c copy %%j ) echo 全部下载完成 pauseLinux/macOS 环境下用 bash 脚本更顺手#!/bin/bash while IFS, read -r url output; do echo 下载 $output ffmpeg -user_agent Mozilla/5.0 -headers Referer: https://example.com/\r\n -i $url -c copy $output done urls.txt注意脚本里的Referer需要替换成你自己的实际来源页面。8.2 用 ffprobe 校验下载结果下载完成后建议用 ffprobe 检查一下文件的时长和编码信息确认视频没有缺分片。ffprobe -v error -show_entries formatduration -of defaultnoprint_wrappers1:nokey1 output.mp4这条命令会输出视频的时长比如3660.000000表示 3660 秒。你可以和播放页面上的时长做对比如果明显偏短说明某些分片没有下载完整需要重新抓取地址再下载。8.3 命名规范和目录规划课程类视频下载后最好按照“课程编号 章节编号 标题”的规则命名例如C01_第01章_课程介绍.mp4 C01_第02章_环境搭建.mp4这样做的好处是方便后续导入手机、平板等设备时保持顺序也方便用 Emby、Jellyfin 这类媒体服务器统一管理。8.4 安全与合规建议工具本身是中性的但使用场景需要注意边界。整理几条实用的建议只下载你自己购买、有权离线使用的课程不要传播、售卖下载后的文件。不尝试绕过 DRM 版权保护这既涉及版权问题也几乎没有技术可能性。不要轻易运行网上流传的“破解版下载工具”这类工具很可能捆绑恶意软件或盗取账号信息。使用带有个人 Cookie 的工具时注意不要在公共设备或群聊中泄露请求信息。下载遇到需要登录鉴权的资源时先确认自己是否有合法访问权限再考虑技术方案。9. 小结m3u8 视频下载并不是什么高深莫测的技术。理解 HLS 的分片协议后整体思路很清晰先用开发者工具或抓包工具找到有效的 m3u8 播放列表地址再用 ffmpeg 或专用工具下载、解密、合并分片最后输出为本地视频文件。这篇文章里覆盖了从 m3u8 协议基础、地址获取、ffmpeg 命令用法、专用工具选择到常见报错排查的完整流程。如果你只是偶尔下载一两个视频ffmpeg 加上正确请求头就够了如果经常需要处理大量课程视频建议把 N_m3u8DL-RE 和批量脚本纳入自己的工作流。下一步你可以继续学习 HTTP 请求头鉴权机制、CDN 防盗链策略或者研究 HLS 直播流的录制优化。需要说明的是技术能力越强越要对自己的使用边界有清晰认知。把工具用在合理合法的场景里才是长久之道。