python下载M3U8视频脚本 安装依赖pip install m3u8 requests程序import os import time import requests import m3u8 from urllib.parse import urljoin from Crypto.Cipher import AES from Crypto.Util.Padding import pad def download_m3u8_video(url, save_nameoutput.mp4): headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)} print( 正在解析 m3u8 播放列表...) try: playlist m3u8.load(uriurl, headersheaders) except Exception as e: print(f❌ 解析失败: {e}) return # 检查是否存在 AES 加密 key, iv None, None if playlist.keys and playlist.keys[-1] is not None: key_info playlist.keys[-1] key_uri key_info.uri # 【核心修复】如果密钥是相对路径使用 urljoin 拼接完整的 URL if not key_uri.startswith(http): key_uri urljoin(url, key_uri) print(f 检测到加密正在获取完整密钥链接: {key_uri}) # 获取密钥内容建议加上与下载视频相同的 headers防止防盗链拦截 key_resp requests.get(key_uri, headersheaders, timeout15) key_resp.raise_for_status() key key_resp.content # 获取 IV 向量如果没有则默认使用全零的 16 字节 iv key_info.iv if iv: iv bytes.fromhex(iv.replace(0x, )) else: iv b\x00 * 16 total len(playlist.segments) print(f✅ 解析成功共 {total} 个片段开始下载并合并...) start_time time.time() size 0 with open(save_name, wb) as f: for i, seg in enumerate(playlist.segments, 1): try: # 同样确保 TS 分片也是完整 URL ts_url seg.absolute_uri r requests.get(ts_url, headersheaders, timeout15) r.raise_for_status() data r.content # 如果有密钥进行 AES 解密 if key: cipher AES.new(keykey, modeAES.MODE_CBC, iviv) data cipher.decrypt(pad(data, AES.block_size)) f.write(data) size len(data) # 打印进度 elapsed time.time() - start_time speed size / elapsed / 1024 / 1024 print(f\r⏳ 进度: {i}/{total} | 已下载: {size / 1024 / 1024:.2f}MB | 速度: {speed:.2f}MB/s, end) except Exception as e: print(f\n❌ 第 {i} 个片段下载失败: {e}) continue print(f\n 视频已成功保存为: {save_name}) if __name__ __main__: M3U8_URL xxx download_m3u8_video(M3U8_URL, my_video.mp4)