python 爬虫 m3u8视频 AES加/解密 相关问题
最近在了解爬虫 记录一下近期的情况
公司在研究机器学习和深度学习于是就有了这篇文章,本文说的是爬取百度的视频思路,目前为止爬虫还未结束但并没有成功,遇到一些问题进行不下去了,这些问题将在本文展开讨论和分享。本文涉及到百度大脑视频其中爬取的视频并未用于商业以及其他非法用途,仅仅是为了个人方便学习和技术锻炼,如有侵权联系删除。
- 首先我们进入官网登录之后页面是这个样子的 点击进入百度大脑
然后随意选择一篇自己喜欢的课程,加入课程,进入课程学习
2.接下来点击开始学习
3. 先看一下网络,这里进到页面之后打控制台重新刷新一下,在点击播放的时候又会出现一部分的网络请求
红框内点击播放是加载的接口需要注意
这里分析此网站采用的是流式媒体 m3u8视频的格式 不懂的同学自行谷歌
此时我们点开这个文件来查看一下文件内容如下
这里贴出来一部分
看不懂m3u8文件的同学点击这里有详细介绍 m3u8 文件格式详解
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:13
#EXT-X-KEY:METHOD=AES-128,URI="https://drm.media.baidubce.com/v1/tokenVideoKey?videoKeyId=mda-kiqkczejn4b8fnqs",IV=0xe3508bcf5e9bf17c6e0fcb55ed8a5157,KEYFORMAT=media-drm-token
#EXTINF:12.500000,
mda-kiqkczejn4b8fnqs.m3u8.0.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://drm.media.baidubce.com/v1/tokenVideoKey?videoKeyId=mda-kiqkczejn4b8fnqs",IV=0xe3508bcf5e9bf17c6e0fcb55ed8a5157,KEYFORMAT=media-drm-token
#EXTINF:8.333333,
mda-kiqkczejn4b8fnqs.m3u8.1.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://drm.media.baidubce.com/v1/tokenVideoKey?videoKeyId=mda-kiqkczejn4b8fnqs",IV=0xe3508bcf5e9bf17c6e0fcb55ed8a5157,KEYFORMAT=media-drm-token
#EXTINF:12.500000,
mda-kiqkczejn4b8fnqs.m3u8.2.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://drm.media.baidubce.com/v1/tokenVideoKey?videoKeyId=mda-kiqkczejn4b8fnqs",IV=0xe3508bcf5e9bf17c6e0fcb55ed8a5157,KEYFORMAT=media-drm-token
#EXTINF:8.333333,
mda-kiqkczejn4b8fnqs.m3u8.3.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://drm.media.baidubce.com/v1/tokenVideoKey?videoKeyId=mda-kiqkczejn4b8fnqs",IV=0xe3508bcf5e9bf17c6e0fcb55ed8a5157,KEYFORMAT=media-drm-token
#EXTINF:8.333333,
mda-kiqkczejn4b8fnqs.m3u8.4.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://drm.media.baidubce.com/v1/tokenVideoKey?videoKeyId=mda-kiqkczejn4b8fnqs",IV=0xe3508bcf5e9bf17c6e0fcb55ed8a5157,KEYFORMAT=media-drm-token
#EXTINF:12.500000,
mda-kiqkczejn4b8fnqs.m3u8.5.ts
4.由此推断出此视频肯定是加密的,所以我们要对视频解码才能在本地播放。
5.接下来直接上代码吧,让代码来帮我讲
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# @author souldou-1257096360@qq.com
# @date 2021/4/1
# @file 视频检测index.py
# 用到的依赖,这里重点说一下 Crypto 的依赖 肯定会遇到问题,直接谷歌一下就能解决
import os
import requests
import json
import datetime
from Crypto.Cipher import AES
class Reptile(object):
def __init__(self, params: object):
self.url, self.token, self.data = params['url'], params['token'], params['data']
print('Reptile!!!,\nurl:{},\ndata:{}\n'.format(self.url, self.data))
self.header = {} #自己的请求头信息 自己模拟
# 创建问价夹
download_path = os.getcwd() + "\download"
if not os.path.exists(download_path):
os.mkdir(download_path)
# 新建日期文件夹
download_path = os.path.join(download_path, '视频' + datetime.datetime.now().strftime('%Y%m%d_%H%M%S'))
os.mkdir(download_path)
all_content = requests.get(url = self.url, headers = self.header).text # 获取M3U8的文件内容
# 保存m3u8文件为文本
with open(download_path + "\m3u8.txt", 'w+') as f:
f.write(all_content)
f.close()
file_line = all_content.split("\n") # 读取文件里的每一行
# 通过判断文件头来确定是否是M3U8文件
if file_line[0] != "#EXTM3U":
raise BaseException(u"非M3U8的链接")
else:
unknow = True # 用来判断是否找到了下载的地址
for index, line in enumerate(file_line):
unknow = False
if "#EXT-X-KEY" in line:
# 找m3u8文件中的参数和解密的key,请求连接
URI_http = line[line.find("URI"):line.rfind('"')].split('"')[1]
# 找m3u8文件中的参数和解密的IV
IV = line[line.find("IV"):].split(',')[0].split('=')[1]
# 拿到请求返回的真实key
tokenVideoKey = requests.get(
url = URI_http + '&playerId=' + '&playerId=pid-1-5-1&token=' + self.token)
data = json.loads(tokenVideoKey.content)
# encryptedVideoKey 就是借口返回的key
encryptedVideoKey, videoKeyId = data['encryptedVideoKey'], data[
'videoKeyId']
# 开始解密文件和保存
# 拼出ts片段的URL,拼接处ts文件的请求地址:https://jh0p4t0rh9rs9610ryc.exp.bcevod.com/mda-kimg4q6rjx1351mk/mda-kimg4q6rjx1351mk.m3u8.15.ts 这样的格式(此链接无效)
pd_url = self.url.rsplit("/", 1)[0] + "/" + file_line[index + 2]
# 获取ts视频文件
res = requests.get(pd_url)
print('res:', res)
c_fule_name = str(file_line[index + 2])
print(c_fule_name + ".mp4")
if encryptedVideoKey and len(encryptedVideoKey):
# AES 解密
KEY = bytes(encryptedVideoKey, encoding = 'utf-8')
IV = bytes(IV, encoding = 'utf-8')
cont = res.content
print('key:{}\nIV:{}\n'.format(KEY, IV))
crypto = AES.new(KEY, AES.MODE_CBC, IV)
c_fule_name + ".mp4"
with open(os.path.join(download_path, c_fule_name), 'ab') as f:
f.write(crypto.decrypt(cont))
pass
pass
else:
print('AES 解密跳过')
with open(os.path.join(download_path, c_fule_name), 'ab') as f:
f.write(res.content)
f.flush()
pass
pass
pass
pass
if unknow:
raise BaseException("未找到对应的下载链接")
else:
print("下载完成")
pass
pass
if __name__ == '__main__':
# 这里的url 自己在浏览器控制台复制 .m3u8 的请求地址,token获取 下边看截图,会在/v1/tokenVideoKey?的这个接口中获取
params = {
"data" : { },
"url" : 'https://jh0p4t0rh9rs9610ryc.exp.bcevod.com/mda-kjjf4mvng54wteir/mda-kjjf4mvng54wteir.m3u8',
"token": '89b5222c412618429cc7c71245825a50c94a73bbeb13f29f56d95c625bae50fb_ae4b649c2a1c435d905425892dab42b1_1617769864',
}
reptile = Reptile(params)
最后重点说一下遇到的问题:以上是关键的代码并非全部,其中会报 IV 字节的错误,暂未解决此问题,后续更新
这里的KEY 和 IV值应该还需要作进一步的处理,目前问题就出在这里,发此篇文章的目的主要就是想大家一起讨论。
这里联系方式,有兴趣的同学滴滴我哈
125709636@qq.com
本文暂且说到这里,后续继续跟进。