美文网首页python
python爬取网站m3u8视频,将ts解密成mp4,合并成整体

python爬取网站m3u8视频,将ts解密成mp4,合并成整体

作者: 朝畫夕拾 | 来源:发表于2019-03-16 13:46 被阅读133次

    一些网站会提供m3u8视频地址,以供下载观看。或者一些网站经过分析后发现是使用m3u8格式进行播放的,这时使用m3u8的地址链接就可以下载到相应的视频。

    一、关于m3u8:(https://blog.csdn.net/baidu_34418350/article/details/64922512)

    m3u8是苹果公司推出一种视频播放标准,是m3u的一种,不过 编码方式是utf-8,是一种文件检索格式,将视频切割成一小段一小段的ts格式的视频文件,然后存在服务器中(现在为了减少I/o访问次数,一般存在服务器的内存中),通过m3u8解析出来路径,然后去请求。

    示例链接:http://cdn.can.cibntv.net/12/201702161000/rexuechangan01/rexuechangan01.m3u8

    第一层

    #EXTM3U

    #EXT-X-VERSION:3

    #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2650800,RESOLUTION=1920x1080

    1.m3u8

    观察数据吗,没有用http://开头时,不是真正路径,需要拼接字符串再次请求:http://cdn.can.cibntv.net/12/201702161000/rexuechangan01/1.m3u8 得到数据

    #EXTM3U

    #EXT-X-VERSION:3

    #EXT-X-TARGETDURATION:14

    #EXTINF:11.480, 

    20170215T224129-1-0.ts

    #EXTINF:11.480, 

    20170215T224129-1-1.ts

    #EXTINF:10.480, 

    20170215T224129-1-2.ts

    #EXTINF:11.400, 

    20170215T224129-1-3.ts

    #EXTINF:11.120, 

    20170215T224129-1-4.ts

    #EXT-X-ENDLIST

    看到ts结尾的文件,这才是视频真正的存放路径:

    http://cdn.can.cibntv.net/12/201702161000/rexuechangan01/20170215T224129-1-0.ts

    这时候用浏览器下载就可以播放。不过这个播放不用我们去解析 android 4.0以后的videoView 就支持自动解析,并拼接播放。

    安卓代码:

    Uri uri = Uri.parse("http://cdn.can.cibntv.net/12/201702161000/rexuechangan01/rexuechangan01.m3u8");

    video_view.setMediaController(new MediaController(this));

    video_view.setVideoURI(uri);

    video_view.requestFocus();

    ideo_view.start();

    这样就可以简单的播放M3u8格式的视频了,下载到本地,可直接用视频软件打开。


    二、视频下载

    可以用python脚本自动下载这些ts文件,但实际上有些网站的ts文件是用AES-128加密过的,所以需要解密才能播放。

    加密过的视频在第二层m3u8中会有一个key文件链接:

    #EXTM3U

    #EXT-X-VERSION:3

    #EXT-X-TARGETDURATION:2

    #EXT-X-MEDIA-SEQUENCE:0

    #EXT-X-KEY:METHOD=AES-128,URI="key.key"  #key密钥文件

    需要去读取这个key文件,才能拿到解密密钥。

    import os,requests,datetime

    from Crypto.Cipher import AES

    from binascii import b2a_hex, a2b_hex

    def download(url):

        download_path = os.getcwd() + "\download"

        if not os.path.exists(download_path):

            os.mkdir(download_path)

        #新建日期文件夹

        download_path = os.path.join(download_path, datetime.datetime.now().strftime('%Y%m%d_%H%M%S'))

        #print download_path

        os.mkdir(download_path)

        all_content = requests.get(url).text  # 获取第一层M3U8文件内容

        if "#EXTM3U" not in all_content:

            raise BaseException("非M3U8的链接")

        if "EXT-X-STREAM-INF" in all_content:  # 第一层

            file_line = all_content.split("\n")

            for line in file_line:

                if '.m3u8' in line:

                    url = url.rsplit("/", 1)[0] + "/" + line # 拼出第二层m3u8的URL

                    all_content = requests.get(url).text

        file_line = all_content.split("\n")

        unknow = True

        key = ""

        for index, line in enumerate(file_line): # 第二层

            if "#EXT-X-KEY" in line:  # 找解密Key

                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 = url.rsplit("/", 1)[0] + "/" + key_path # 拼出key解密密钥URL

                res = requests.get(key_url)

                key = res.content

                print "key:" , key

            if "EXTINF" in line: # 找ts地址并下载

                unknow = False

                pd_url = url.rsplit("/", 1)[0] + "/" + file_line[index + 1] # 拼出ts片段的URL

                #print pd_url

                res = requests.get(pd_url)

                c_fule_name = file_line[index + 1].rsplit("/", 1)[-1]

                if len(key): # AES 解密

                    cryptor = AES.new(key, AES.MODE_CBC, key) 

                    with open(os.path.join(download_path, c_fule_name + ".mp4"), 'ab') as f:

                        f.write(cryptor.decrypt(res.content))

                else:

                    with open(os.path.join(download_path, c_fule_name), 'ab') as f:

                        f.write(res.content)

                        f.flush()

        if unknow:

            raise BaseException("未找到对应的下载链接")

        else:

            print "下载完成"

        merge_file(download_path)

    def merge_file(path):

        os.chdir(path)

        cmd = "copy /b * new.tmp"

        os.system(cmd)

        os.system('del /Q *.ts')

        os.system('del /Q *.mp4')

        os.rename("new.tmp", "new.mp4")

    if __name__ == '__main__':

        url = "http://cdn.can.cibntv.net/12/201702161000/rexuechangan01/rexuechangan01.m3u8"

        download(_url)

    三、关于解密报错:No module named Crypto.Cipher

    在python 中使用AES算法时,会报告上述错误,原因是Crypto并非标准模块,需要自己单独安装。

    from Crypto.Cipher import AES

    第一种办法:pip install pycropt 如果报错,就选择第二种办法。

    第二种办法:使用编译好的安装包。http://www.voidspace.org.uk/python/modules.shtml#pycrypto

    PyCrypto 2.6 for Python 2.7 32bit

    PyCrypto 2.6 for Python 2.7 64bit

    装上不好使就换一个试试,安装上面2个都不好使,就安装低版本的(我本机安装上面2个都报错,安装下面的版本就可用了)

    PyCrypto 2.3 for 32bit Windows and Python 2.7 (.zip)

    如果还是报错就到下面目录修改大小写:(我没遇到这个问题)

    C:\Python27\Lib\site-packages\crypto 改成

     C:\Python27\Lib\site-packages\Crypto

    四、合并文件

    可以通过cmd命令的方式将所有的ts合并成一个文件:

    copy /b d:\xxx\download_ts\*   d:\xxx\download_ts\new.mp4

    直接调用merge_file即可,会删除临时文件

    相关文章

      网友评论

        本文标题:python爬取网站m3u8视频,将ts解密成mp4,合并成整体

        本文链接:https://www.haomeiwen.com/subject/bwtsmqtx.html