返回文章列表

使用 Python /脚本自动化下载 m3u8 分片并合并为 MP4

在线视频越来越普及,很多平台都采用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视频的基本流程是:

  1. 获取m3u8文件的内容并解析
  2. 提取所有视频分片的URL
  3. 依次下载所有分片到本地
  4. 使用ffmpeg将所有分片合并成一个MP4文件
  5. (可选)如果分片被加密,需要先解密再合并

了解这个流程后,我们就可以有针对性地编写代码了。

基础脚本实现

下面我们来编写一个基础版本的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工具可能更简单易用。无论选择哪种方式,都要记得遵守相关法律法规,尊重知识产权,只下载和使用有合法权限的内容。

参考资料