python 爬虫 m3u8 视频文件 加密解密 整合mp4

news2024/12/23 9:32:57

文章目录

    • 一、完整代码
    • 二、视频分析
      • 1. 认识m3u8文件
      • 2. 获取密钥,构建解密器
      • 3. 下载ts文件
      • 4. 合并ts文件为mp4
    • 三、总结

一、完整代码

完整代码如下:

import requests
import re
import os
from tqdm import tqdm
from Crypto.Cipher import AES


# 创建临时文件夹
dirs = 'ts_list_need_to_merge/'
os.makedirs(dirs, exist_ok=True)

headers = {
        'Accept': '*/*',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
        'Connection': 'keep-alive',
        'Origin': 'http://www.kpd510.me',
        'Referer': 'http://www.kpd510.me/',
        'Sec-Fetch-Dest': 'empty',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Site': 'cross-site',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.69',
        'sec-ch-ua': '"Chromium";v="116", "Not)A;Brand";v="24", "Microsoft Edge";v="116"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Windows"',
    }



def parse_m3u8_text(m3u8_text):
    m3u8_text = m3u8_text.split()
    encode_info = [line for line in m3u8_text if line.startswith('#EXT-X-KEY:')][0]
    pattern = r"#EXT-X-KEY:METHOD=(.*),URI=\"(.*)\""  
    
    ## 获得加密method 和 key.key的url
    match = re.search(pattern, encode_info)
    if match:
        method = match.group(1)
        key_url = match.group(2)
    else:
        raise '解析失败'
    
    ## 获得ts文件url
    ts_list = [line for line in m3u8_text if line.endswith('ts')]
    return method, key_url, ts_list

def download_method_1(ts_list):
    # 这里弄一个filename_list 方便后续合并ts到mp4
    ts_file_list = []
    for ts_url in tqdm(ts_list):
        filename = dirs + os.path.split(ts_url)[-1]
        content = requests.get(ts_url, headers=headers).content
        decrypt_content_and_save_file(filename, content)
        ts_file_list.append(filename)
    return ts_file_list

def decrypt_content_and_save_file(filename, content):
    with open(filename, mode='wb') as f:
        f.write(decrypter.decrypt(content))


def merge_ts_to_mp4(filename, ts_file_list):
    with open(filename, mode='ab') as f1:
        for ts_file in ts_file_list:
            with open(ts_file, mode='rb') as f2:
                f1.write(f2.read())

if __name__ == '__main__':
    m3u8_url = 'https://play.bo262626.com/20231108/xV1bY9Cn/700kb/hls/index.m3u8'
    response = requests.get(m3u8_url, headers=headers)
    m3u8 = response.text
    method, key_url, ts_list = parse_m3u8_text(m3u8)
    
    key_url = 'https://play.bo262626.com' + key_url
    ts_list = ['https://play.bo262626.com' + item for item in ts_list]
    
    key = requests.get(key_url, headers=headers).content
    decrypter = AES.new(key, AES.MODE_CBC)
    ts_file_list = download_method_1(ts_list[:3])
    
    merge_ts_to_mp4('test.mp4', ts_file_list)

二、视频分析

1. 认识m3u8文件

m3u8的结构详细分析可以看这个链接m3u8 文件格式详解 - 简书 (jianshu.com),这里我们只简要介绍一下;

相信无论多小白都应该知道如何打开开发者模型解析得到下面的结果;

要注意的是,只有预览里面包含了ts信息的才算是我们需要的m3u8文件;大家可以看到左侧有两个index.m3u8,其中一个是没有ts信息的,所以我们直接忽略掉;现在我们先下载来,再来具体分析一下m3u8文件以及里面的内容分别表达什么意思;

下载代码如下:

import requests
import re

headers = {
    'Accept': '*/*',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
    'Connection': 'keep-alive',
    'Origin': 'http://www.kpd510.me',
    'Referer': 'http://www.kpd510.me/',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'cross-site',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.69',
    'sec-ch-ua': '"Chromium";v="116", "Not)A;Brand";v="24", "Microsoft Edge";v="116"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Windows"',
}

response = requests.get('https://play.bo262626.com/20231108/xV1bY9Cn/700kb/hls/index.m3u8', headers=headers)

m3u8 = response.text

m3u8文件的实质是一个视频的url列表,其中ts是计算器可以直接播放的视频格式文件,但是直接下载是可能被加了密的文件,我们需要m3u8文件内容信息进行解密;

我们可以这样理解,m3u8把一个完整的mp4视频切割成了很多的小块,每一个小块在m3u8都是ts文件格式,并在m3u8中采取了加密的措施,至于为什么要加密,这里就不多介绍;

在一般的视频爬取中,我们只需要考虑两个部分,一个是EXT-X-KEY,一个是ts

其中EXT-X-KEY包含了ts的加密方式,ts包含了ts文件的下载地址;

在红色部分也就是EXT-X-KEY部分,我们可以从METHOD中获取到采取的加密方式是AES-128,同时看到URI的地址/20231126/10VkaJks/700kb/hls/key.key,这也就是AES加密密匙的地址:key.key,接下来我们写一个文件来对m3u8文件解析,目的是提取出红色部分和蓝色部分;

代码如下:

def parse_m3u8_text(m3u8_text):
    m3u8_text = m3u8_text.split()
    encode_info = [line for line in m3u8_text if line.startswith('#EXT-X-KEY:')][0]
    pattern = r"#EXT-X-KEY:METHOD=(.*),URI=\"(.*)\""  
    
    ## 获得加密method 和 key.key的url
    match = re.search(pattern, encode_info)
    if match:
        method = match.group(1)
        key_url = match.group(2)
    else:
        raise '解析失败'
    
    ## 获得ts文件url
    ts_list = [line for line in m3u8_text if line.endswith('ts')]
    return method, key_url, ts_list

## 在这里我们直接把m3u8文本丢进去就可以获得
## method, key_url, ts_list
method, key_url, ts_list = parse_m3u8_text(m3u8)
## method = 'AES-128'
## key_url = '/20231108/xV1bY9Cn/700kb/hls/key.key'
## ts_list = ['...ts', '...ts', ...]

2. 获取密钥,构建解密器

因为构建解密器我们需要密钥,而密钥存储在key.key中,首先我们需要解析key_url获取密钥;

在这里可以明显的看到key_url = '/20231108/xV1bY9Cn/700kb/hls/key.key'这不是一个完整的url,我们在这里加上获取m3u8请求的主域名便好;

代码如下:

headers = {
    'Accept': '*/*',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
    'Connection': 'keep-alive',
    'Origin': 'http://www.kpd510.me',
    'Referer': 'http://www.kpd510.me/',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'cross-site',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.69',
    'sec-ch-ua': '"Chromium";v="116", "Not)A;Brand";v="24", "Microsoft Edge";v="116"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Windows"',
}

key_url = 'https://play.bo262626.com' + key_url
key = requests.get(key_url, headers=headers).content
# 这里我们得到key = b'388d590fabfeabcf' 是一个二进制结果

得到了密钥,再结合加密方式AES-128,我们就可以构建一个解密器,构建解密器代码如下:

from Crypto.Cipher import AES
## 这里网络爬取视频一般是MODE_CBC模式
decrypter = AES.new(key, AES.MODE_CBC)

这里要提起的是网络上的m3u8文件采取的加密一般是AES.MODE_CBC模式,在后续操作中如果这里出问题就换MODE一个一个试就好;

3. 下载ts文件

由于有许多的ts文件,我们有三种方法,第一是简单的requests请求一个一个下,这也是最费时的一种;第二个是多进程或者多线程的方式下载;第三个是采用协程的方式;接下来我们一个个实现;

在开始之间,ts_list存在同样的问题,就是需要重构url,这里代码如下:

ts_list = ['https://play.bo262626.com' + item for item in ts_list]

# 这里得到:
# ['https://play.bo262626.com/20231108/xV1bY9Cn/700kb/hls/o3jSJ9mc.ts',
#  'https://play.bo262626.com/20231108/xV1bY9Cn/700kb/hls/GNHDlClJ.ts',
#  'https://play.bo262626.com/20231108/xV1bY9Cn/700kb/hls/zKym5c6V.ts',
#  'https://play.bo262626.com/20231108/xV1bY9Cn/700kb/hls/4ll4NQH3.ts',
#  'https://play.bo262626.com/20231108/xV1bY9Cn/700kb/hls/RwUOniSQ.ts' ...]

再测试一下解密器是否可以:

def decrypt_content_and_save_file(filename, content):
    with open(filename, mode='wb') as f:
        f.write(decrypter.decrypt(content))

test_content = requests.get(ts_list[0], headers=headers).content
decrypt_content_and_save_file('test.ts', test_content)

## 打开视频看是否能打开
## 如果能打开说明解密没问题

直接requests: 代码如下

import os
from tqdm import tqdm

dirs = 'ts_list_need_to_merge/'
os.makedirs(dirs, exist_ok=True)

def download_method_1(ts_list):
    # 这里弄一个filename_list 方便后续合并ts到mp4
    ts_file_list = []
    for ts_url in tqdm(ts_list):
        filename = dirs + os.path.split(ts_url)[-1]
        content = requests.get(ts_url, headers=headers).content
        decrypt_content_and_save_file(filename, content)
        ts_file_list.append(filename)
    return ts_file_list

# 下载测试
ts_file_list = download_method_1(ts_list[:4])

实现挺慢的,不合理;

多进程: 代码如下

# 忘记了,有时间再回来实现

协程: 代码如下

# 忘记了,有时间再回来实现

4. 合并ts文件为mp4

在完成前面的步骤后,直接ab的方式把所有的文件按顺序加入就好;

def merge_ts_to_mp4(filename, ts_file_list):
    with open(filename, mode='ab') as f1:
        for ts_file in ts_file_list:
            with open(ts_file, mode='rb') as f2:
                f1.write(f2.read())

merge_ts_to_mp4('test.mp4', ts_file_list)

后续如果需要删除'ts_list_need_to_merge/'这个临时文件夹里面的所有内容,直接运行下面代码

import send2trash

send2trash.send2trash('ts_list_need_to_merge/') # send2trash.send2trash(dirs)

三、总结

别在图书馆测试这段代码!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1303883.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

油田中控室与32台碳储罐之间数据无线传输

二氧化碳强化石油开采技术,须先深入了解石油储层的地质特征和二氧化碳的作用机制。现场有8辆二氧化碳罐装车,每辆罐车上有4台液态二氧化碳储罐,每台罐的尾部都装有一台西门子S7-200 smart PLC。在注入二氧化碳的过程中,中控室S7-1…

json.loads和eval 速度对比

json.loads和eval 速度对比 代码1结果图代码2参考地址 代码1 import json import time import pandas as pddata_sets pd.read_pickle("val_token_id.pandas_pickle") data_sets[str(i) for i in data_sets] starttime.time() [json.loads(i) for i in data_sets] …

企业使用APP自动化测试工具的重要因素

随着移动应用市场的蓬勃发展,企业对高质量、高效率的软件交付提出了更高的要求。在这个背景下,APP自动化测试工具成为了企业不可或缺的一部分。以下是企业采用APP自动化测试工具的关键因素: 1. 快速且可重复的测试执行 自动化测试工具能够快速…

好看的早上问候语早安图片,今天最新唯美温馨祝福语

1、天气冷了,情谊不凉,树叶黄了,思念不忘,问候像一杯热茶,让人暖心!祝愿我们与健康平安同行!朋友们,大家早上好! 2、多一个人牵挂是一种幸福;多一个人相知是一…

【分治】循环赛日程表Python实现

文章目录 [toc]问题描述分治算法示例Python实现 无运动员数量约束循环赛日程表算法示例Python实现 问题描述 设有 n 2 k n 2^{k} n2k个运动员要进行网球循环赛,设计一个满足以下要求的比赛日程表 每个选手必须与其他 n − 1 n - 1 n−1个选手各赛一次每个选手一天…

vue elementui点击按钮新增输入框(点多少次就新增多少个输入框,无限新增)

效果如图&#xff1a; 核心代码&#xff1a; <div v-for"(item,index) in arrayData" :key"item.id">//上面这个是关键代码&#xff0c;所有思路靠这个打通<el-inputtype"input" //除了输入框&#xff0c;还有textarea等placeholder&…

编程实战:自己编写HTTP服务器(系列5:执行后台命令)

系列入口&#xff1a;编程实战&#xff1a;自己编写HTTP服务器&#xff08;系列1&#xff1a;概述和应答&#xff09;-CSDN博客 本文介绍执行后台命令的shell.asp的实现。 目录 一、概述 二、主体代码 三、详解 3.1 参数 一、概述 这个功能就相当于一个终端&#xff0c;不…

商城免费搭建之java商城 java电子商务Spring Cloud+Spring Boot+mybatis+MQ+VR全景+b2b2c 鸿鹄云商

鸿鹄云商 SAAS云产品概述 【SAAS云平台】打造全行业全渠道全场景的SaaS产品&#xff0c;为店铺经营场景提供一体化解决方案&#xff1b;门店经营区域化、网店经营一体化&#xff0c;本地化、全方位、一站式服务&#xff0c;为多门店提供统一运营解决方案&#xff1b;提供丰富多…

MySQL:从MySQL看主从架构高可用性实现

目录 1 主备延迟 1.1 主备延迟 1.2 主备延迟的来源 1.2.1 主备机性能有差距 1.2.2 备库压力大 1.2.3 大事务 1.3 主备延迟的排查思路 3&#xff09;查看MySQL状态 2 主备切换策略 2.1 可靠性优先策略 2.2 可用性优先策略 2.3 常见切换技术 从进入互联网时代开始&a…

Linux之进程(三)(环境变量)

目录 一、基本概念 二、环境变量 1、PATH 2、HOME 3、SHELL 三、环境变量参数 四、argc和argv 一、基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。如&#xff1a;临时文件夹位置和系统文件夹位置等。环境变量通常…

【软考】信息系统项目管理师论文方向猜想

报喜不报忧&#xff0c;每天都在为鸡零狗碎推诿扯皮&#xff0c;属实是有辱师门。 通过软考&#xff0c;目前算是真正有意义的事情。 虽然都说高项的论文是个玄学&#xff0c;但是道听途说了一些通关感想还是蛮有启发的。 文件要求 参考了一份广西省高级工程师评审的文件&am…

【C语言】二分查找(详解)

&#x1f3a5; 岁月失语唯石能言的个人主页 &#x1f525;个人栏专&#xff1a;秒懂C语言 ⭐若在许我少年时&#xff0c;一两黄金一两风 一、二分查找的思路 二分查找也叫折半查找&#xff0c;二分查找针对的是一个有序的数据集合&#xff0c;每次都通过跟区间的…

C# 图解教程 第5版 —— 第18章 泛型

文章目录 18.1 什么是泛型18.2 C# 中的泛型18.3 泛型类18.3.1 声明泛型类18.3.2 创建构造类型18.3.3 创建变量和实例18.3.4 使用泛型的示例18.3.5 比较泛型和非泛型栈 18.4 类型参数的约束18.4.1 Where 子句18.4.2 约束类型和次序 18.5 泛型方法18.5.1 声明泛型方法18.5.2 调用…

宿舍智能电能表预付费系统的费控策略及应用

安科瑞电气股份有限公司 上海嘉定 201801 摘要:基于智能电能表的预付费系统平台可以实现对预付费客户的适时算费、远程费控和服务。预付费系统的费控策略包括算费子策略、催费预警提醒子策略、欠费停电子策略,介绍3个子策略的制定原则、设计流程,并以示例说明策略的实现方式,通…

每日一博 - Cache Miss Attack

文章目录 概述解决思路缓存空值键并设置短期 TTL&#xff08;生存时间&#xff09;使用布隆过滤器 伪代码1. 缓存空值键并设置短期 TTLa. 缓存空值键b. 设置短期 TTL 2. 使用布隆过滤器a. 集成布隆过滤器b. 查询布隆过滤器 进一步优化系统性能的建议 概述 在缓存管理中&#x…

(C++)VS下sizeof(string(““))与linux-g++下sizeof(string(““))大小区别及原因剖析

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 说明 博主是x86平台&#xff0c;所以下面的结果是28&#xff1b;x64平台下是40&#xff0c;size_t变了&#xff0c;由int变long long。 接下来我们先来介绍 vs 下string的数据结构 我们可以看到有一个_Buf数组&#xff0c;…

【IDEA】反向撤销操作快捷键 ctrl+shift+z 和搜狗热键冲突的解决办法

当我们执行某些操作时与搜狗热键冲突&#xff0c;直接取消搜狗的快捷键即可&#xff01;&#xff01;&#xff01;以下以 ctrlshiftz 为例。 在输入悬浮框右键找到更多设置 按键里面找到系统功能快捷键设置 取消掉冲突的热键即可

Word插件-好用的插件-PPT 素材该怎么积累-大珩助手

PPT 素材该怎么积累&#xff1f; 使用大珩助手中的素材库功能&#xff0c;将Word中的&#xff0c;或系统中的文本文件、图片、其他word文档、pdf&#xff0c;所有见到的好素材&#xff0c;一键收纳。 步骤&#xff1a;选中文件&#xff0c;按住鼠标左键拖到素材库界面中&…

IBM DMC运行在RedHat 9的FIPS模式

文章目录 环境步骤打开RedHat的FIPS模式安装DMCnssdbpk12util和certutil导入certificate导入Liberty的SSL key导入Java的certificate查看nssdb&#xff08;可选&#xff09; 配置jvm.options配置server.xml配置java.security配置dswebserver_override.properties重启DMC验证 常…

End-to-End Reconstruction-Classification Learning for Face Forgery Detection

一、研究背景 现有模型主要通过提取特定的伪造模式进行深度伪造检测&#xff0c;导致学习到的表征与训练集中已知的伪造类型高度相关&#xff0c;因此模型难以泛化到未知的伪造类型上使用。 二、研究动机 1.真实样本的特征分布相对更为紧凑&#xff0c;因此学习真实人脸之间的…