欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python爬取m3u8格式视频并解密ts文件合并转为mp4格式

程序员文章站 2022-07-12 22:15:39
...

 

 

一. m3u8是什么格式

m3u8是苹果公司推出的视频播放标准,是m3u的一种,只是编码格式采用的是UTF-8。

m3u8准确来说是一种索引文件,使用m3u8文件实际上是通过它来解析对应的放在服务器上的视频网络地址,从而实现在线播放。使用m3u8格式文件主要因为可以实现多码率视频的适配,视频网站可以根据用户的网络带宽情况,自动为客户端匹配一个合适的码率文件进行播放,从而保证视频的流畅度。

它将视频切割成一小段一小段的ts格式的视频文件,然后存在服务器中(现在为了减少I/o访问次数,一般存在服务器的内存中),通过m3u8解析出来路径,然后去请求。

二. 如何处理经过AES-128加密的ts文件

示例链接:https://cdn.letv-cdn.com/2018/12/05/JOCeEEUuoteFrjCg/playlist.m3u8

输入这个链接并不会跳转到源播放地址,而是下载一个.m3u8格式的文件,文件内容一般长这样:

#EXTM3U
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="https:/*******/**********/hlskey?info=C77821E76077257C9C33DC5901307461&t=1602634262&key=81E7CD7DD2D96CEF9F2B1B18AC2707C9",IV=0xC77821E76077257C9C33DC5901307461
#EXT-X-VERSION:4
#EXTINF:6.756756,
out000.ts
#EXTINF:10.427089,
out001.ts
#EXTINF:3.378378,
out002.ts
#EXTINF:1.126133,
.............

out.....ts
#EXT-X-ENDLIST

将文件中的url中的playlist.m3u8 替换为 out000.ts会下载一个.ts文件,这个ts文件就是视频的一个片段,整个视频由若干个小片段构成,没有经过加密的文件下载后直接可以播放,但经过AES-128加密后的文件下载后会无法播放

Python爬取m3u8格式视频并解密ts文件合并转为mp4格式

我们主要研究的是经过加密的ts文件,并解密它。我们去把 index.m3u8 替换成 key.key,即可获取到加密的**,这个** key 将会是我们后续解码文件的关键,没了它下载得到的文件是没有意义的。

       因为需要解码 AES-128 这种加密方式需要用到特殊的模块 AES,所以我们要去安装 Crypto,按照如下的方法导入类来使用。可以通过 pip install Crypto 安装 Crypto库,如果发生了 ImportError,显示没有 Crypro 库,那么就去 site-packages 里面看看文件名是不是 crypto,改成 Crypto 应该就没问题了。

下载后的ts文件我们可以使用win自带的 copy /b '下载的文件目录路径'/*.ts  '  '合并后的文件目录路径'/new.mp4 来合并ts文件,之后再使用 del *.ts 命令来删除所有的.ts文件,在python中我们可以使用os.system()命令来处理cmd命令

Python爬取m3u8格式视频并解密ts文件合并转为mp4格式

具体代码如下:包括未加密和加密两种处理方式

import requests
import os
from Crypto.Cipher import AES
def m3u8(url):
    base_url = url[:url.rfind('/')+1]#如果需要拼接url,则启用 , +1 把 / 加上
    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'}
    rs = requests.get(url,headers=headers).text
    list_content = rs.split('\n')
    player_list = []
    #如果没有merge文件夹则新建merge文件夹,用于存放ts文件
    if not os.path.exists('merge'):
        os.system('mkdir merge')
    key = ''
    for index,line in enumerate(list_content):
        # 判断视频是否经过AES-128加密
        if "#EXT-X-KEY" in line:
            method_pos = line.find("METHOD")
            comma_pos = line.find(",")
            method = line[method_pos:comma_pos].split('=')[1]#获取加密方式
            print("Decode Method:", method)
            uri_pos = line.find("URI")
            quotation_mark_pos = line.rfind('"')
            key_path = line[uri_pos:quotation_mark_pos].split('"')[1]
            key_url = key_path
            res = requests.get(key_url)
            key = res.content   #获取加***
            print("key:", key)
        #以下拼接方式可能会根据自己的需求进行改动
        if '#EXTINF' in line:
            # href = ''
            # 如果加密,直接提取每一级的.ts文件链接地址
            if 'http' in list_content[index + 1]:
                href = list_content[index + 1]
                player_list.append(href)
            # 如果没有加密,构造出url链接
            elif('ad0.ts' not in list_content[index + 1]):
                href = base_url + list_content[index+1]
                player_list.append(href)
    if(len(key)):
        print('此视频经过加密')
        print(player_list)#打印ts地址列表
        for i,j in enumerate(player_list):
            cryptor = AES.new(key, AES.MODE_CBC, key)
            res = requests.get(j,headers=headers)
            with open('merge/' + str(i+1) + '.ts','wb') as file:
                file.write(cryptor.decrypt(res.content))#将解密后的视频写入文件
                print('正在写入第{}个文件'.format(i+1))
    else:
        print('此视频未加密')
        print(player_list)#打印ts地址列表
        for i,j in enumerate(player_list):
            res = requests.get(j,headers=headers)
            with open('merge/' + str(i+1) + '.ts','wb') as file:
                file.write(res.content)
                print('正在写入第{}个文件'.format(i+1))
        print('下载完成')
#当全写下载完之后合并文件并删除所有.ts文件
def merge_ts():
    path = os.getcwd() + '\merge'#获取视频存放路径
    merge_cmd = 'copy /b ' + path + '\*.ts ' + path + '\\new.mp4'
    del_cmd = 'del ' + path + '\*.ts'
    os.system(merge_cmd)#执行合并命令
    os.system(del_cmd)#执行删除命令
    print('合并完成')
if __name__ == '__main__':
    url = 'https://cdn.letv-cdn.com/2018/12/05/JOCeEEUuoteFrjCg/playlist.m3u8'
    #下载视频
    m3u8(url)
    #合并视频
    merge_ts()

 

 

相关标签: python