1. python抓取、解析、下載小電影……

        共 7473字,需瀏覽 15分鐘

         ·

        2021-10-25 01:13


        老實說是不是因為標(biāo)題才點進來的?雖然我這里沒有小電影,但是今天的內(nèi)容也是實打?qū)嵉母韶洠?/span>這叫授人以魚不如授人以漁,有了這技術(shù),小電影不分分鐘的事嘛!

        前言

        一到周末就想搞點有意思的事,比如之前分享的arduino開發(fā),比如上周分享的博客爬蟲,今天我又想搞點有意思的事,所以就有了今天的內(nèi)容——python爬取m3u8視頻資源。不過需要在這里需要著重說明的是,技術(shù)無罪,切勿用技術(shù)搞違法犯罪的事,不然日子真的就越來越有判頭了

        知識擴展

        在開始抓取m3u8視頻(小電影)之前,我們先了解下m3u8的相關(guān)知識,了解的更多,可以讓我們少走彎路。

        m3u8是什么?

        在此之前,我僅僅知道m3u8是一種網(wǎng)絡(luò)串流,在平時娛樂時候會找一些m3u8的資源,看看直播啥的,直到今天要分享m3u8的相關(guān)內(nèi)容,才真正開始搜集m3u8的相關(guān)知識點。關(guān)于m3u8連百度百科都沒有說明,搜到知乎一篇內(nèi)容(【全網(wǎng)最全】m3u8到底是什么格式?一篇文章搞定m3u8下載),下面的原理圖也是參照的這篇內(nèi)容:

        從上面的原理圖中我們可以得到以下知識點:

        • 首先m3u8并非是視頻格式,而是視頻文件的索引。
        • ts文件才是我們真正播放的視頻資源。ts是日本高清攝像機拍攝下進行的封裝格式,全稱為MPEG2-TS。ts即"Transport Stream"的縮寫。MPEG2-TS格式的特點就是要求從視頻流的任一片段開始都是可以獨立解碼的。

        m3u8通常分兩種格式,一種是單碼率(固定分辨率),一種是多碼率(包含多種分別率)。下面就是一個單碼率的m3u8文件的內(nèi)容:

        #EXTM3U
        #EXT-X-VERSION:3
        #EXT-X-TARGETDURATION:10
        #EXT-X-MEDIA-SEQUENCE:1619459525
        #EXT-X-PROGRAM-DATE-TIME:2021-10-23T05:39:42Z
        #EXTINF:10.0,
        1634967582-1-1619459525.hls.ts
        #EXT-X-PROGRAM-DATE-TIME:2021-10-23T05:39:52Z
        #EXTINF:10.0,
        1634967592-1-1619459526.hls.ts
        #EXT-X-PROGRAM-DATE-TIME:2021-10-23T05:40:02Z
        #EXTINF:10.0,
        1634967602-1-1619459527.hls.ts

        這個就是一個多碼率的m3u8文件,從多碼率的文件格式可以看出來,多碼率中包括了多個單碼率是m3u8文鏈接:

        #EXTM3U
        #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=500000,RESOLUTION=480x270
        500kb/hls/index.m3u8
        #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=300000,RESOLUTION=360x202
        300kb/hls/index.m3u8
        m3u8文件指令

        另外我在另外一篇博客發(fā)現(xiàn)m3u8其實是m3u文件的擴展(參考文檔2),這可能就是為什么沒有找到m3u8相關(guān)詞條的原因吧,同時在m3u的詞條中發(fā)現(xiàn)了M#U文件的指令描述(每個字段的含義):

        #EXTM3U?//必需,表示一個擴展的m3u文件

        #EXT-X-VERSION:3?//hls的協(xié)議版本號,暗示媒體流的兼容性

        #EXT-X-MEDIA-SEQUENCE:xx?//首個分段的sequence?number

        #EXT-X-ALLOW-CACHE:NO?//是否緩存

        #EXT-X-TARGETDURATION:5?//每個視頻分段最大的時長(單位秒)

        #EXT-X-DISCONTINUITY?//表示換編碼

        #EXTINF:?//每個切片的時長

        另外關(guān)于m3u的文件指令是有國際標(biāo)準(zhǔn)的,感興趣的小伙伴可以去看下:

        http://tools.ietf.org/html/draft-pantos-http-live-streaming-06

        好了,關(guān)于m3u8的相關(guān)內(nèi)容,我們就說這么多,感興趣的小伙伴可以自己繼續(xù)探索,下面我們看下如何用python抓取、解析和下載m3u8文件索引中的視頻文。

        抓取、解析、下載

        首先我們先要拿到目標(biāo)視頻資源的索引文件,也就是m3u8文件。一般稍微懂點web開發(fā)的小伙伴,應(yīng)該都知道瀏覽器抓包吧,F12打開瀏覽器控制臺,然后選擇Network,刷新下頁面,在左側(cè)資源區(qū)找到index.m3u8文件。

        通常會有兩個m3u8,第一個是獲取視頻碼率列表的,也就是多碼率m3u8,這個文件我們是沒辦法直接解析的,我們要找的是包含ts視頻資源的m3u8文件。這里我隨便在網(wǎng)上搜了一個葫蘆娃的視頻,然后通過控制臺拿到m3u8文件地址:

        https://vod1.bdzybf1.com/20200819/wMgIH6RN/1000kb/hls/index.m3u8

        下面我們就用python解析下載這個視頻文件。

        解析m3u8文件

        解析m3u8文件最核心的地方是分析m3u8的文件結(jié)構(gòu),然后根據(jù)其文件內(nèi)容寫出對應(yīng)的解析邏輯。這里我推薦直接用requests庫模擬調(diào)用,然后分析響應(yīng)結(jié)果,因為用文本工具之類的查看m3u8文件的話,換行符\n、制表符\t這些看起來不夠直觀,但是requests就不會有這個問題,因為我們解析的就是requests的響應(yīng)結(jié)果。

        這里的以我們上面m3u8文件為例響應(yīng)結(jié)果如下:

        可以清晰地看出,這個m3u8文件是通過換行符\n分割的,有部分m3u8文件中會出現(xiàn)制表符和換行符組合的情況,所以具體情況具體分析。

        另外,我從響應(yīng)內(nèi)容中發(fā)現(xiàn),這個視頻資源是進行了AES-128加密的,所以后面在下載視頻資源的時候要解密。

        解析ts視頻地址

        因為python代碼都很簡單,代碼量也不多,所以就不展開講了,看代碼注釋應(yīng)該可以看懂。這個方法主要是為了獲取ts視頻文件的地址。

        import?requests

        def?getTsFileUrlList(m3u8Url):
        ????#?組裝請求頭
        ????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'
        ????????????}
        ????#?請求?m3u8文件,并拿到文件內(nèi)容
        ????ts_rs?=?requests.get(url?=?m3u8Url,?headers=headers).text
        ????print(ts_rs)
        ????#?換行符分割文件內(nèi)容
        ????list_content?=?ts_rs.split('\n');
        ????print('list_content:{}'.format(list_content))
        ????player_list?=?[]
        ????#?循環(huán)分割結(jié)果
        ????for?line?in?list_content:
        ??????#?以下拼接方式可能會根據(jù)自己的需求進行改動
        ??????if?'#EXTINF'?in?line:
        ????????continue;
        ??????#?僅記錄?ts文件地址??
        ??????elif?line.endswith('.ts'):
        ????????player_list.append(line)
        ????print('數(shù)據(jù)列表組裝完成-size:?{}'.format(len(player_list)));
        ????return?player_list;

        運行上面這個方法的話,最終會獲取到m3u8索引文件中所有的ts視頻地址,但是由于我們剛才已經(jīng)從m3u8文件中發(fā)現(xiàn)了,視頻資源是加密的,所以在下載的時候我們需要解密。

        下載文件

        這里的方法是下載并解密視頻資源,這里我加了一個解密操作,因為注釋夠清晰,所以我也不過多贅述了

        def?fileDownloadWithdecrypt(fileSavePath,?player_list):
        ????#?創(chuàng)建文件夾
        ????if?not?os.path.exists(fileSavePath):
        ????????os.mkdir(fileSavePath);
        ????#?循環(huán)?ts?視頻資源列表
        ????for?index,?url?in?enumerate(player_list):
        ????????#?發(fā)送下載請求
        ????????ts_video?=?requests.get(url?=?url,?headers=headers)
        ????????#?保存文件
        ????????with?open('{}/{}.ts'.format(fileSavePath,?str(index?+?1)),?'wb')?as?file:
        ????????????#?視頻資源解密
        ????????????context?=?decrypt(ts_video.content);
        ????????????#?文件寫入
        ????????????file.write(context)
        ????????????print('正在寫入第{}個文件'.format(index?+?1))
        ????print('下載完成');

        下面是解密代碼

        from?Crypto.Cipher?import?AES???#?用于AES解碼

        def?decrypt(context):
        ????#?加密的key
        ????key?=??b'2cd1da2aedacaec8';
        ????#?解密
        ????cryptor?=?AES.new(key,?AES.MODE_CBC,?key);
        ????decrypt_content?=?cryptor.decrypt(context);
        ????return?decrypt_content;

        這里用的是pycryptodome庫,安裝方式如下:

        ?pip3?install?pycryptodome

        關(guān)于密文,在m3u8文件里面已經(jīng)有了,直接下載就可以拿到,這里我就不通過代碼拿了:

        這里下載視頻會比較費時間,為了提高下效率可以用多線程,但是由于時間的關(guān)系就不演示了。

        合并視頻

        合并視頻就更簡單了,就是講前面我們保存的視頻合并成一個完整的視頻,合并完之后的格式是mp4。

        def?fileMerge(filePath):
        ????#?查詢出文件中的ts文件
        ????c?=?os.listdir(filePath)
        ????#?打開視頻保存文件
        ????with?open('%s.mp4'?%?filePath,?'wb+')?as?f:
        ??????#?循環(huán)
        ??????for?i?in?range(len(c)):
        ????????#?打開?ts?視頻文件
        ????????x?=?open('{}/{}.ts'.format(filePath,?str(i?+?1)),?'rb').read()
        ????????f.write(x)
        ????print('合并完成')

        我看了下,短短的一集葫蘆娃,總共被分割成272ts文件(好像比這個多,我沒下載完就把網(wǎng)斷了):

        272ts文件合并成一個視頻文件:

        好了,到這里我們python爬取m3u8視頻資源的實例就結(jié)束了,今天的示例還算比較完美,目標(biāo)也比較完美的達成了。奈斯!

        完整代碼如下:

        import?requests
        import?os
        from?Crypto.Cipher?import?AES???#?用于AES解碼

        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'
        ????????????}

        def?getTsFileUrlList(m3u8Url):
        ????ts_rs?=?requests.get(url?=?m3u8Url,?headers=headers).text
        ????print(ts_rs)
        ????list_content?=?ts_rs.split('\n');
        ????print('list_content:{}'.format(list_content))
        ????player_list?=?[]
        ????index?=?1;
        ????for?line?in?list_content:
        ??????#?以下拼接方式可能會根據(jù)自己的需求進行改動
        ??????if?'#EXTINF'?in?line:
        ????????continue;
        ??????elif?line.endswith('.ts'):
        ????????player_list.append(line)
        ????print('數(shù)據(jù)列表組裝完成-size:?{}'.format(len(player_list)));
        ????return?player_list;????
        ????
        def?fileDownloadWithdecrypt(fileSavePath,?player_list):
        ????if?not?os.path.exists(fileSavePath):
        ????????os.mkdir(fileSavePath);
        ????for?index,?url?in?enumerate(player_list):
        ????????ts_video?=?requests.get(url?=?url,?headers=headers)
        ????????with?open('{}/{}.ts'.format(fileSavePath,?str(index?+?1)),?'wb')?as?file:
        ????????????context?=?decrypt(ts_video.content);
        ????????????file.write(context)
        ????????????print('正在寫入第{}個文件'.format(index?+?1))
        ????print('下載完成');
        ????
        ????
        def?fileMerge(filePath):
        ????c?=?os.listdir(filePath)
        ????with?open('%s.mp4'?%?filePath,?'wb+')?as?f:
        ??????for?i?in?range(len(c)):
        ????????x?=?open('{}/{}.ts'.format(filePath,?str(i?+?1)),?'rb').read()
        ????????f.write(x)
        ????print('合并完成')
        ????
        ????
        def?decrypt(context):
        ????key?=??b'2cd1da2aedacaec8';
        ????cryptor?=?AES.new(key,?AES.MODE_CBC,?key);
        ????decrypt_content?=?cryptor.decrypt(context);
        ????return?decrypt_content;
        ????
        ????
        if?__name__?==?'__main__':
        ????m3u8Url?=?'https://vod1.bdzybf1.com/20200819/wMgIH6RN/1000kb/hls/index.m3u8';
        ????videoList?=?getTsFileUrlList(m3u8Url);
        ????print(videoList)
        ????savePath?=?"./test"
        ????fileDownloadWithdecrypt(savePath,?videoList);
        ????fileMerge(savePath);

        運行上面的代碼,你就可以得到一集完整的葫蘆娃

        當(dāng)然,如果你能找到資源,用上面這段代碼爬取小電影也是可以的

        總結(jié)

        今天的視頻爬蟲很簡單,可以說非常簡單,核心技術(shù)點也不多,主要涉及如下幾點:

        • request請求
        • 字符串解析(響應(yīng)結(jié)果解析)
        • 文件操作
        • ASE解密

        只需要稍微有一點python基礎(chǔ),就可以做出來,所以這里我也沒什么好總結(jié)的了。

        最后,免費為python做一個無償廣告。我一直覺得python是一門不錯的語言,特別是作為腳本使用的時候,真的是太方便了,今天它也依然沒有讓我失望。

        其實嚴(yán)格來說,我學(xué)python,但是之前一直詬病于它的縮進語法,所以也就一直沒入門,直到做了一段時間java web開發(fā)之后,回頭再看下python,覺得好簡單,于是就又愉快地使用它了,不過用它寫腳本真的太爽了,短短幾行代碼,搞定java一個繁瑣的項目,而且用起來也很輕便。

        最近一年多的時間,我用它處理過數(shù)據(jù)、用它跑數(shù)據(jù)庫統(tǒng)計過數(shù)據(jù),然后日程工作中我可以用它生成文件目錄、爬取資料,也感覺我對它越來越有好感,所以在這里強烈安利各位小伙伴都來學(xué)下python,特別是那些非開發(fā)崗位的小伙伴,python簡直是統(tǒng)計數(shù)據(jù)的利器,雖然不像廣告吹的那么秀,但是技多不壓身呀,而且它真的是可以極大提供我們的效率。

        最后的最后,再強調(diào)下,技術(shù)無罪,切勿用技術(shù)搞違法犯罪的事,不然日子真的就越來越有判頭了!

        技術(shù)無罪,切勿用技術(shù)搞違法犯罪的事,不然日子真的就越來越有判頭了!

        技術(shù)無罪,切勿用技術(shù)搞違法犯罪的事,不然日子真的就越來越有判頭了!

        重要的事情說三遍?。?!

        另外,今天忙著搞爬蟲了,設(shè)計模式的類圖還沒來得及補,明天要加下油了。好了,鐵子們,晚安吧

        參考內(nèi)容

        [1] ? ?https://zhuanlan.zhihu.com/p/346683119

        [2] ? ?https://www.cnblogs.com/shakin/p/3870439.html


        - END -


        瀏覽 115
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 欧美伊人电影 | 精品国产自 | 天天艹日日干 | 久久人人爽人人爽人人片aV免费 | 啪啪啪网站免费看 |