【python】M3U8下载器脚本

脚本目标:

    1. 输入M3U8文件的链接,得到视频

    2.使用异步操作,这样可以快很多,不加锁,因为懒得写,而且影响不大

已知条件:

    1.m3u8文件其实就是一个记录了ts文件下载链接的工具文件,每个ts文件就是视频的一部分,把所有ts文件下载下来,合并就可以得到完整的视频

脚本思路:

    1.创建一个文件夹,用来存放下载好的m3u8文件和下载好的ts文件

    2.下载并打开m3u8文件,根据m3u8文件下载ts文件,这边设计了两种情况,a.ts的下载链接是完整的 b.ts的下载链接是需要拼接的

    3.根据m3u8文件自动校验文件是否下载完整

    4.由于很多时候ts文件的命名是没有规律的,所以再次打开m3u8文件,根据里面的顺序,以追加的形式写入到一个新的ts文件里

代码实现:

  先创建好文件夹,这边使用了相对路径

def init():
if os.path.exists("./temp_data"):
return
else:
os.mkdir("./temp_data")

  得到m3u8下载链接,获得m3u8文件名,这边假设是https://xxxxxxx126.net/nos/hls/2019/03/13/1214418271_9xxxxxxx32465d1f4c8_sd.m3u8,那么就设置“1214418271_9xxxxxxx32465d1f4c8_sd.m3u8”为文件名

url =str(input("输入m3u8文件url >"))
name = url.rsplit("/")[-1]

  下载m3u8文件

def m3u8_files_download(url,name):   #下载m3u8文件
resp = requests.get(url)
with open(f"temp_data/{name}.txt",mode="wb") as f:
f.write(resp.content)
resp.close()

  给出第一个ts的下载链接,用户自己判断一下是需要拼接的,还是无需拼接的完整url

def get_type(name):
with open(f"temp_data/{name}.txt","r") as f:
for line in f:
if line.startswith("#"):
continue
else:
print("内容为:",line)
print("选择模式: 1.直接下载型 2.拼接型")
choice = input(">")
return str(choice)

  写一个启动器,根据不同的选择,创建不同的任务,创建的任务为异步任务

async def starter(choice,name):
tasks=[]
async with aiohttp.ClientSession() as session:
if choice =="1":
with open(f"/temp_data/{name}.txt","r") as f:
for line in f:
if line.startswith("#"):
continue
else:
download_url = line.strip()
line = line.split("/")
file_name = str(line[-1]).strip() # 得下载的ts文件名
task = download_ts(file_name,download_url,session)
tasks.append(task)
print("文件下载中.....")
await asyncio.wait(tasks) # 等待任务执行结束
print("文件下载完成")
if choice=="2":
url = str(input("输入拼接的url>"))
with open(f"temp_data/{name}.txt","r") as f:
for line in f:
if line.startswith("#"):
continue
else:
line = line.strip()
file_name = line # 得下载的ts文件名
download_url = url+line
task = download_ts(file_name,download_url,session)
tasks.append(task)
print("文件下载中.....")
await asyncio.wait(tasks) # 等待任务执行结束
print("文件下载完成")

  下载ts文件,用aiohttp来代理requests

async def aio_download_ts(download_url,line_name,session):
async with session.get(download_url,headers=header) as resp:
async with aiofiles.open(f"temp_data/{line_name}",mode="wb") as f:
await f.write(await resp.content.read())
print(f"文件{line_name}下载完成!!")

  校验文件的完整性:依据m3u8文件,判断文件是否存在

def verification(name):
files=[]
with open(f"temp_data/{name}.txt","r") as f:
for line in f:
if line.startswith("#"):
continue
else:
line=line.strip()
if os.path.exists(f"temp_data/{line}"):
continue
else:
files.append(line)
print("以下文件缺失,请手动查看:",files)

  合并文件,实现的方式时创建一个ts文件,依据m3u8文件里的文件顺序,依次将二进制文件写入到新的ts文件里

def merge_ts(file_name):
new_name = str(input("输入合并后的文件名>"))
with open(f"./{new_name}.ts", "ab+") as f:
with open(f"temp_data/{file_name}.txt","r") as f2:
for line in f2:
if line.startswith("#"):
continue
else:
line = line.strip().split("/")[-1].strip()
ts_name = line
try:
with open(f"temp_data/{ts_name}","rb") as f3:
f.write(f3.read())
except:
continue

  最后再写一个主函数,执行这一切

def main():
init()
url =str(input("输入m3u8文件url >"))
name = url.rsplit("/")[-1]
m3u8_files_download(url,name)#下载m3u8文件
choice=get_type(name)
asyncio.run(starter(choice,name))
print("校验文件完整性")
verification(name)
print("是否合并文件? Y/N")
if str(input(">"))=="Y":
merge_ts(name)
else:
print("结束")

最终功能代码

import aiohttp
import aiofiles
import asyncio
import requests
import os
header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36"}
def merge_ts(file_name):
new_name = str(input("输入合并后的文件名>"))
with open(f"./{new_name}.ts", "ab+") as f:
with open(f"temp_data/{file_name}.txt","r") as f2:
for line in f2:
if line.startswith("#"):
continue
else:
line = line.strip().split("/")[-1].strip()
ts_name = line
try:
with open(f"temp_data/{ts_name}","rb") as f3:
f.write(f3.read())
except:
continue
async def aio_download_ts(download_url,line_name,session):
async with session.get(download_url,headers=header) as resp:
async with aiofiles.open(f"temp_data/{line_name}",mode="wb") as f:
await f.write(await resp.content.read())
print(f"文件{line_name}下载完成!!")
def m3u8_files_download(url,name): #下载m3u8文件
resp = requests.get(url)
with open(f"temp_data/{name}.txt",mode="wb") as f:
f.write(resp.content)
resp.close()
def get_type(name):
with open(f"temp_data/{name}.txt","r") as f:
for line in f:
if line.startswith("#"):
continue
else:
print("内容为:",line)
print("选择模式: 1.直接下载型 2.拼接型")
choice = input(">")
return str(choice)
def init():
if os.path.exists("./temp_data"):
return
else:
os.mkdir("./temp_data")
def verification(name):
files=[]
with open(f"temp_data/{name}.txt","r") as f:
for line in f:
if line.startswith("#"):
continue
else:
line=line.strip()
if os.path.exists(f"temp_data/{line}"):
continue
else:
files.append(line)
print("以下文件缺失,请手动查看:",files)
async def download_ts(file_name,download_url,session): async with session.get(download_url,headers=header) as resp:
async with aiofiles.open(f"temp_data/{file_name}",mode="wb") as f:
await f.write(await resp.content.read()) async def starter(choice,name):
tasks=[]
async with aiohttp.ClientSession() as session:
if choice =="1":
with open(f"/temp_data/{name}.txt","r") as f:
for line in f:
if line.startswith("#"):
continue
else:
download_url = line.strip()
line = line.split("/")
file_name = str(line[-1]).strip() # 得下载的ts文件名
task = download_ts(file_name,download_url,session)
tasks.append(task)
print("文件下载中.....")
await asyncio.wait(tasks) # 等待任务执行结束
print("文件下载完成")
if choice=="2":
url = str(input("输入拼接的url>"))
with open(f"temp_data/{name}.txt","r") as f:
for line in f:
if line.startswith("#"):
continue
else:
line = line.strip()
file_name = line # 得下载的ts文件名
download_url = url+line
task = download_ts(file_name,download_url,session)
tasks.append(task)
print("文件下载中.....")
await asyncio.wait(tasks) # 等待人物执行结束
print("文件下载完成") def main():
init()
url =str(input("输入m3u8文件url >"))
name = url.rsplit("/")[-1]
m3u8_files_download(url,name)#下载m3u8文件
choice=get_type(name)
asyncio.run(starter(choice,name))
print("校验文件完整性")
verification(name)
print("是否合并文件? Y/N")
if str(input(">"))=="Y":
merge_ts(name)
else:
print("结束")
main()

使用自欺欺人术,直接把ts文件后缀改成MP4,看着舒服点。

实现效果

视频打开能正常观看,脚本完成

后记:关于脚本的使用

  理论上把aiohttp,aiofiles,asyncio三个库安装好,复制粘贴应该就可以直接用,也可以把一些需要手工提供的量,在脚本中写死,以在不同的爬虫中使用。

ENDING..........

【python】M3U8下载器脚本的更多相关文章

  1. 以下三种下载方式有什么不同?如何用python模拟下载器下载?

    问题始于一个链接https://i1.pixiv.net/img-zip-...这个链接在浏览器打开,会直接下载一个不完整的zip文件 但是,使用下载器下载却是完整文件 而当我尝试使用python下载 ...

  2. python动态视频下载器

    这里向大家分享一下python爬虫的一些应用,主要是用爬虫配合简单的GUI界面实现视频,音乐和小说的下载器.今天就先介绍如何实现一个动态视频下载器. 爬取电影天堂视频 首先介绍的是python爬取电影 ...

  3. 用python实现的百度音乐下载器-python-pyqt-改进版

    之前写过一个用python实现的百度新歌榜.热歌榜下载器的博文,实现了百度新歌.热门歌曲的爬取与下载.但那个采用的是单线程,网络状况一般的情况下,扫描前100首歌的时间大概得到40来秒.而且用Pyqt ...

  4. Python实现多线程HTTP下载器

    本文将介绍使用Python编写多线程HTTP下载器,并生成.exe可执行文件. 环境:windows/Linux + Python2.7.x 单线程 在介绍多线程之前首先介绍单线程.编写单线程的思路为 ...

  5. 用 python 实现一个多线程网页下载器

    今天上来分享一下昨天实现的一个多线程网页下载器. 这是一个有着真实需求的实现,我的用途是拿它来通过 HTTP 方式向服务器提交游戏数据.把它放上来也是想大家帮忙挑刺,找找 bug,让它工作得更好. k ...

  6. [python]非常小的下载图片脚本(非通用)

    说在最前面:这不是一个十分通用的下载图片脚本,只是根据我的一个小问题,为了减少我的重复性工作写的脚本. 问题 起因:我的这篇博文什么是真正的程序员浏览量超过了4000+. 问题来了:里面的图片我都是用 ...

  7. 【图文详解】python爬虫实战——5分钟做个图片自动下载器

    python爬虫实战——图片自动下载器 之前介绍了那么多基本知识[Python爬虫]入门知识,(没看的先去看!!)大家也估计手痒了.想要实际做个小东西来看看,毕竟: talk is cheap sho ...

  8. Python实战:美女图片下载器,海量图片任你下载

    Python应用现在如火如荼,应用范围很广.因其效率高开发迅速的优势,快速进入编程语言排行榜前几名.本系列文章致力于可以全面系统的介绍Python语言开发知识和相关知识总结.希望大家能够快速入门并学习 ...

  9. python多进程断点续传分片下载器

    python多进程断点续传分片下载器 标签:python 下载器 多进程 因为爬虫要用到下载器,但是直接用urllib下载很慢,所以找了很久终于找到一个让我欣喜的下载器.他能够断点续传分片下载,极大提 ...

随机推荐

  1. Java 8的18个常用日期处理

    Java 8的18个常用日期处理 一.简介 伴随 lambda表达式.streams 以及一系列小优化,Java 8 推出了全新的日期时间API. Java处理日期.日历和时间的不足之处:将 java ...

  2. DH问题汇总

    本节内容主要转载于:弄清楚DL,D-H,CDH problem,CDH assumption,DDH,BDDH,BCDH. DLP(Discrete Logarithm Problem) 在乘法群\( ...

  3. .net core JWT验证,HttpContext.User为空的问题

    这几天在学习张老师.net core教程JWT部分,链接 https://mp.weixin.qq.com/s/7135y3MkUlPIp-flfwscig 教程使用的.net core 2.2, 在 ...

  4. Event Loop 是什么?

    Event Loop 是什么? 本文写于 2020 年 12 月 6 日 广义上来说 Event Loop 并不是 JavaScript 独有的概念,他是一个计算机的通用概念. 狭义上来说,只有 No ...

  5. 877. Stone Game - LeetCode

    Question 877. Stone Game Solution 题目大意: 说有偶数个数字,alex和lee两个人比赛,每次轮流从第一个数字或最后一个数字中拿走一个(偶数个数字,所以他俩拿的数字个 ...

  6. 438. Find All Anagrams in a String - LeetCode

    Question 438. Find All Anagrams in a String Solution 题目大意:给两个字符串,s和p,求p在s中出现的位置,p串中的字符无序,ab=ba 思路:起初 ...

  7. Nginx基本配置与应用

    一.准备 1.1 环境准备 CentOS7软件环境 1.2 tomcat多实例 把/etc/profile.d/tomcat.sh中的变量注释了 #export TOMCAT_HOME=/usr/lo ...

  8. [SQLServer]NetCore中将SQLServer数据库备份为Sql脚本

    NetCore中将SQLServer数据库备份为Sql脚本 描述: 最近写项目收到了一个需求, 就是将SQL Server数据库备份为Sql脚本, 如果是My Sql之类的还好说, 但是在网上搜了一大 ...

  9. 每天一个 HTTP 状态码 204

    204 No Content 204 No Content 表示服务器成功地处理了客户端的请求,但是没有任何要响应的内容.API 设计上,在用 PUT 请求更新某个资源成功后,后端可以在 HTTP 响 ...

  10. Go中rune类型浅析

    一.字符串简单遍历操作 在很多语言中,字符串都是不可变类型,golang也是. 1.访问字符串字符 如下代码,可以实现访问字符串的单个字符和单个字节 package main import ( &qu ...