在线视频越来越普及,很多平台都采用m3u8格式来传输视频内容。这种格式将视频分割成多个小片段,通过播放列表来控制播放顺序。如果你想把这些在线视频保存到本地,手动下载每个分片再合并显然不现实。这时候,用Python写一个自动化脚本就成了高效的解决方案。
本文会一步步教你如何编写Python脚本,自动下载m3u8文件中的所有分片,然后合并成完整的MP4视频。即使你是编程新手,跟着步骤操作也能顺利完成。
准备工作与环境搭建
在开始编写脚本前,我们需要准备好必要的工具和库。首先确保你的电脑上已经安装了Python,推荐使用3.7及以上版本。如果还没安装,可以从官网下载并按照提示完成安装。
我们需要用到以下几个Python库:
- requests:用于发送HTTP请求,下载m3u8文件和视频分片
- m3u8:专门解析m3u8文件的库
- ffmpeg:用于合并视频分片(需要单独安装,不是Python库)
打开命令行工具,输入以下命令安装所需的Python库:
pip install requests m3u8
对于ffmpeg,Windows用户可以从官网下载后将其添加到系统环境变量,macOS用户可以用Homebrew安装(brew install ffmpeg
),Linux用户则可以通过包管理器安装(如sudo apt install ffmpeg
)。
m3u8 下载原理
在动手写代码前,先简单了解一下m3u8的工作原理会很有帮助。m3u8文件本质上是一个播放列表,里面记录了一系列视频分片(通常是.ts格式)的URL地址,有时还会包含加密信息。
下载m3u8视频的基本流程是:
- 获取m3u8文件的内容并解析
- 提取所有视频分片的URL
- 依次下载所有分片到本地
- 使用ffmpeg将所有分片合并成一个MP4文件
- (可选)如果分片被加密,需要先解密再合并
了解这个流程后,我们就可以有针对性地编写代码了。
基础脚本实现
下面我们来编写一个基础版本的m3u8下载脚本。这个脚本可以处理未加密的m3u8文件,完成从下载到合并的全过程。
import os
import requests
import m3u8
import subprocess
from urllib.parse import urljoin
def download_m3u8(m3u8_url, output_file):
# 创建临时目录存放分片
temp_dir = "temp_ts_files"
if not os.path.exists(temp_dir):
os.makedirs(temp_dir)
# 下载并解析m3u8文件
response = requests.get(m3u8_url)
m3u8_obj = m3u8.loads(response.text)
# 下载所有分片
ts_urls = []
for segment in m3u8_obj.segments:
ts_url = urljoin(m3u8_url, segment.uri)
ts_urls.append(ts_url)
ts_filename = os.path.join(temp_dir, f"{len(ts_urls)}.ts")
# 如果文件已存在则跳过
if os.path.exists(ts_filename):
print(f"已存在: {ts_filename}")
continue
# 下载分片
print(f"下载中: {ts_filename}")
ts_response = requests.get(ts_url, stream=True)
with open(ts_filename, 'wb') as f:
for chunk in ts_response.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
# 生成分片列表文件
list_file = "ts_list.txt"
with open(list_file, 'w') as f:
for i in range(1, len(ts_urls) + 1):
f.write(f"file '{os.path.join(temp_dir, f'{i}.ts')}'\n")
# 使用ffmpeg合并分片
print("正在合并视频...")
subprocess.run([
'ffmpeg', '-y', '-f', 'concat', '-safe', '0',
'-i', list_file, '-c', 'copy', output_file
], check=True)
# 清理临时文件
print("清理临时文件...")
for i in range(1, len(ts_urls) + 1):
os.remove(os.path.join(temp_dir, f'{i}.ts'))
os.rmdir(temp_dir)
os.remove(list_file)
print(f"视频已保存为: {output_file}")
# 使用示例
if __name__ == "__main__":
m3u8_url = "这里替换为你的m3u8文件URL"
output_file = "output.mp4"
download_m3u8(m3u8_url, output_file)
这个脚本的使用方法很简单,只需要将实际的m3u8文件URL替换到示例中的位置,运行脚本后就会自动下载并生成output.mp4文件。脚本会创建临时目录存放分片,合并完成后自动清理,不会占用额外空间。
高级功能扩展
基础脚本可以应对简单场景,但实际使用中可能会遇到需要处理加密内容、设置代理或断点续传等需求。我们可以对脚本进行一些扩展:
处理加密的m3u8文件
很多视频平台会对m3u8分片进行加密(通常是AES-128加密),这时候需要先获取密钥进行解密。我们可以扩展脚本以支持加密内容:
# 仅展示关键扩展部分
import Crypto.Cipher.AES # 需要安装pycryptodome库
def download_encrypted_m3u8(m3u8_url, output_file):
# ...(前面的代码类似基础版本)
# 获取密钥
key_uri = urljoin(m3u8_url, m3u8_obj.keys[0].uri)
key_response = requests.get(key_uri)
key = key_response.content
# 下载并解密分片
for segment in m3u8_obj.segments:
# ...(获取ts_url等代码)
# 下载分片
ts_response = requests.get(ts_url)
encrypted_data = ts_response.content
# 解密(IV从分片信息中获取)
iv = segment.iv or b'0000000000000000'
cipher = Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_CBC, iv)
decrypted_data = cipher.decrypt(encrypted_data)
# 保存解密后的分片
with open(ts_filename, 'wb') as f:
f.write(decrypted_data)
# ...(后面的合并代码与基础版本相同)
使用这段扩展代码前,需要先安装pycryptodome库:pip install pycryptodome
多线程下载加速
对于包含大量分片的视频,单线程下载速度可能较慢。我们可以使用多线程来加速下载:
from concurrent.futures import ThreadPoolExecutor
# 在下载分片部分使用线程池
with ThreadPoolExecutor(max_workers=5) as executor:
executor.map(download_single_ts, ts_urls, [temp_dir]*len(ts_urls))
# 单独的分片下载函数
def download_single_ts(ts_url, temp_dir):
# 实现单个分片的下载逻辑
pass
播放器验证方法
下载并合并完成后,我们可以用播放器验证视频是否正常。推荐使用VLC媒体播放器,它不仅能直接播放m3u8流,也能完美支持合并后的MP4文件。
使用VLC验证的方法很简单:打开VLC,点击"媒体" -> "打开文件",选择合并后的MP4文件即可播放。如果想直接播放m3u8流进行对比,可以选择"媒体" -> "打开网络串流",输入m3u8的URL后点击播放。
其他支持m3u8格式的播放器还有PotPlayer、MPC-HC等,它们也可以用来验证下载结果的完整性和播放效果。
非编程方案推荐
如果你不熟悉Python编程,或者觉得编写脚本太麻烦,也可以使用现成的工具来完成m3u8下载和转换工作。比如m3u8转mp4工具就提供了图形界面,只需输入m3u8的URL,点击几下就能完成下载和格式转换,非常适合新手使用。
这类工具通常还内置了更多实用功能,如批量下载、自动识别加密内容、调整输出格式参数等,可以大大提高处理效率。
注意事项与常见问题
在使用脚本或工具下载m3u8视频时,需要注意以下几点:
- 确保你有合法权利下载和保存目标视频,遵守版权法规和网站条款
- 部分网站会设置防盗链或时效限制,可能导致下载失败或分片过期
- 如果遇到403错误,尝试在请求头中添加User-Agent等信息模拟浏览器
- 合并大文件时需要一定时间,请耐心等待,不要强行终止程序
- 如果合并后的视频没有声音,可能需要在ffmpeg命令中指定音频编码
常见问题解决:如果下载的分片无法合并,首先检查ffmpeg是否正确安装并添加到环境变量;其次确认所有分片都已完整下载;最后可以尝试在ffmpeg命令中去掉-c copy
参数,让ffmpeg重新编码视频。
总结
使用Python脚本下载m3u8分片并合并为MP4是一种灵活高效的方法,尤其适合需要批量处理或自定义下载逻辑的场景。通过本文介绍的基础脚本和扩展功能,你可以应对大多数m3u8下载需求。
对于普通用户,图形化的m3u8转mp4工具可能更简单易用。无论选择哪种方式,都要记得遵守相关法律法规,尊重知识产权,只下载和使用有合法权限的内容。