使用python下载加密的流媒体m3u8视频文件,获取电影资源

使用python下载加密的流媒体m3u8视频文件,获取电影资源

m3u8简介

M3U8是Unicode版本的M3U,用UTF-8编码,m3u8文件其实是 HTTP Live Streaming(缩写为HLS)协议的部分内容。
HLS 的工作原理是把整个流分成多个小的文件来下载,每次只下载一些。当媒体流正在播放时,客户端可以选择从许多不同的备用源中以不同的速率下载同样的资源,允许流媒体会话适应不同的数据速率。
综上,m3u8 文件实质是一个播放列表(playlist)
协议格式主要标签:

  1. EXTM3U:声明该文件是一个 m3u8 文件;
  2. EXT-X-VERSION:声明 HLS 的协议版本号;
  3. EXT-X-TARGETDURATION:表示每个视频分段序列的最大时长(单位:秒);
  4. EXT-X-PLAYLIST-TYPE:表明流媒体类型,若值为VOD表示该视屏流为点播源,若值为EVENT表示该视频流为直播源;
  5. EXT-X-MEDIA-SEQUENCE:表示播放列表第一个 URL 片段文件的序列号;
  6. EXT-X-KEY:使用此标签可以指定解密方法,属性列表主要包括:1) METHOD:指定加密方法,2) URI:指定密钥路径;
  7. EXTINF:表示其后 URL 指定的媒体片段序列时长(单位:秒),每个 URL 媒体片段序列之前必须指定该标签.

m3u8文件示例

代码示例

在在线视频网站中,使用python下载加密的流媒体m3u8视频文件。

获取文件名与m3u8地址

在浏览器中,打开开发者工具,切换到“网络“选项卡,过滤获得m3u8流媒体文件地址。

name = 'nz'
url = "https://vod3.buycar5.cn/20210402/Z4mMbiNW/1000kb/hls/index.m3u8"

获取文件名与m3u8地址

媒体序列解密

为了爬虫自动化获取密钥,需要了解密钥获取流程。

  1. 利用上述获取的m3u8文件,切换到”响应(Response)“选型卡查看EXT-X-KEY标签的URI属性的值:
https://ts3.xarxrljt.com:9999/20210402/Z4mMbiNW/1000kb/hls/key.key

URI

  1. 复制密钥地址,查看密钥:
    KEY

爬虫获取密钥,解密需要使用Crypto库,使用以下命令安装所需库:

pip install pycrypto

利用密钥地址获取密钥:

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,headers=headers)
    key = res.content   #获取加密密钥

视频序列片段下载

想要下载视频,首先需要解析得到m3u8文件中的视频片段序列,然后根据视频片段序列列表下载视频:

#视频片段序列构建
if '#EXTINF' in line:
    # 获取每一媒体序列的.ts文件链接地址
    if 'http' in list_content[index + 1]:
        href = list_content[index + 1]
        player_list.append(href)
    else:
        href = base_url + list_content[index+1]
        player_list.append(href)
#视频序列片段下载
for i,j in enumerate(player_list):
    if not os.path.exists('{}/'.format(movie_name + str(i+1) + '.ts')):
        cryptor = AES.new(key, AES.MODE_CBC, key)
        res = requests.get(j,headers=headers)
        requests.adapters.DEFAULT_RETRIES = 5
        with open('{}/'.format(movie_name) + str(i+1) + '.ts','wb') as file:
            file.write(cryptor.decrypt(res.content))#将解密后的视频写入文件
            print('正在写入第{}个文件'.format(i+1))
            #time.sleep(5)

下载结果
下载结果

完整代码

import requests
import os
from Crypto.Cipher import AES
import time

headers = {
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36 Edg/86.0.622.56",
                "Connection": "close"
                }
def m3u8(url,movie_name):
    base_url = url[:url.rfind('/')+1]#用于拼接url
    rs = requests.get(url,headers=headers).text
    list_content = rs.split('\n')
    player_list = []
    #创建文件夹,用于存放ts文件
    if not os.path.exists('{}'.format(movie_name)):
        #os.system('mkdir merge')
        os.mkdir('{}'.format(movie_name))
    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,headers=headers)
            key = res.content   #获取加密密钥

        #print("key:", key)

        """
        获取.ts文件链接地址方式可根据需要进行定制
        """
        if '#EXTINF' in line:
            # 获取每一媒体序列的.ts文件链接地址
            if 'http' in list_content[index + 1]:
                href = list_content[index + 1]
                player_list.append(href)
            else:
                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):
            if not os.path.exists('{}/'.format(movie_name + str(i+1) + '.ts')):
                cryptor = AES.new(key, AES.MODE_CBC, key)
                res = requests.get(j,headers=headers)
                requests.adapters.DEFAULT_RETRIES = 5
                with open('{}/'.format(movie_name) + str(i+1) + '.ts','wb') as file:
                    file.write(cryptor.decrypt(res.content))#将解密后的视频写入文件
                    print('正在写入第{}个文件'.format(i+1))
                    #time.sleep(5)
            else:
                #print(i)
                pass
    else:
        print('此视频未加密')
        #print(player_list)#打印ts地址列表
        for i,j in enumerate(player_list):
            if not os.path.exists('{}/'.format(movie_name + str(i+1) + '.ts')):
                res = requests.get(j,headers=headers)
                with open('{}/'.format(movie_name) + str(i+1) + '.ts','wb') as file:
                    file.write(cryptor.decrypt(res.content))#将解密后的视频写入文件
                    print('正在写入第{}个文件'.format(i+1))
    print('下载完成')

name = 'nz'
url = "https://vod3.buycar5.cn/20210402/Z4mMbiNW/1000kb/hls/index.m3u8"
m3u8(url,name)

后记

可以使用多线程,提高视频下载速度。
文中示例的m3u8视频文件的加密方式简单,其他复杂加密方式可以利用JS断点获得密钥,然后传递给解密函数。
Enjoy coding!

  • 8
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盼小辉丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值