文章目录
前言
一、演示
二、查找网页视频流的索引文件
三、分析视频流的url和视频流索引文件的差异性
四、判断视频数据是否需要转化为ts
五、判断视频是否被加密,如若被加密,需要先解密
六、合并所有的ts视频,以MP4模式输出完整视频
总结
前言
目的:将网站上的m3u8视频下载到本地-----仅娱乐使用;
流程:
- 通过网页调试模式,获取网页视频流的索引文件;
- 分析视频流的url和视频流索引文件的差异性;
- 通过视频流的url,下载视频数据至本地;
- 判断视频数据是否需要转化为ts;
- 判断视频是否被加密,如若被加密,需要先解密;
- 合并所有的ts视频,以MP4模式输出完整视频;
一、演示
二、查找网页视频流的索引文件
F12调试模式后,找到该文件,双击后,可直接下载视频索引文件,其中存在视频片段的部分url或者完整url;
代码实现如下:
python"># 视频索引文件下载网址
m3u8_url = "https://v.gsuus.com/play/PdyY7qzd/index.m3u8"
# User-Agent 即用户代理,在网站中可以查询
hea = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0"
user_agent_list = [
# 在这里可以写多个headers,然后随机选一个进行访问,这样可以防止频繁访问ip被封
hea,
]
headers = {
'user-agent': random.choice(user_agent_list),
'Connection': 'close',
}
resp = requests.get(m3u8_url, headers, verify=False)
data = resp.text
print(data)
三、分析视频流的url和视频流索引文件的差异性
通过分析视频流的地址,来下载所有的片段视频
代码实现如下:
python"># 视频文件下载网址
url_dow = "https://gs.gszyi.com:999/hls/499/20241002/2923112/plist0.ts"
# User-Agent 即用户代理,在网站中可以查询
hea = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0"
user_agent_list = [
# 在这里可以写多个headers,然后随机选一个进行访问,这样可以防止频繁访问ip被封
hea,
]
headers = {
'user-agent': random.choice(user_agent_list),
'Connection': 'close',
}
# url_dow:下载ts视频文件的url
# headers:自定义 HTTP 请求头
# timeout:请求超时时间设置
res = requests.get(url_dow, headers,timeout=20)
save_path = "000.ts"
# 判断页面是否正确
if res.status_code == 200:
data = res.content
# 以二进制模式打开文件,写入二进制数据
with open(save_path, 'wb+') as f:
f.write(data)
f.flush()
print("视频{}下载完毕!!!".format(save_path))
四、判断视频数据是否需要转化为ts
视频为ts格式,则不需要进行转化,如若是其他格式,比如jpeg,jpg格式则需要转化为ts格式,即是重命名文件名称(用该功能函数即可实现 os.rename() )。
五、判断视频是否被加密,如若被加密,需要先解密
如若显示该key网址url,则表示视频被加密,一般所有视频都只有一个key,但也有例外,有些视频每个片段都会进行加密,目前还在研究如何解决,不过也够用了,嘿嘿。
前面下载的视频打开便会显示错误,则就是说明视频需要解密。(注意:某些情况下,可能解密后视频依然无法正常打开,造成原因可能是解密方法不对或者下载视频数据异常。)
代码实现如下:
python">from Crypto.Cipher import AES
# 解密ts视频
def jiemi(src,dec,key):
# src:要解密的文件; dec:解密后的文件; key、iv 从m3u8可见
try:
# 以二进制格式打开已下载的ts文件
with open(src, 'rb') as f1:
# 读取文件数据
part = f1.read()
# key密钥的长度等于IV的向量长度
if len(key) == 16:
IV=b'0000000000000000'
elif len(key) == 32:
IV=b'00000000000000000000000000000000'
# 解密数据
cipher = AES.new(key, AES.MODE_CBC,IV)
plain_data = cipher.decrypt(part)
if part:
# 创建新文件
with open(dec, 'wb') as f2:
# 将解密后的数据写入到创建的新文件中
f2.write(plain_data)
print("解密成功!")
except Exception as error:
print(src)
print("错误异常:%s" % error )
print("原始异常信息:{}".format(traceback.format_exc())) # 返回异常信息
# src:要解密的文件; dec:解密后的文件; key、iv 从m3u8可见
src = "000.ts"
dec = "111.ts"
# key文件中读取
key = "qG6ikBmMJpJGNulz"
# 需要将key和iv转换为字节形式的数据
key = bytes(key, encoding='utf-8')
jiemi(src,dec,key)
实例演示:
六、合并所有的ts视频,以MP4模式输出完整视频
前置条件:
1、需要配置ffmpeg 的运行环境【可以自行下载,或者我的资源中也有安装包】;
2、下载ffmpeg 完成后,配置环境变量即可。
使用该命令合并视频:
#file_names_file:表示所有ts文件的路径
#output.mp4 输出视频名称
os.system(f'ffmpeg -f concat -safe 0 -i {file_names_file} -c copy output.mp4')
所以,合并视频之前,我们需要将file_names_file文件创造出来,否则执行合并命令会失败;
如下图所示(这里就不写代码实现了,思路就是将存放视频流的文件目录列出来,然后判断是否为视频文件,并将对应的路径写入到txt文件内即可。);
然后,我们有了这个file_names_file文件后,便可直接运行合并命令(视频流必须完整,视频流必须与文件内的视频路径对应,否则会执行失败);
代码实现如下:
python">import threading
def getvideo():
# 3.2 大量 ts 文件
file_names_file = 'video.txt'
os.system(f'ffmpeg -f concat -safe 0 -i {file_names_file} -c copy output.mp4')
# os.remove(file_names_file)
t = threading.Thread(target=getvideo)
t.start()
t.join()
print("视频合并结束!")
总结
至此,整个流程完结,可以下载到我们需要的视频了,说实话,比在网站上看要快不少,还是比较有趣的。
并且,请求频繁会导致资源请求失败,这个也要考虑,我用的是多线程,速度很快,所以加入了获取资源失败时会重新获取资源,至少不会漏掉视频资源。
网页请求失败的话,则是表示网站拒绝你的访问,这个问题还待解决,不解决也足够使用了,反正自己使用即可。
后续完善整个工具,目前只实现单个视频下载,后续完成多个视频下载....