zoukankan      html  css  js  c++  java
  • python解决m3u8直播视频的爬取

    一、背景

    在爬虫方面包括图片,文字,视频,音频等的获取。受到速度的限制,视频的爬取较为麻烦,因为视频是进行切片处理的采取的方式是hls,这是苹果公司制定的一个方案。它会把内容切片,用.m3u8进行组织,在m3u8里面记录了断点的位置,将所有的片段下载下来在拼接就可以连接成整个视频。目前较大的视频都是采取这样的方式。同时m3u8的格式也可以被h5直接读取,这样从理论上和实际过程中解决了视频的传输问题。模型图如下。

    二、文件信息

    2.1 .m3u8的头文件格式

    用检索我们可以在source/media中看到一个.m3u8的文件,通过对这个文件进行访问,可以看到下面的结果。

    这一部分包括了文件格式的定义,以及加密方式,和解密的密钥。

    # EXTM3U:.m3u8文件的格式定义
    # EXT-X-KEY: 密钥的信息
    # METHOD: 加密的方法,这里采用的是AES-128的加密方式
    # URI: 密钥的地址,需要获取访问得到密钥的信息
    # IV: 偏移量,AES加密的方法,通过这个密钥就可以解密,获取正确的视频信息

    结果:

    2.2 每个.ts的文件片段

    每一个.m3u8的片段都包含了这个片段的密钥,加密方法,用于解析视频内容。

    # EXINF:片段切割的大小,大概是10s左右
    # v.f...:下载的地址,每一个.ts片段都保留一个地址,可能相同可能不同
    # EXT-X-KEY:加密的方式和密钥,每一个视频都有一个密钥,可能相同,可能不同
    # METHOD:加密方式,AES-128的加密方式

    结果

    三、解密

    3.1 PyCryptodome安装

    在有密钥的情况下我们需要进行解密,不然下载的文件就是无法播放的。解密的方法参考加密的手法。这里的密钥是AES,因此使用AES的解密方法去解密。

    使用以下的指令安装

    # PyCryptodome的安装,由于版本的问题,在使用AES模块的时候,安装PyCryptodome
    pip install PyCryptodome 

    结果

    3.2 构建解码器与解码

    首先获取到VI,然后获取到key,构建一个解码器

    from Crypto.Cipher import AES
    url_key = "key.key"  # 省略写法
    content_key = requests.get(url_key).content  # 获取key值
    vi = "0x00000000000000000000000000000000"  # vi值一样
    vt = vi.replace("0x", "")[:16].encode()  # 偏移码
    ci = AES.new(content_key, AES.MODE_CBC, vt)  # 构建解码器
    content = requests.get(url_content_ts).content  # 获取加密视频内容
    content_ts = ci.decrypt(content)  # 解码ts中的二进制格式

    3.3 对获取的content解密

    完整的代码

    import requests
    import os
    import re
    from Crypto.Cipher import AES
    
    url = "https://1252524126.vod2.myqcloud.com/9764a7a5vodtransgzp1252524126/0176cbbd5285890799673243539/drm/v.f230.m3u8?"
    data = {
        "time": ""
    }
    
    download_url = "https://1252524126.vod2.myqcloud.com/9764a7a5vodtransgzp1252524126/0176cbbd5285890799673243539/drm/"
    
    """
    列举一个单位格大小:
    #EXTINF:2.000000,
    v.f230.ts?start=0&end=158495&type=mpegts
    #EXT-X-KEY:METHOD=AES-128,URI="https://app.xiaoe-tech.com/get_video_key.php?edk=CiCTzP%2B6jBR9H5awSTdnrwcCQzZlldD%2BTYaAr%2FlaHOwsPBCO08TAChiaoOvUBCokYjRhNjFiNTgtMmVhNy00OWYxLTgwZGMtZTE0NTIyODc5YWIy&fileId=5285890799673243539&keySource=VodBuildInKMS",IV=0x00000000000000000000000000000000
    """
    
    
    def download():
        url_key = "https://app.xiaoe-tech.com/get_video_key.php?edk=CiCTzP%2B6jBR9H5awSTdnrwcCQzZlldD%2BTYaAr%2FlaHOwsPBCO08TAChiaoOvUBCokYjRhNjFiNTgtMmVhNy00OWYxLTgwZGMtZTE0NTIyODc5YWIy&fileId=5285890799673243539&keySource=VodBuildInKMS"
        content_key = requests.get(url_key).content  # 获取key值
        download_path = os.getcwd() + r"download"
        if not os.path.exists(download_path):
            os.mkdir(download_path)
        m3u8_content = requests.get(url, params=data).text
        print(m3u8_content)
        exit()
        result = re.compile(r"v.f230.ts?start=[0-9]+&end=[0-9]+&type=mpegts", re.S).findall(m3u8_content)  # 匹配.ts的文件地址
        vi = "0x00000000000000000000000000000000"
        vt = vi.replace("0x", "")[:16].encode()  # 偏移码
        ci = AES.new(content_key, AES.MODE_CBC, vt)  # 构建解码器
        for i in enumerate(result):
            print(f"正在下载:{i[0]}")
            content_ts = requests.get(download_url + str(i[1])).content
            with open(download_path + "\" + str(i[0] + 1) + ".mp4", 'ab') as f:
                f.write(ci.decrypt(content_ts))  # 将内容解码
                f.flush()
    
    
    if __name__ == '__main__':
        download()

    3.4 合并片段

    使用以下的指令合并得到的.ts片段

    # 首先进入当前的目录 download/*.ts
    cd download
    # 使用和并指令进行合并
    # /b表示二进制 最后会在当前的目录下面产生一个new.mp4的文件
    copy /b *.ts new.mp4

    四、总结

    上述讲述了.m3u8文件的爬取和解析方法,例如直播的爬取,或者是是视频的爬取都涉及到上述的内容。此方法需要自己分析一下内容,没有写成接口的形式,同时这个解码是AES-128的方式,在遇到其他加密方法自行查阅相关解码方式。在下载之前先拿一个片段进行测试,如果可以在批量下载,使用一个可以读取.ts文件的播放器。

    五、参考:

    下面的blog是一下参考

    https://blog.csdn.net/weixin_40346015/article/details/102595690

    https://www.jianshu.com/p/98756e274fa0

    https://www.52pojie.cn/thread-971265-1-1.html

    详细的介绍:https://pakchoi.me/2016/06/21/hls-fe/

    包安装问题https://www.cnblogs.com/new-june/p/9401002.html

  • 相关阅读:
    Qt QChart 中 QValueAxis 和 QCategoryAxis 区别
    Qt QChart 绘制面积图 QAreaSeries
    Qt QChart 设置线条样式 虚线
    Qt 读取csv文件并且绘制折线图
    Qt comboBox控件的三种基本用法
    Qt QStringList 的学习笔记
    OpenYurt 联手 eKuiper,解决 IoT 场景下边缘流数据处理难题
    如何避免 Go 命令行执行产生“孤儿”进程?
    阿里巴巴代码平台架构的演进之路
    云原生演进趋势下传统数据库升级实践
  • 原文地址:https://www.cnblogs.com/future-dream/p/12582918.html
Copyright © 2011-2022 走看看