python 玩转m3u8视频
最近在捣鼓视频转码,所谓好记性不如烂笔头,索性把想到的知识点都记录在案吧
现在大多数网站都使用m3u8格式的视频文件,一是体积小,传输快;二是可以切片,提高用户体验。
好了,废话不多说,开始今天的主题:
假如我们在网站上看到一个好的视频,我们想下载下来,怎么办??那这篇文章可以帮助到你(不过你要会使用pthon啊,骚年~~)
先放一张流程图:
具体就分这4步,概括一下就是在浏览器中找到这个m3u8文件,下载里面所有的ts文件,最后将所有的ts文件合并为mp4视频。
完整上码
1 import re 2 import requests, os 3 project_path = os.path.abspath(os.path.dirname(__file__)) 4 video_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'video')) 5 6 7 class VideoSynthesis: 8 def __init__(self): 9 self.header = { 10 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36' 11 } 12 self.m3u8_link = 'https://v.pinimg.com/videos/v2/hls/49/3e/6b/493e6bb3f832caf2bef872d648698ff4_hls480w.m3u8' 13 self.base_url = 'https://v.pinimg.com/videos/v2/hls/49/3e/6b/' 14 15 def get_m3u8_link(self): 16 # 下载m3u8视频 17 m3u8_response = requests.get(url=self.m3u8_link, headers=self.header, verify=False) 18 print(m3u8_response.text) 19 return m3u8_response 20 21 def handle_m3u8_response(self, m3u8_response): 22 # 处理m3u8响应 23 ts_filename = re.findall('.*?EXTINF:.*?,\n(.*?)\n', m3u8_response.replace(' ', '').replace(r'\n', '')) 24 print(f'tslist: {ts_filename}') 25 ts_link_list = [] 26 for item in ts_filename: 27 result_url = self.base_url + item 28 ts_link_list.append(result_url) 29 print(f'ts_link_list: {ts_link_list}') 30 return ts_link_list, ts_filename 31 32 def download_ts_video(self, ts_url_list, ts_filename): 33 # 通过ts链接下载ts文件 34 for i in range(len(ts_url_list)): 35 ts_url = ts_url_list[i] 36 ts_name = ts_filename[i] 37 try: 38 response = requests.get(ts_url, stream=True, verify=False) 39 except Exception as e: 40 print("异常请求:%s" % e.args) 41 return 42 43 # 在当前目录下创建个video文件夹 44 ts_path = project_path + r"\video\{}".format(ts_name) 45 with open(ts_path, "wb+") as file: 46 for chunk in response.iter_content(chunk_size=1024): 47 if chunk: 48 file.write(chunk) 49 print("TS文件下载完毕!!") 50 51 def heBingTsVideo(self): 52 # 视频合成 53 hebing_path = video_path + r"\m3u8_video.mp4" 54 print(hebing_path) 55 all_ts = os.listdir(video_path) 56 with open(hebing_path, 'wb+') as f: 57 for i in range(len(all_ts)): 58 ts_video_path = os.path.join(video_path, all_ts[i]) 59 f.write(open(ts_video_path, 'rb').read()) 60 print("合并完成!!") 61 62 def run(self): 63 m3u8_response = self.get_m3u8_link() 64 ts_link_list, ts_filename = self.handle_m3u8_response(m3u8_response) 65 66 # ts_link_list = ['https://v.pinimg.com/videos/v2/hls/49/3e/6b/493e6bb3f832caf2bef872d648698ff4_hls480w00000.ts', 'https://v.pinimg.com/videos/v2/hls/49/3e/6b/493e6bb3f832caf2bef872d648698ff4_hls480w00001.ts', 'https://v.pinimg.com/videos/v2/hls/49/3e/6b/493e6bb3f832caf2bef872d648698ff4_hls480w00002.ts', 'https://v.pinimg.com/videos/v2/hls/49/3e/6b/493e6bb3f832caf2bef872d648698ff4_hls480w00003.ts'] 67 # ts_filename = ['493e6bb3f832caf2bef872d648698ff4_hls480w00000.ts', '493e6bb3f832caf2bef872d648698ff4_hls480w00001.ts' ,'493e6bb3f832caf2bef872d648698ff4_hls480w00002.ts', '493e6bb3f832caf2bef872d648698ff4_hls480w00003.ts'] 68 69 self.download_ts_video(ts_link_list, ts_filename) 70 self.heBingTsVideo() 71 72 73 if __name__ == '__main__': 74 video_synthesis = VideoSynthesis() 75 video_synthesis.run()
视频下载完以后,可能还会遇到压缩,合并问题,那这时候就要用到ffmpeg 这个神器了,直接编写一个脚本就完事了~
1 # coding=utf-8 2 3 import os 4 5 NEW_RESOLUTION = "640x480" # 目标分辨率,常量 6 NEW_FPS = 12 # 目标帧率,常量 7 8 curpath = os.getcwd() # 获取当前路径 9 input_dir = os.path.join(curpath, "Input_Video") 10 output_dir = os.path.join(curpath, "Output_Video") 11 input_video_list = os.listdir(input_dir) # 获取视频列表 12 13 # 如果没有Output_Video这个文件夹,则创建这个文件夹 14 if not os.path.exists(output_dir): 15 os.mkdir(output_dir) 16 17 # 开始批量二次编码压缩视频转码 18 for each_video in input_video_list: 19 video_name, _ = os.path.splitext(each_video) # _是没意义,就只是一个无用代号,占个坑而已 20 ffmpeg_command = ("ffmpeg -i %s%s%s -s %s -r %s -y %s%s%s_c.mp4" % ( 21 input_dir, os.sep, each_video, NEW_RESOLUTION, NEW_FPS, output_dir, os.sep, video_name)) 22 print(ffmpeg_command) 23 os.system(ffmpeg_command) 24 25 os.system("pause")
注意:这里调用的是系统指令,所以务必使你的ffmpeg.exe执行程序能够被访问到,放到系统全局变量路径下面即可。
视频合并
1 ffmpeg -f concat -i filelist.txt -c copy output.mp4
filelist.txt为ffmpeg同级目录下新建记事本,名字随意,而里面的内容长这个样子
file 's1-1.mp4' file 's1-2.mp4' file 's1-3.mp4'
注意,如果用这种方式,那么这3个文件也必须存放在同级目录下。如果想使用全路径的形式,比如:file D:\s1\2.mp4'
则应使用下面这条命令
ffmpeg -f concat -safe 0 -i filelist.txt -c copy output.mp4 -- -safe 0 授权进入
参考文章 https://blog.csdn.net/weixin_38640052/article/details/119680697
https://blog.csdn.net/human_soul/article/details/103263573
https://www.cnblogs.com/zipython/p/12920095.html
https://jingyan.baidu.com/article/2a138328517dce464b134f24.html
https://blog.csdn.net/winniezhang/article/details/89260841