有加密的m3u8视频下载以及解码方法

有加密的m3u8视频下载以及解码⽅法
突然⼼⾎来潮想着,之前爬⾍学习也可以爬取⼀些数据和图⽚了,那么视频呢?是不是也是到⼀个 url 然后直接写⼊⽂件保存就可以呢?事实证明没那么容易,四处查资料还是折腾了⼀天,最后终于可以了。在众多博⽂中帮助最⼤的就是如下这篇,⾮常感谢。
总的来说,根据我看的博⽂中介绍,m3u8 是⼀种视频的播放格式,与传统的MP4不同(依稀记得以前如果想要下载⼀个视频,只需要将⼀个视频从头播放到尾,然后就可以在系统的某处到缓存⽂件),它是将⼀个完整的视频切割成多个 ts 后缀的视频,然后当我们的进度条被移动或者按时间顺序移动的时候,就会下载对应的⽚段来加载。
使⽤抓包⼯具 Fiddler,可以看到当⽹页中的视频开始播放时,⾸先会向⼀个另外的地址发起请求,获取⼀个后缀为 index.m3u8 的⽂件。我所查看的⽹站,会在这个后缀为 index.m3u8 的⽂件之后再去获取⼀个 1000kb/hls/index.m3u8 的资源,⽽这个才是真正的m3u8 ⽂件。⾥⾯的内容指定了,我们即将获取的 m3u8 资源的 url 是什么、排列顺序,加密⽅式以及密钥的 url。
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="key.key"
#EXTINF:10.000000,
mYexOkq6386000.ts
#EXTINF:10.000000,
mYexOkq6386001.ts
上⾯就是⼀个 m3u8 ⽂件的前⼀部分,我们爬⾍需要关注的是加密⽅式是 AES-128 。然后去把 index.m3u8 替换成 key.key,即可获取到加密的密钥,这个密钥 key 将会是我们后续解码⽂件的关键,没了它下载得到的⽂件是没有意义的。
下载的⽅法与以往的爬⾍程序相同,额外不同的在于写⼊⽂件的瞬间。⾸先因为需要解码 AES 这种加密⽅式需要⽤到特殊的模块AES,所以我们要去安装 Crypto,按照如下的⽅法导⼊类来使⽤。注意有个坑就是,安装 Crypto 的同时需要安
装 PyCryptodome(pycrypto 根据开发者的说法已经不再维护,这个是新的库,功能和接⼝基本⼀致),才可以顺利导⼊。如果发⽣了ImportError,显⽰没有 Crypro 库,那么就去 site-packages ⾥⾯看看⽂件名是不是 crypto,改成 Crypto 应该就没问题了。
from Crypto.Cipher import AES
data = ......
key = ......
cryptor = de('utf-8'), AES.MODE_CBC)
with open(filepath, 'ab') as file:
file.write(cryptor.decrypt(data))
如果没有在把类型为 str 的 key 改成 bytes 类型的话会报 TypeError。然后似乎 open 的地⽅打开⽅式 'ab' 或者 'ab+' 都没什么区别,只要是⼆进制写已经就可以。
没意外的话就可以在指定的⽂件夹中看到下载的⼀系列 ts ⽂件,⽽且是可以播放的。但是每⼀个⽚段
的时间都很短,所以我们需要把所有的⽚段拼接成⼀个完整的视频,查到可以⽤⼀句 cmd 命令来合并,加 /b 的⽬的就是直接拼接⽽不做其他多余的操作否则会影响视频的解码播放。
copy /b D:\download_video\111\*.ts D:\download_video\111.ts
可是如果写完程序抓取完视频还得⼿动去打⼀个 cmd 命令就很⿇烦,os 模块的 system 函数就可以帮助我们解决这个问题。但似乎其中接受的字符串的要求,尤其是对路径的解读,对 \ 和 / 这两个字符的认知似乎不同于直接在 cmd 命令⾏中输⼊的。在 python 中我们是以 \ 反斜杠作为转义字符,然后以 / 正斜杠作为路径之间的分隔;但是在 cmd 命令中是相反的,并且如果我们使⽤ os.path.join 来帮助我们构建路径的时候它也是使⽤ \ 反斜杠来拼接的。请忽略那个覆盖,因为不想删掉之后重新再跑⼀次哈哈。
总结的说,如果我们所构建的路径只需要在 python 中使⽤,例如 open ⼀个指定路径的⽂件,就是⽤
python 对路径的规范;但是如果需要执⾏ cmd 命令,推荐使⽤ os.path.join,既⽅便⼜不会出错。我的代码就是⼀句话:
os.system("copy /b {} {}".format(os.path.join(download_file, filename, "*.ts"), os.path.join(download_file,filename + ".ts")))
那么既然完成了任务,原先那些琐碎的⼩的 ts ⽂件就要删掉啦~⽤ os.remove ⼀个⼀个删除,因为 os.removedirs 只能删除空的⽂件夹。
for i in os.listdir(os.path.join(download_file, filename)):
但是下载的速度很缓慢,整个视频⽂件⼀共才 250M 我却需要下载超过5 分钟。想尝试⽤多线程来处理队列任务,看看能不能加快速度!具体内容留待下⼀篇博⽂!
#encoding = gb2312
import requests
import os
import re
from bs4 import BeautifulSoup
from Crypto.Cipher import AES
from my_quant.time_function import progressbar
import time
def progressbar(tot, pre):
'''
max_bar means the total number of tasks.
i means the number of finished tasks.
视频文件加密'''
max_bar = 20
finish = int(pre*max_bar/tot)
unfinish = (max_bar - finish)
bar = "[{}{}]".format(finish * "-", unfinish * " ")
percent = str(int(pre/tot * 100)) + "%"
if pre < tot:
sys.stdout.write(bar + percent + "\r")
else:
sys.stdout.write(bar + percent + "\n")
sys.stdout.flush()
def cal_time(fun):
def inner_wrapper(*args):
start = time.time()
fun(*args)
end = time.time()
print('Time spent is ' + str(round(end - start,1)))
return inner_wrapper
@cal_time
def video_downlowner(url):
download_file = "D:\\download_video"
headers = {'user-agent': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50'}
result = (url, headers = headers)
soup = , 'html.parser')
filename = soup.find('div', class_ = 'tit')
filename = filename.find_all('a')[-1].string
filename = re.sub(" ", "", filename)#remove the blank in the string.
#filename = "111"
folder = ists(download_file + '/' + filename)
if not folder:
os.makedirs(download_file + '/' + filename)
folder = download_file + '/' + filename
pattern = repile(r'var vHLSurl = "(.*)";')
script = soup.find_all('script', type = "text/javascript")
s = script[3].text
s_after = re.sub(" +", " ", s)
res = pattern.findall(s_after)[0]
new_result = (res, headers)
res = re.sub('index.m3u8', '1000kb/hls/index.m3u8', res)
nn_result = (res, headers)
#print()
pattern1 = repile(r",(.*?)#")
lis = pattern1.findall(re.sub('\n', '', ))
res = re.sub('index.m3u8', 'key.key', res)
nnn_result = (res, headers)
key =
print('key is ' + key)
i = 0
for item in lis[1:]:
download_url = re.sub('key.key', item, res)
r = (download_url ,headers = headers).content
cryptor = de('utf-8'), AES.MODE_CBC)
i += 1
#print(i)
progressbar(len(lis[1:]), i)
if ists(folder + '/' + item):
continue
with open(folder + '/' + item, 'ab+') as file:
r = (download_url ,headers = headers).content
file.write(cryptor.decrypt(r))
'''
Merge ts files.
'''
if not ists(os.path.join(download_file,filename + ".ts")):
os.system("copy /b {} {}".format(os.path.join(download_file, filename, "*.ts"), os.path.join(download_file,filename + ".ts"))) '''
Start to delete ts files.
'''
for i in os.listdir(os.path.join(download_file, filename)):
if __name__ == "__main__":
url = ...
video_downlowner(url)

本文发布于:2024-09-21 13:39:19,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/380929.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:视频   下载   路径   播放   需要   加密
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议