基本原理,通过浏览器“开发者工具”,找到 m3u8 文件(如果有2个m3u8,注意查看其响应内容,确保是包含 ts 文件列表的那个,通常是第2个),再使用爬虫下载所有的 ts 文件到本地,最后通过 ffmpeg 工具合并为 mp4。
一、遇到的坑
1、使用以下命令,在线下载并生成 mp4 时,文件过多时,中途会卡死。
ffmpeg -i http://ip:port/abc/index.m3u8 -c copy -bsf:a aac_adtstoasc output.mp4
解决办法:自己把所有的 ts 文件下载到本地,再合并。
2、循环使用 requests 下载多个文件时,卡死,其实是链接超时,但因为某种原因它既不报错也不退出。
解决办法:在 requests.get 中增加超时参数,重新链接。
3、本地合并时报“Invalid data found when processing input”错误。原因在于 ts 文件被加密。
解决办法:将 m3u8 中的 key 文件路径改为本地,并在 ffmpeg 中增加 -protocol_whitelist "file,http,https,crypto,tcp" 选项。
二、操作过程
1、下载 index.m3u8 文件到本地,通过 python 的 m3u8 模块读取解析,获得所有 ts 地址,并全部下载之。
2、下载 key 文件(地址在 m3u8 中)保存到本地当前目录,并修改 m3u8 中的 key 地址为当前目录。
3、修改 m3u8 中所有的 ts 文件地址为本地地址。
4、当前目录执行命令:
ffmpeg -allowed_extensions ALL -protocol_whitelist "file,http,https,crypto,tcp" -i index.m3u8 -c copy out.mp4
三、代码
import m3u8, requests
m3u8_file = 'index.m3u8'
start = 0
def get_ts(url):
i = 0
while i < 3:
try:
rep = requests.get(url, timeout=(5.05, 27)).content
return rep
except requests.exceptions.RequestException:
i += 1
def down_seg(i):
uri = data["segments"][i]['uri']
pos = uri.rfind('/')
ts_filename = uri[pos+1:]
print(i, ts_filename, "...", end='\t')
ts = get_ts(uri)
f = open('ts/'+ts_filename, 'wb')
f.write( ts )
f.close()
print('DONE')
data = m3u8.load(m3u8_file).data
for i in range(start, len(data["segments"])):
down_seg(i)