【Fiddler+M3U8解析+Python】高效下载微信小程序分段视频实战

张开发
2026/4/18 0:00:13 15 分钟阅读

分享文章

【Fiddler+M3U8解析+Python】高效下载微信小程序分段视频实战
1. Fiddler抓包实战锁定M3U8文件位置微信小程序的视频内容通常采用M3U8流媒体格式这种技术会把完整视频切割成多个TS片段。要下载这些视频首先需要找到M3U8索引文件的位置。Fiddler作为专业的网络抓包工具能帮我们精准捕获这些关键信息。安装配置Fiddler时有个小技巧记得在Tools Options HTTPS中勾选Decrypt HTTPS traffic这样才能捕获微信小程序的加密流量。我第一次使用时没注意这个设置结果抓到的全是乱码白白浪费了半天时间。实际操作时先在电脑端打开微信小程序找到目标视频页面。这时候不要急着播放先打开Fiddler清空现有会话CtrlX然后再点击播放按钮。你会看到Fiddler界面瞬间刷出大量请求关键是要找到Process栏显示WeChat的那些请求。我常用的筛选技巧是在Fiddler右侧Inspectors面板选择Headers视图重点关注URL中包含.m3u8的请求。有时候服务器会使用二级索引即主M3U8文件里还包含多个子M3U8地址。遇到这种情况时建议把整个M3U8文件树都保存下来后面解析时会方便很多。2. 深入解析M3U8文件结构M3U8文件本质上是个播放列表里面记录了所有TS片段的下载地址。但不同网站的实现方式差异很大需要掌握几种常见模式才能应对各种情况。最简单的M3U8文件直接包含TS片段地址比如#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:10 #EXTINF:9.009, http://example.com/segment001.ts #EXTINF:9.009, http://example.com/segment002.ts但更多时候会遇到相对路径的情况这时需要拼接基础URL。我在处理某教育类小程序时就踩过这个坑TS地址都是/videos/seg1.ts这样的形式必须结合之前抓包得到的Host字段才能组成完整URL。更复杂的情况是加密的M3U8文件里会包含#EXT-X-KEY字段指定解密密钥。遇到这种情况时需要在Python代码中加入解密逻辑。不过好在微信小程序视频目前大多还是明文传输这给我们省了不少事。3. Python自动化下载方案有了M3U8文件接下来就是用Python实现自动化下载了。这里我推荐使用requests库配合多线程速度会比单线程快很多。首先定义一个下载函数def download_ts(url, save_path, headers): try: r requests.get(url, headersheaders, timeout10) with open(save_path, wb) as f: f.write(r.content) return True except Exception as e: print(f下载失败 {url}: {str(e)}) return False对于线程池的实现我习惯用concurrent.futuresfrom concurrent.futures import ThreadPoolExecutor def batch_download(ts_list, save_dir, headers, max_workers5): with ThreadPoolExecutor(max_workersmax_workers) as executor: futures [] for index, ts_url in enumerate(ts_list): save_path f{save_dir}/{index:04d}.ts futures.append(executor.submit(download_ts, ts_url, save_path, headers)) for future in concurrent.futures.as_completed(futures): if not future.result(): print(部分片段下载失败建议重试)实际使用中发现微信小程序视频的TS片段通常有数百个但用这种方法10分钟左右的视频5分钟内就能下载完成。记得设置合理的超时时间和重试机制网络不稳定时特别有用。4. TS片段合并与优化处理下载完所有TS片段后合并环节也有不少讲究。虽然简单的二进制合并就能播放但想要获得更好的兼容性建议使用FFmpeg工具。安装FFmpeg后可以用这个命令合并ffmpeg -f concat -safe 0 -i file_list.txt -c copy output.mp4其中file_list.txt内容格式为file 0001.ts file 0002.ts ...如果遇到音视频不同步的问题可能是某些TS片段损坏导致的。这时候可以先用ffprobe检查各个片段的时长ffprobe -v error -show_entries formatduration -of defaultnoprint_wrappers1:nokey1 input.ts我在处理某次下载任务时发现有3个TS片段时长异常导致最终视频后半部分严重不同步。后来单独重新下载了这几个片段问题就解决了。所以建议大家在合并前先做完整性检查。5. 完整代码实现与异常处理结合上述各个环节这里给出一个健壮的完整实现方案。代码加入了重试机制、进度显示和错误处理适合处理长时间运行的下载任务。import os import requests from concurrent.futures import ThreadPoolExecutor, as_completed from urllib.parse import urljoin import ffmpeg class M3U8Downloader: def __init__(self, base_url, headers, max_retry3): self.base_url base_url self.headers headers self.max_retry max_retry self.ts_list [] def parse_m3u8(self, m3u8_url): resp requests.get(m3u8_url, headersself.headers) if resp.status_code ! 200: raise Exception(fM3U8下载失败: {resp.status_code}) lines resp.text.split(\n) ts_urls [] for line in lines: line line.strip() if line and not line.startswith(#): if line.startswith(http): ts_urls.append(line) else: ts_urls.append(urljoin(self.base_url, line)) return ts_urls def download_with_retry(self, url, save_path, retry_count0): try: r requests.get(url, headersself.headers, timeout15) if r.status_code 200: with open(save_path, wb) as f: f.write(r.content) return True return False except Exception: if retry_count self.max_retry: return self.download_with_retry(url, save_path, retry_count1) return False def download_all(self, output_dir, max_workers5): if not os.path.exists(output_dir): os.makedirs(output_dir) with ThreadPoolExecutor(max_workersmax_workers) as executor: futures [] for idx, ts_url in enumerate(self.ts_list): save_path os.path.join(output_dir, f{idx:04d}.ts) futures.append(executor.submit( self.download_with_retry, ts_url, save_path)) for future in as_completed(futures): if not future.result(): print(下载失败请检查网络或URL) def merge_to_mp4(self, ts_dir, output_file): ts_files sorted([f for f in os.listdir(ts_dir) if f.endswith(.ts)]) with open(file_list.txt, w) as f: for ts in ts_files: f.write(ffile {os.path.join(ts_dir, ts)}\n) try: ( ffmpeg .input(file_list.txt, formatconcat, safe0) .output(output_file, ccopy) .run() ) return True except ffmpeg.Error as e: print(f合并失败: {e.stderr.decode()}) return False # 使用示例 if __name__ __main__: headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } base_url http://example.com/videos/ m3u8_url http://example.com/videos/playlist.m3u8 downloader M3U8Downloader(base_url, headers) ts_list downloader.parse_m3u8(m3u8_url) downloader.ts_list ts_list downloader.download_all(ts_files) downloader.merge_to_mp4(ts_files, output.mp4)这段代码在实际项目中经过多次优化处理过各种异常情况。比如某次下载800多个TS片段时遇到服务器限速通过调整max_workers参数和增加重试机制最终完成了下载。建议大家在关键步骤都添加日志记录方便排查问题。6. 常见问题排查与解决方案在实际操作过程中有几个高频出现的问题值得特别注意首先是403 Forbidden错误这通常是由于headers设置不当导致的。微信小程序的请求需要携带特定User-Agent我建议直接从Fiddler抓包中复制完整的headers字典。有时候还需要加入Referer字段才能通过验证。其次是TS片段顺序错乱的问题。有些网站的M3U8文件中的TS片段并不是按数字顺序排列的这时候如果按文件名排序合并就会得到混乱的视频。解决方案是在下载时保留原始顺序编号合并时严格按M3U8文件中的顺序处理。内存不足也是常见问题特别是在处理超长视频时。我遇到过合并2000个TS片段时程序崩溃的情况。后来改用FFmpeg的concat协议就解决了因为它不需要将所有片段同时加载到内存中。最后提醒大家注意法律风险这个方法仅适用于自己有权限下载的内容。某些小程序视频可能受DRM保护强行下载可能涉及法律问题。建议在下载前确认内容的版权状态。

更多文章