基本代码源自:

https://blog.csdn.net/s_kangkang_A/article/details/103071822。

感谢 s_kangkang_A

https://blog.csdn.net/s_kangkang_A

在此基础上继续进行了完善:

1、调整了 baseurl 的获取方式,直接从 m3u8 文件的路径中获取 baseurl,这样就把 所有参数 都可以拿到代码外面 进行输入,而无需 每次改代码了

2、改用了eventlet 绿色线程,提高了效率和网络速度

3、增加了 m3u8 的加密处理

4、修订了 存盘文件 名称,可以解决一些 网站使用特殊文件名的问题。

5、修订了 Queue 中的 轮空 的判定方法,改成了 标准 样式。原作的判定方法,曾经用过,特殊条件下会出错的。

还在继续努力的,设法能 直接 render 输入网址,自动得到 m3u8 文件,这样就是 全自动了。

需要用 python 3.7以上运行,否则requests就不能正常再 eventlet 中工作。

另外:eventlet 真的是个极品的 "线程"库。已经用了好多年。

# -*- coding: utf-8 -*-
from __future__ import print_function
from __future__ import absolute_importimport datetime
import os, sys
import re
import threading
#from eventlet.green import threading
import time
from urllib.parse import urlparse
#import requests
import eventletif sys.version_info.major < 3:import Queueimport ConfigParser as configparser
else:   import queue as Queueimport configparserrequests = eventlet.import_patched('requests')# 预下载,获取m3u8文件,读出ts链接,并写入文档
def down(headers, url, base_url):m3u8_dirname = os.path.dirname (url)m3u8_urlp = urlparse (url)# 当ts文件链接不完整时,需拼凑resp = requests.get(url, headers=headers)m3u8_text = resp.text# print(m3u8_text)# 按行拆分m3u8文档ts_queue = eventlet.queue.Queue()#ts_queue = eventlet.queue.LifoQueue ()#ts_queue = Queue(10000)lines = m3u8_text.split('\n')s = len(lines)# 找到文档中含有ts字段的行#concatfile = 'cache/' + "s" + '.txt'concatfile = 'cache/' + "decode" + '.m3u8'if os.path.exists(concatfile):os.remove(concatfile)s_count = 1for i,line in enumerate(lines):#if len(line) >=3 and line[-3:] == '.ts':if '.ts' in line:if 'http' in line:# print("ts>>", line)http_line = linepasselse:path = os.path.dirname (line)if len(path) == 0:http_line = m3u8_dirname + '/' + lineelse:http_line = m3u8_urlp.scheme + '://' + m3u8_urlp.netloc + '' + line#line = base_url + line#filename = re.search('([a-zA-Z0-9-_]+.ts)', line).group(1).strip()#filename = os.path.basename (line)filename = str(s_count).zfill(10)+'.ts'if not os.path.exists('cache/' +filename):#print ("  Add ", filename)#ts_queue.put(line)ts_queue.put ((filename, http_line, 0))else:#print ("  Had ", filename)pass# print('ts>>',line)# 一定要先写文件,因为线程的下载是无序的,文件无法按照# 123456。。。去顺序排序,而文件中的命名也无法保证是按顺序的# 这会导致下载的ts文件无序,合并时,就会顺序错误,导致视频有问题。#open(concatfile, 'a+').write("file %s\n" % filename)open(concatfile, 'a+').write("%s\n" % filename)#print("\r", '文件写入中', i, "/", s, end="", flush=True)s_count += 1print("\r", '写入中', s_count, "/", s, http_line, end="", flush=True)else:# 若发现了 加密 key,则把 key 本地化key_re = re.search ("(URI=\".*\.key\")", line)if key_re != None:key_url = key_re.group(1).strip()key_url = key_url[5:-1]path = os.path.dirname (key_url)if len(path) == 0:http_key = m3u8_dirname + '/' + key_urlelse:http_key = m3u8_urlp.scheme + '://' + m3u8_urlp.netloc + '' + key_urlkey_line = line[:key_re.start()+5] + "key.key" + line[key_re.end()-1:]print (line, key_url, http_key, key_line,"\n")key_r = requests.get(http_key, stream=True, headers=headers, timeout=(15, 60), verify=True)with open('cache/key.key', 'wb') as fp:for chunk in key_r.iter_content(5242):if chunk:fp.write(chunk)open(concatfile, 'a+').write(key_line+"\n")else:                open(concatfile, 'a+').write(line+"\n")return ts_queue, concatfile# 线程模式,执行线程下载
def run(ts_queue, headers, pool):while True:try:#url, sleepTime = ts_queue.get (True, 0.5)filename, url, sleepTime = ts_queue.get (True, 0.5)except Queue.Empty :breakif sleepTime > 0:eventlet.sleep (sleepTime)#filename = re.search('([a-zA-Z0-9-_]+.ts)', url).group(1).strip()#filename = os.path.basename (url)requests.packages.urllib3.disable_warnings()try:r = requests.get(url, stream=True, headers=headers, timeout=(15, 60), verify=False)r.raise_for_status ()with open('cache/' + filename, 'wb') as fp:for chunk in r.iter_content(5242):if chunk:fp.write(chunk)print("\r", '任务文件 ', filename, ' 下载成功', pool.running(), ts_queue.qsize(), end="         ", flush=True)except Exception as exc:print( '任务文件 ', filename, ' 下载失败, 代码:', exc)ts_queue.put((filename, url, 5))#eventlet.sleep (2)#return True# 视频合并方法,使用ffmpeg
def merge(concatfile, name):try:#path = 'cache/' + name + '.mp4'path = 'e:/rm/80s/' + name + '.mp4'# command = 'ffmpeg -y -f concat -i %s -crf 18 -ar 48000 -vcodec libx264 -c:a aac -r 25 -g 25 -keyint_min 25 -strict -2 %s' % (concatfile, path)command  = "ffmpeg -allowed_extensions ALL -protocol_whitelist \"file,http,crypto,tcp\" "#command += ' -y -f concat -i %s -bsf:a aac_adtstoasc -c copy %s' % (concatfile, path)command += ' -y -i %s -bsf:a aac_adtstoasc -c copy %s' % (concatfile, path)print (command)os.system(command)print('视频合并完成')except:print('合并失败')def remove():dir = 'cache/'"""#for line in open('cache/s.txt'):for line in open('cache/decode.m3u8'):#line = re.search('file (.*?ts)', line).group(1).strip()line = re.search('(.*?ts)', line).group(1).strip()# print(line)os.remove(dir + line)print("ts文件全部删除")try:os.remove('cache/s.txt')print('文件删除成功')except:print('文件删除失败')"""command = "del " + dir + "*/Q"os.system(command)# headers 和 base_url 必须根据实际网站 !手动 ! 设置
if __name__ == '__main__':# 测试用链接:https://yiyi.55zuiday.com/ppvod/70B5A6E3A150A99882E28EC793CAF519.m3u8 # 链接电影:地球最后的夜晚# https://youku.com-ok-sohu.com/20191110/20128_fd24c5a9/1000k/hls/61033a1fdc2000000.ts#base_url = 'https://yiyi.55zuiday.com/'base_url = 'http://cn5.download05.com/hls/20190721/e7339c09fff1c6c817c2b3cfad9b1d39/1563674290/film_00000.ts'headers = {#'referer': 'https://yiyi.55zuiday.com/share/wVuAcJFy1tMy4t0x','referer': 'http://www.douying99.com/play/47309_m3u8_0.html','user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36'}requests.adapters.DEFAULT_RETRIES = 5name = input('请输入视频名称:')headers['referer'] = input('请输入网页链接:').strip()url = input('请输入视频m3u8链接:').strip()start = datetime.datetime.now().replace(microsecond=0)print("目录文件开始写入")s, concatfile = down(headers, url, base_url)print('\n')print("目录文件写入结束")# 获取队列元素数量t_num = s.qsize()# 根据数量来开线程数,每五个元素一个线程# 最大开到50个print("下载任务开始")"""if num > 5:t_num = num // 5else:t_num = 1"""if t_num > 60:t_num = 60# print(s,concatfile)pool = eventlet.GreenPool(t_num)run_args={'ts_queue': s, 'headers': headers, 'pool': pool}for i in range(t_num):pool.spawn_n (run, **run_args)pool.waitall()"""threads = []for i in range(t_num):t = threading.Thread(target=run, name='th-' + str(i), kwargs={'ts_queue': s, 'headers': headers})t.setDaemon(True)threads.append(t)for t in threads:time.sleep(0.4)t.start()for t in threads:t.join()"""print('\n')print("下载任务结束")end = datetime.datetime.now().replace(microsecond=0)print('写文件及下载耗时:' + str(end - start))merge(concatfile, name)remove()over = datetime.datetime.now().replace(microsecond=0)print('合并及删除文件耗时:' + str(over - end))print("所有任务结束 ", name)print('任务总时长:', over - start)

python 实现多线程下载m3u8格式视频,使用FFmpeg合并(升级修订自s_kangkang_A)相关推荐

  1. python多线程下载m3u8文件,python 实现多线程下载m3u8格式视频并使用fmmpeg合并

    如何把m3u8格式转换成mp4格式? 可以按照如下方式进行操作: 抑郁的人在水底,正常人在水面,小编沉浮在中间,上不去也下不来. 手机上面找到m3u8格式文件的存储位置,在打开方式里边选择" ...

  2. python多线程下载视频_python 实现多线程下载m3u8格式视频并使用fmmpeg合并

    电影之类的长视频好像都用m3u8格式了,这就导致了多线程下载视频的意义不是很大,都是短视频,线不线程就没什么意义了嘛. 我们知道,m3u8的链接会下载一个文档,相当长,半小时的视频,应该有接近千行ts ...

  3. 【python】多线程下载m3u8分段视频

    1.说明 m3u8是一种传输数据的方式,比如说一集20分钟的完整视频被分割成一千多段一两秒的小视频,客户端播放的时候是感觉是连续,但如果你要下载这集视频,那就要把一千多个小视频全都下载然后自己拼接成一 ...

  4. 多线程下载m3u8影视资源 通过ffmpeg合并ts文件为mp4

    需要用到的ffmpeg,下载地址:Download FFmpeg  下载以后的目录. 合并.转换.切片都用到了ffmpeg.exe,其它两个我暂时没用到. <dependency>< ...

  5. python下载大文件mp4_Python 下载 m3u8 格式视频

    Python requests 下载 m3u8 格式 视频 最近爬取一个视频网站,遇到 m3u8 格式的视频需要下载. 抓包分析,视频文件是多个 ts 文件,什么是 ts文件,请去百度吧: 附图:抓包 ...

  6. python下载m3u8视频_使用python 下载m3u8格式视频,并使用ffmpeg 合成视频

    使用python 下载m3u8格式视频,并合成 # -*- coding: utf-8 -*- # Created on 2018/07/26 import os import requests &q ...

  7. python爬取下载m3u8加密视频,原来这么简单!

    1.前言 爬取视频的时候发现,现在的视频都是经过加密(m3u8),不再是mp4或者avi链接直接在网页显示,都是经过加密形成ts文件分段进行播放. 今天就教大家如果通过python爬取下载m3u8加密 ...

  8. 如何优雅的批量下载m3u8 格式视频

    我们去很多网站上 去下载视频,解析出的地址 是m3u8格式视频, 使用 普通的下载方式下载就是一个m3u8文件.里面装的是一段一段的视频.一方面,不做特殊处理播放器可能播放不了,另一方面该格式可能是加 ...

  9. Python编程:封装M3U8格式视频下载类

    一.前言 m3u8是苹果公司推出的视频播放标准,是m3u的一种,只是编码格式采用的是UTF-8. m3u8准确来说是一种索引文件,使用m3u8文件实际上是通过它来解析对应的放在服务器上的视频网络地址, ...

最新文章

  1. 不得不爱开源 Wijmo jQuery 插件集(4)-【手风琴效果】(附页面展示和源码)
  2. python扩展库不是用于科学计算的有_有哪些科学计算的开源库
  3. 协议详解_I2C协议详解
  4. 在Linux上将视频转换成动态gif图片 (附:ffmpeg和ImageMagick安装方法)
  5. 新手小白之学习python一飞冲天日志之—基本数据类型,条件控制语句
  6. 拓端tecdat|R语言生态学建模:增强回归树(BRT)预测短鳍鳗生存分布和影响因素
  7. 学渣的c#复习手记 类 一
  8. 番茄助手在VS2017中的设置
  9. 简单的 OpenGL 纹理贴图不起作用?
  10. FastFDS--文件服务系统
  11. 图片转换成文字并导出的方法
  12. STM32比较器的使用
  13. Java中常见的5种WEB服务器介绍以及性能配置要点总结
  14. 将image对象转成BufferedImage
  15. 在chrome中f12控制自动刷新页面增加阅读量方法
  16. 深算院入选“数字政府建设赋能计划”成员单位
  17. Linux2--修改root密码,文件操作
  18. Tableau疫情可视化
  19. 计算长方体体积(3分)
  20. Python教你每把轻松吃鸡

热门文章

  1. 【老生谈算法】matlabAP近邻传播聚类算法源码——聚类算法
  2. [变分法介绍]优美的旋轮线:最速下降线问题,通过费马光学原理的初等证明
  3. HDU 4513 吉哥系列故事――完美队形II(Manacher)
  4. mac 重启 ssh 服务
  5. cut out数据增强_数据增强:Mixup,Cutout,CutMix | Mosaic
  6. python切分数据集_Python数据集切分实例
  7. 100天精通Andriod逆向——第2天:Android基础知识和jadx的使用
  8. jadx在windows下的安装
  9. 数据科学与大数据技术和计算机科学与技术哪个好
  10. 海德汉LSV2通讯协议