热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

m3u8转mp4缓存合并工厂_使用Python下载M3U8格式视频

作者简介本篇文章来自MRArchive的投稿,分享了如何使用Python下载M3U8格式的视频,希望对大家有所帮助!同时也感谢作者贡献的精
543ed0bc37b628392e130b51134f8e63.png

/  作者简介  /

本篇文章来自 MRArchive 的投稿,分享了如何使用Python下载M3U8格式的视频,希望对大家有所帮助!同时也感谢作者贡献的精彩文章。

作者信息

网站:https://toodo.fun

B站:https://space.bilibili.com/314191627

/  背景简介  /

M3U 是一种播放多媒体列表的文件格式,它的设计初衷是为了播放音频文件,比如MP3,但是越来越多的软件现在用来播放视频文件列表,M3U也可以指定在线流媒体音频源。很多播放器和软件都支持M3U文件格式。

m3u8 文件是 HTTP Live Streaming(缩写为 HLS) 协议的部分内容,而 HLS 是一个由苹果公司提出的基于 HTTP 的流媒体网络传输协议。

HLS 是新一代流媒体传输协议,其基本实现原理为将一个大的媒体文件进行分片,将该分片文件资源路径记录于 m3u8 文件(即 playlist)内,其中附带一些额外描述(比如该资源的多带宽信息···)用于提供给客户端。客户端依据该 m3u8 文件即可获取对应的媒体资源,进行播放。

扩展M3U指令:

#EXTM3U //必需,表示一个扩展的m3u文件

#EXT-X-VERSION:3 //hls的协议版本号,暗示媒体流的兼容性

#EXT-X-MEDIA-SEQUENCE:xx //首个分段的sequence number

#EXT-X-ALLOW-CACHE:NO //是否缓存

#EXT-X-TARGETDURATION:5 //每个视频分段最大的时长(单位秒)

#EXT-X-DISCONTINUITY //表示换编码

#EXTINF: //每个切片的时长

/  获取.m3u8文件中的视频信息  /

.m3u8文件储存了视频所在的位置信息,我们可以通过发送一个Get请求来获取链接中的内容:

content = requests.get(m3u8Url).text

/  拼接视频下载链接  /

我们通过得到的视频信息进行视频网址拼接,.m3u8文件中的链接可以为全路径或者相对路径,所以我们判断后进行拼接并存入一个列表当中:

urls = []for index, video in enumerate(content.split('\n')): if '#EXTINF' in video: if content[index + 1][0] == '/': downloadLink = url.split('//')[0] + "//" + url.split('//')[1].split('/')[0] + content[index + 1] elif content[index + 1][:4] == 'http': downloadLink = content[index + 1] else: downloadLink = url.replace(url.split('/')[-1], content[index + 1]) urls.append(downloadLink)

/  使用多线程下载视频  /

得到视频列表后,我们就可以对视频进行下载了,为了提高下载效率,我们可以使用多线程进行下载:

def download(downloadLink, name): for _ in range(10): try: req = requests.get(downloadLink, headers=headers, timeout=15).content with open(f"{name}", "wb") as f: f.write(req) f.flush() break except: if _ == 9: print(f"{name}下载失败") else: print(f"{name}正在进行第{_}次重试")pool = ThreadPoolExecutor(max_workers=threadNum)futures = []for index, downloadLink in enumerate(urls): fileList.append(os.path.basename(downloadLink)) futures.append(pool.submit(download, downloadLink, f"{downloadPath}/{os.path.basename(downloadLink)}"))wait(futures)

/  合并视频  /

等待全部下载完成后,是一个个的ts视频文件,然后我们再将这些文件合并成一个视频文件,此时要注意视频的顺序,我们可以在我们的视频列表中依次取出进行合并

def merge_file(path, name): global fileList cmd = "copy /b " for i in fileList: if i != fileList[-1]: cmd += f"{i} + " else: cmd += f"{i} {name}" os.chdir(path) with open('combine.cmd', 'w') as f: f.write(cmd) os.system("combine.cmd") os.system('del /Q *.ts') os.system('del /Q *.cmd')

这里我们是写了一个脚本来完成合并的任务,使用命令'copy /b file1 + file2 +... + fileN newFile'进行合并,并于完成后将ts小文件进行了删除。至此,视频就下载完成了。

/  完整代码如下  /

import requestsimport osfrom concurrent.futures import ThreadPoolExecutor, waitimport sysfinishedNum = 0allNum = 0fileList = []headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0'}def download(downloadLink, name): global finishedNum global allNum for _ in range(10): try: req = requests.get(downloadLink, headers=headers, timeout=15).content with open(f"{name}", "wb") as f: f.write(req) f.flush() finishedNum += 1 print(f"{name}下载成功, 总进度{round(finishedNum / allNum * 100, 2)}% ({finishedNum}/{allNum})") break except: if _ == 9: print(f"{name}下载失败") else: print(f"{name}正在进行第{_}次重试")def merge_file(path, name): global fileList cmd = "copy /b " for i in fileList: if i != fileList[-1]: cmd += f"{i} + " else: cmd += f"{i} {name}" os.chdir(path) with open('combine.cmd', 'w') as f: f.write(cmd) os.system("combine.cmd") os.system('del /Q *.ts') os.system('del /Q *.cmd')def downloader(url, name, threadNum): global allNum global fileList print("读取文件信息中...") downloadPath = 'Download' if not os.path.exists(downloadPath): os.mkdir(downloadPath) # 查看是否存在 if os.path.exists(f"{downloadPath}/{name}"): print(f"视频文件已经存在,如需重新下载请先删除之前的视频文件") return content = requests.get(url, headers=headers).text.split('\n') if "#EXTM3U" not in content[0]: raise BaseException(f"非M3U8链接") # .m3u8 跳转 for video in content: if ".m3u8" in video: if video[0] == '/': url = url.split('//')[0] + "//" + url.split('//')[1].split('/')[0] + video elif video[:4] == 'http': url = video else: url = url.replace(url.split('/')[-1], video) print(url) content = requests.get(url, headers=headers).text.split('\n') urls = [] for index, video in enumerate(content): if '#EXTINF' in video: if content[index + 1][0] == '/': downloadLink = url.split('//')[0] + "//" + url.split('//')[1].split('/')[0] + content[index + 1] elif content[index + 1][:4] == 'http': downloadLink = content[index + 1] else: downloadLink = url.replace(url.split('/')[-1], content[index + 1]) urls.append(downloadLink) allNum = len(urls) pool = ThreadPoolExecutor(max_workers=threadNum) futures = [] for index, downloadLink in enumerate(urls): fileList.append(os.path.basename(downloadLink)) futures.append(pool.submit(download, downloadLink, f"{downloadPath}/{os.path.basename(downloadLink)}")) wait(futures) print(f"运行完成") merge_file(downloadPath, name) print(f"合并完成") print(f"文件下载成功,尽情享用吧")if __name__ == '__main__': videoUrl = str(sys.argv[1]) name = str(sys.argv[2]) threadNum = int(sys.argv[3]) downloader(videoUrl, name, threadNum)

/  打包好的Windows版软件下载  /

百度云下载地址:https://pan.baidu.com/s/1ZsPb9WTmYP8VUKuR9tuoyw 提取码:mxb6

蓝奏云下载地址:https://lanzous.com/icnc1ve




推荐阅读
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • Vagrant虚拟化工具的安装和使用教程
    本文介绍了Vagrant虚拟化工具的安装和使用教程。首先介绍了安装virtualBox和Vagrant的步骤。然后详细说明了Vagrant的安装和使用方法,包括如何检查安装是否成功。最后介绍了下载虚拟机镜像的步骤,以及Vagrant镜像网站的相关信息。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了在处理不规则数据时如何使用Python自动提取文本中的时间日期,包括使用dateutil.parser模块统一日期字符串格式和使用datefinder模块提取日期。同时,还介绍了一段使用正则表达式的代码,可以支持中文日期和一些特殊的时间识别,例如'2012年12月12日'、'3小时前'、'在2012/12/13哈哈'等。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • LVS实现负载均衡的原理LVS负载均衡负载均衡集群是LoadBalance集群。是一种将网络上的访问流量分布于各个节点,以降低服务器压力,更好的向客户端 ... [详细]
  • 本文介绍了Java后台Jsonp处理方法及其应用场景。首先解释了Jsonp是一个非官方的协议,它允许在服务器端通过Script tags返回至客户端,并通过javascript callback的形式实现跨域访问。然后介绍了JSON系统开发方法,它是一种面向数据结构的分析和设计方法,以活动为中心,将一连串的活动顺序组合成一个完整的工作进程。接着给出了一个客户端示例代码,使用了jQuery的ajax方法请求一个Jsonp数据。 ... [详细]
author-avatar
那是黑夜过后的黎明_182
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有