爬虫--抓取m3u8类型的视频
抓取m3u8类型的视频
1 思路步骤
视频url:https://www.9meiju.cc/mohuankehuan/shandianxiadibaji/1-1.html
-
打开网址分析当前视频是由多个片段组成还是单独一个视频
如果是一个单独视频,则找到网址,直接下载即可
如果为多个片段的视频,则需要找到片段的文件进行处理,本案例以9美剧的m3u8视频为例
-
找到m3u8文件后进行下载,下载后打开文件分析是否需要秘钥
需要秘钥则根据秘钥地址,进行秘钥下载,然后下载所有ts文件
-
合并所有ts文件,转成mp4格式视频
2 url分析
2.1 寻找真正的index.m3u8
真正的index.m3u8
,响应的内容里面是 包含所有后续ts文件的请求url路径、指定的 加密算法 类型,以及密钥文件的URI路径所在
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:1
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="/20220418/671fJxOB/2000kb/hls/key.key"
# 加密方法为 AES-128,及解密key文件的位置地址
# 需要使用代码拼凑成完整路径,进行请求 域名 + '/20220418/671fJxOB/2000kb/hls/key.key'
#EXTINF:1.235,
/20220418/671fJxOB/2000kb/hls/kj6uqHoP.ts # 并且这里ts的url也要拼凑完整
#EXTINF:1.001,
/20220418/671fJxOB/2000kb/hls/ZXX8LYPa.ts
#EXTINF:1.001,
/20220418/671fJxOB/2000kb/hls/sOezpD2H.ts
#EXTINF:1.001,
...
2.2 分析index.m3u8
-
通过网络查找发现有俩个m3u8文件
url分别为
https://new.qqaku.com/20211117/iHVkqQMI/index.m3u8
https://new.qqaku.com/20211117/iHVkqQMI/2523kb/hls/index.m3u8
通过分析 第一个index.m3u8请求返回的内容中,包含了第二个m3u8请求的url地址
再通过拼接请求第二个index.m3u8后,返回了包含当前所有ts文件的地址内容
现在分析出了第二个真正的index.m3u8的地址,但是第一个地址从哪里来的呢?
-
查找第一个index.m3u8的url地址
打开1-1.html 响应的源码 source
发现url存在页面源代码中的js里 知道了位置,在代码中通过正则匹配就可以获取到了
-
分析总结
思路:1.通过页面源代码,可以找到第一个index.m3u8的url
2.通过请求返回包含第二个index.m3u8文件的url内容
3.进行拼接,请求第二个m3u8的url,以此返回所有的ts内容
2.3 总结说明
其他所有的视频网站,基本都大同小异,只不过再寻找最后 真正的index.m3u8文件 时,前面嵌套了多少层url请求的区别,才能找到真正的地址而已
例如:每日影视的网站,https://sp.weoknow.com/index.php/vod/play/id/28124/sid/1/nid/1.html
1.需要 先在源代码,正则找到 "url":"https://v4.dious.cc/share/CjqUrWJmQFUs4Tab"
2.请求第一个找到的url,源码里 正则找到
var playlist = '[{"url":"/20220515/jXanPsgX/1200kb/hls/index.m3u8"}]'; # 其实可以直接到 真正index_m3u8这里 var main = "/20220515/jXanPsgX/index.m3u8";
3.再访问 真正的index.m3u8,返回所有的ts内容
3 代码实现
3.1 获取最后一个m3u8的url地址
import re
from urllib.parse import urljoin
import requests
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
session = requests.Session()
session.get('https://www.9meiju.cc/', headers=headers)
url = 'https://www.9meiju.cc/mohuankehuan/shandianxiadibaji/1-2.html'
response = session.get(url, headers=headers)
response.encoding = 'UTF-8'
data = response.text
# print(data)
'''
<script>
var zanpiancms_player = {"player":"\/public\/","url":"https:\/\/new.qqaku.com\/20211124\/nLwncbZW\/index.m3u8","next":"https:\/\/www.9meiju.cc\/mohuankehuan\/shandianxiadibaji\/1-3.html","name":"wjm3u8","apiurl":null,"adtime":"0","adurl":"","copyright":0,"danmu":{"status":0}};
</script>
'''
# 正则抓取上面的源代码中的m3u8的url
m3u8_uri = re.search('"url":"(.+?index.m3u8)"', data).group(1).replace('\\', '')
# 写入文件 分析当前的页面源代码
with open('99.html', 'w', encoding='UTF-8') as f:
# 写入response.content bytes二进制类型
f.write(response.content.decode('UTF-8'))
# 请求可以获取index.m3u8文件
response = session.get(m3u8_uri, headers=headers)
with open('m3u8_uri.text', 'w', encoding='UTF-8') as f:
# 写入response.content bytes二进制类型
f.write(response.content.decode('UTF-8'))
response.encoding = 'UTF-8'
data = response.text
# 拆分返回的内容获取真正的index.m3u8文件的url
url = data.split('/', 3)[-1]
print(data)
print('m3u8_uri', m3u8_uri)
print('url', url)
print(urljoin(m3u8_uri, url))
3.2 多线程下载ts文件与视频合并
import time
import requests
import os
from concurrent.futures import ThreadPoolExecutor, wait
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36"
}
def down_video(url, i):
'''
下载ts文件
'''
# print(url)
# 下载ts文件
resp = requests.get(url, headers=headers)
with open(os.path.join(path, str(i)+'.ts'), mode="wb") as f3:
f3.write(resp.content)
print('{} 下载完成!'.format(url))
def download_all_videos(url, path):
'''
下载m3u8文件以及多线程下载ts文件
'''
# 请求m3u8文件进行下载
resp = requests.get(url, headers=headers)
with open("first.m3u8", mode="w", encoding="utf-8") as f:
f.write(resp.text)
if not os.path.exists(path):
os.mkdir(path)
# 开启线程 准备下载
pool = ThreadPoolExecutor(max_workers=50)
# 1. 读取文件
tasks = []
i = 0
with open("first.m3u8", mode="r", encoding="utf-8") as f:
for line in f:
# 如果不是url 则走下次循环
if line.startswith("#"):
continue
print(line, i)
# 开启线程
tasks.append(pool.submit(down_video, line.strip(), i))
i += 1
print(i)
# 统一等待
wait(tasks)
# 处理m3u8文件中的url问题
def do_m3u8_url(path, m3u8_filename="index.m3u8"):
# 这里还没处理key的问题
if not os.path.exists(path):
os.mkdir(path)
# else:
# shutil.rmtree(path)
# os.mkdir(path)
with open(m3u8_filename, mode="r", encoding="utf-8") as f:
data = f.readlines()
fw = open(os.path.join(path, m3u8_filename), 'w', encoding="utf-8")
abs_path = os.getcwd()
i = 0
for line in data:
# 如果不是url 则走下次循环
if line.startswith("#"):
# 判断处理是存在需要秘钥
fw.write(line)
else:
fw.write(f'{abs_path}/{path}/{i}.ts\n')
i += 1
def merge(filePath, filename='output'):
'''
利用工具 ffmpeg 进行ts文件合并 解决视频音频不同步的问题 建议使用这种
'''
os.chdir(path)
cmd = f'ffmpeg -i index.m3u8 -c copy {filename}.mp4'
os.system(cmd)
if __name__ == '__main__':
# 抓取99美剧闪电侠
# ts文件存储目录
path = 'ts'
url = 'https://new.qqaku.com/20211124/nLwncbZW/1100kb/hls/index.m3u8'
# 下载m3u8文件以及ts文件
download_all_videos(url, path)
do_m3u8_url(path)
# 文件合并
merge(path, 'ts2')
print('over')
注意:当前视频合并所用的工具为ffmpeg 如需安装 查看ffmpeg的使用
3.3 合并获取上面代码
import re
from urllib.parse import urljoin
import requests
import os # 执行cmd/控制台上的命令
from concurrent.futures import ThreadPoolExecutor, wait
from retrying import retry
def get_m3u8_url(url):
'''
获取页面中m3u8的url
:param url: 电影页面的url
:return:
'''
session = requests.Session()
# 访问首页获取cookie
session.get('https://www.9meiju.cc/', headers=headers)
# url = 'https://www.9meiju.cc/mohuankehuan/shandianxiadibaji/1-2.html'
response = session.get(url, headers=headers)
response.encoding = 'UTF-8'
data = response.text
# print(data)
m3u8_uri = re.search('"url":"(.+?index.m3u8)"', data).group(1).replace('\\', '')
# 写入文件 分析当前的页面源代码
# with open('99.html', 'w', encoding='UTF-8') as f:
# 写入response.content bytes二进制类型
# f.write(response.content.decode('UTF-8'))
# 请求可以获取index.m3u8文件
response = session.get(m3u8_uri, headers=headers)
# with open('m3u8_uri.text', 'w', encoding='UTF-8') as f:
# 写入response.content bytes二进制类型
# f.write(response.content.decode('UTF-8'))
response.encoding = 'UTF-8'
data = response.text
# 拆分返回的内容获取真整的index.m3u8文件的url
# 注意 一定要strip
url = data.split('/', 3)[-1].strip()
print(data)
print('m3u8_uri', m3u8_uri)
url = urljoin(m3u8_uri, url)
print('url', url)
return url
@retry(stop_max_attempt_number=3)
def down_video(url, i):
'''
下载ts文件
'''
# print(url)
# 下载ts文件
# try:
resp = requests.get(url, headers=headers)
with open(os.path.join(path, str(i)+'.ts'), mode="wb") as f3:
f3.write(resp.content)
assert resp.status_code == 200
def download_all_videos(url, path):
'''
下载m3u8文件以及多线程下载ts文件
'''
# 请求m3u8文件进行下载
resp = requests.get(url, headers=headers)
with open("index.m3u8", mode="w", encoding="utf-8") as f:
f.write(resp.content.decode('UTF-8'))
if not os.path.exists(path):
os.mkdir(path)
# 开启线程 准备下载
pool = ThreadPoolExecutor(max_workers=50)
# 1. 读取文件
tasks = []
i = 0
with open("index.m3u8", mode="r", encoding="utf-8") as f:
for line in f:
# 如果不是url 则走下次循环
if line.startswith("#"):
continue
print(line, i)
# 开启线程
tasks.append(pool.submit(down_video, line.strip(), i))
i += 1
print(i)
# 统一等待
wait(tasks)
# 如果阻塞可以给一个超时参数
# wait(tasks, timeout=1800)
def do_m3u8_url(path, m3u8_filename="index.m3u8"):
# 这里还没处理key的问题
if not os.path.exists(path):
os.mkdir(path)
# else:
# shutil.rmtree(path)
# os.mkdir(path)
with open(m3u8_filename, mode="r", encoding="utf-8") as f:
data = f.readlines()
fw = open(os.path.join(path, m3u8_filename), 'w', encoding="utf-8")
abs_path = os.getcwd()
i = 0
for line in data:
# 如果不是url 则走下次循环
if line.startswith("#"):
fw.write(line)
else:
fw.write(f'{abs_path}/{path}/{i}.ts\n')
i += 1
def merge(path, filename='output'):
'''
使用工具 ffmpeg 进行ts文件合并 解决视频音频不同步的问题 建议使用这种
'''
os.chdir(path)
cmd = f'ffmpeg -i index.m3u8 -c copy {filename}.mp4'
os.system(cmd)
if __name__ == '__main__':
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
# 电影的url 返回index.m3u8的url地址
url = get_m3u8_url('https://www.9meiju.cc/mohuankehuan/shandianxiadibaji/1-2.html')
# ts文件存储目录
path = 'ts'
# 下载m3u8文件以及ts文件
download_all_videos(url, path)
do_m3u8_url(path)
# 文件合并
merge(path, '第二集')
print('over')
4 特殊情况
4.1 情况说明
在获取index.m3u8文件的内容时,有的文件内容会显示...jpg/png的情况,并没显示...ts,那么遇到这种情况需要单独处理 内容如下:
这种情况使用上面的代码就无法进行正常合并,合并后的视频无法播放
但使用ffprobe分析,发现识别为png,进而导致无法正常拼接
在这种情况下,只需要将其中PNG文件头部分全部使用FF填充,即可处理该问题
填充后的效果如图
4.2 代码处理
# 解析伪装成png的ts
def resolve_ts(src_path, dst_path):
'''
如果m3u8返回的ts文件地址为
https://p1.eckwai.com/ufile/adsocial/7ead0935-dd4f-4d2f-b17d-dd9902f8cc77.png
则需要下面处理后 才能进行合并
原因在于 使用Hexeditor打开后,发现文件头被描述为了PNG
在这种情况下,只需要将其中PNG文件头部分全部使用FF填充,即可处理该问题
:return:
'''
if not os.path.exists(dst_path):
os.mkdir(dst_path)
file_list = sorted(os.listdir(src_path), key=lambda x: int(x.split('.')[0]))
for i in file_list:
origin_ts = os.path.join(src_path, i)
resolved_ts = os.path.join(dst_path, i)
try:
infile = open(origin_ts, "rb") # 打开文件
outfile = open(resolved_ts, "wb") # 内容输出
data = infile.read()
outfile.write(data)
outfile.seek(0x00)
outfile.write(b'\xff\xff\xff\xff')
outfile.flush()
infile.close() # 文件关闭
outfile.close()
except:
pass
print('resolve ' + origin_ts + ' success')
4.3 完整代码
import shutil
import time
from urllib.parse import urljoin
import requests
import os
import re
from concurrent.futures import ThreadPoolExecutor, wait
def get_m3u8_url(url):
'''
获取页面中m3u8的url
:param url: 电影页面的url
:return:
'''
session = requests.Session()
# 访问首页获取cookie
session.get('https://www.9meiju.cc/', headers=headers)
# url = 'https://www.9meiju.cc/mohuankehuan/shandianxiadibaji/1-2.html'
response = session.get(url, headers=headers)
response.encoding = 'UTF-8'
data = response.text
# print(data)
m3u8_uri = re.search('"url":"(.+?index.m3u8)"', data).group(1).replace('\\', '')
# 请求可以获取index.m3u8文件
response = session.get(m3u8_uri, headers=headers)
response.encoding = 'UTF-8'
data = response.text
# 拆分返回的内容获取真整的index.m3u8文件的url
# 注意 一定要strip
url = data.split('/', 3)[-1].strip()
print(data)
print('m3u8_uri', m3u8_uri)
url = urljoin(m3u8_uri, url)
print('url', url)
return url
def down_video(url, i):
'''
下载ts文件
'''
# print(url)
# 下载ts文件
resp = requests.get(url, headers=headers)
with open(os.path.join(path, str(i)+'.ts'), mode="wb") as f3:
f3.write(resp.content)
# print('{} 下载完成!'.format(url))
def download_all_videos(url, path):
'''
下载m3u8文件以及多线程下载ts文件
'''
# 请求m3u8文件进行下载
resp = requests.get(url, headers=headers)
with open("index.m3u8", mode="w", encoding="utf-8") as f:
f.write(resp.content.decode('UTF-8'))
if not os.path.exists(path):
os.mkdir(path)
# 开启线程 准备下载
pool = ThreadPoolExecutor(max_workers=50)
# 1. 读取文件
tasks = []
i = 0
with open("index.m3u8", mode="r", encoding="utf-8") as f:
for line in f:
# 如果不是url 则走下次循环
if line.startswith("#"):
continue
print(line, i)
# 开启线程
tasks.append(pool.submit(down_video, line.strip(), i))
i += 1
print(i)
# 统一等待
wait(tasks)
# 解析伪装成png的ts
def resolve_ts(src_path, dst_path):
'''
如果m3u8返回的ts文件地址为
https://p1.eckwai.com/ufile/adsocial/7ead0935-dd4f-4d2f-b17d-dd9902f8cc77.png
则需要下面处理后 才能进行合并
原因在于 使用Hexeditor打开后,发现文件头被描述为了PNG
在这种情况下,只需要将其中PNG文件头部分全部使用FF填充,即可处理该问题
'''
if not os.path.exists(dst_path):
os.mkdir(dst_path)
file_list = sorted(os.listdir(src_path), key=lambda x: int(x.split('.')[0]))
for i in file_list:
origin_ts = os.path.join(src_path, i)
resolved_ts = os.path.join(dst_path, i)
try:
infile = open(origin_ts, "rb") # 打开文件
outfile = open(resolved_ts, "wb") # 内容输出
data = infile.read()
outfile.write(data)
outfile.seek(0x00)
outfile.write(b'\xff\xff\xff\xff')
outfile.flush()
infile.close() # 文件关闭
outfile.close()
except:
pass
"""
else:
# 删除目录
shutil.rmtree(src_path)
# 将副本重命名为正式文件
os.rename(dst_path, dst_path.rstrip('2'))
"""
print('resolve ' + origin_ts + ' success')
# 处理m3u8文件中的url问题
def do_m3u8_url(path, m3u8_filename="index.m3u8"):
# 这里还没处理key的问题
if not os.path.exists(path):
os.mkdir(path)
with open(m3u8_filename, mode="r", encoding="utf-8") as f:
data = f.readlines()
fw = open(os.path.join(path, m3u8_filename), 'w', encoding="utf-8")
abs_path = os.getcwd()
i = 0
for line in data:
# 如果不是url 则走下次循环
if line.startswith("#"):
fw.write(line)
else:
fw.write(f'{abs_path}/{path}/{i}.ts\n')
i += 1
def merge(path, filename='output'):
'''
使用工具 ffmpeg 进行ts文件合并 解决视频音频不同步的问题 建议使用这种
'''
os.chdir(path)
cmd = f'ffmpeg -i index.m3u8 -c copy {filename}.mp4'
os.system(cmd)
if __name__ == '__main__':
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36"
}
url = get_m3u8_url('https://www.9meiju.cc/mohuankehuan/shandianxiadibaji/1-20.html')
# 抓取99美剧闪电侠
# ts文件存储目录
path = 'ts'
# 下载m3u8文件以及ts文件
download_all_videos(url, path)
# 合并png的ts文件
src_path = path
dst_path = path+'2'
resolve_ts(src_path, dst_path)
do_m3u8_url(dst_path)
merge(dst_path, '闪电侠')
print('over')
5 解密处理
5.1 加密判断
上面我们讲的是没有经过加密的 ts 文件,这些文件下载后直接可以播放
但经过AES-128加密后的文件下载后会无法播放,所以还需要进行解密
如何判断是否需要加密?分析index.m3u8的请求 响应内容
无需解密index.m3u8文件
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:4
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:3.086,
https://hey05.cjkypo.com/20211215/FMbNtNzz/1100kb/hls/7qs6gJc0.ts
#EXTINF:2.085,
https://hey05.cjkypo.com/20211215/FMbNtNzz/1100kb/hls/rYpHhq0I.ts
#EXTINF:2.085,
https://hey05.cjkypo.com/20211215/FMbNtNzz/1100kb/hls/bfays5sw.ts
######### 分割线 #########
需要解密index.m3u8文件
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:1
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="/20220418/671fJxOB/2000kb/hls/key.key"
# 加密方法为 AES-128,及解密key文件的位置地址
# 需要使用代码拼凑成完整路径,进行请求 域名 + '/20220418/671fJxOB/2000kb/hls/key.key'
#EXTINF:1.235,
/20220418/671fJxOB/2000kb/hls/kj6uqHoP.ts # 并且这里ts的url也要拼凑完整
#EXTINF:1.001,
/20220418/671fJxOB/2000kb/hls/ZXX8LYPa.ts
...
5.2 加密m3u8的处理流程
# 工具ffmepg,可以针对加密的ts文件,进行解密 和 合并
# 处理流程:
1.下载所有的 ts文件、index.m3u8 以及 key.key 文件,并放到同一个文件夹中
2.将 m3u8文件改名为 index.m3u8,将 key.key 改名为 key.m3u8
3.更改 index.m3u8 里的 URL,变为本地路径的 key文件,将所有ts文件也改为本地路径的ts 文件
4.ffmepg命令合并,通过修改后的 本地index.m3u8文件,来合并成mp4格式的视频
ffmpeg -i index.m3u8 -c copy {filename}.mp4
# eg:
project/
-ts/
-0.ts
-1.ts
...
-index.m3u8
-key.m3u8
修改后的index.m3u8内容如下所示:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:1
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="project/ts/key.m3u8"
#EXTINF:1.235,
project/ts/0.ts
#EXTINF:1.001,
project/ts/1.ts
#EXTINF:1.001,
project/ts/2.ts
5.3 代码实现
import time
from urllib.parse import urljoin
import requests
import os
from concurrent.futures import ThreadPoolExecutor, wait
import re
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36"
}
def down_video(url, i):
'''
下载ts文件
'''
resp = requests.get(url, headers=headers)
with open(os.path.join(path, str(i) + '.ts'), mode="wb") as f3:
f3.write(resp.content)
# print('{} 下载完成!'.format(url))
def download_all_videos(path, host):
'''
下载m3u8文件 以及 多线程下载ts文件
'''
if not os.path.exists(path):
os.mkdir(path)
# 开启线程 准备下载
pool = ThreadPoolExecutor(max_workers=50)
# 1. 读取文件
tasks = []
i = 0
with open("index.m3u8", mode="r", encoding="utf-8") as f:
for line in f:
# 如果不是url 则走下次循环
if line.startswith("#"):
continue
# 若是url 则加上域名前缀
line = host + line
print(line, i)
# 开启线程
tasks.append(pool.submit(down_video, line.strip(), i))
i += 1
# 统一等待
wait(tasks)
# 修改m3u8文件
def do_m3u8_url(url, path, m3u8_filename="index.m3u8"):
if not os.path.exists(path):
os.mkdir(path)
with open(m3u8_filename, mode="r", encoding="utf-8") as f:
data = f.readlines()
#
fw = open(os.path.join(path, m3u8_filename), 'w')
abs_path = os.getcwd()
i = 0
for line in data:
# 如果不是url 则走下次循环
if line.startswith("#"):
# 判断处理是存在需要秘钥
if line.find('URI') != -1:
line = line.split('/')[0] + 'key.m3u8"\n' # 写成相对路径
# '#EXT-X-KEY:METHOD=AES-128,URI="key.m3u8"'
# me的写法:写成绝对路径
# if line.startswith('#EXT-X-KEY'):
# line = re.sub('"(.+?)"', f'"{ts_dir_path}\\key.m3u8"'.replace('\\', '/'), line)
host = url.rsplit('/', 1)[0]
# 下载key文件
download_m3u8(host + '/key.key', os.path.join(path, 'key.m3u8'))
fw.write(line)
else:
fw.write(f'{abs_path}/{path}/{i}.ts\n')
i += 1
def download_m3u8(url, m3u8_filename="index.m3u8", state=0):
print('正在下载index.m3u8文件')
resp = requests.get(url, headers=headers)
with open(m3u8_filename, mode="w", encoding="utf-8") as f:
f.write(resp.text)
def merge(filePath, filename='output'):
'''
进行ts文件合并 解决视频音频不同步的问题 建议使用这种
'''
os.chdir(path)
cmd = f'ffmpeg -i index.m3u8 -c copy {filename}.mp4'
os.system(cmd)
def get_m3u8_data(first_m3u8_url):
session = requests.Session()
# 请求第一次m3u8de url
resp = session.get(first_m3u8_url, headers=headers)
resp.encoding = 'UTF-8'
data = resp.text
# 第二次请求m3u8文件地址 返回最终包含所有ts文件的m3u8
second_m3u8_url = urljoin(first_m3u8_url, data.split('/', 3)[-1].strip())
resp = session.get(second_m3u8_url, headers=headers)
with open('index.m3u8', 'wb') as f:
f.write(resp.content)
return second_m3u8_url
if __name__ == '__main__':
# ts文件存储目录
path = 'ts'
# 带加密的ts文件的 index.m3u8 url
url = 'https://s7.fsvod1.com/20220622/5LnZiDXn/index.m3u8'
meu8_url = get_m3u8_data(url)
# 下载m3u8文件以及ts文件
host = 'https://s7.fsvod1.com' # 主机地址 用于拼凑完整的ts路径和秘钥路径
download_all_videos(path, host)
do_m3u8_url(meu8_url, path)
# 文件合并
merge(path, '奇异博士')
print('over')