<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 7473字,需瀏覽 15分鐘

           ·

          2021-10-25 01:13


          老實(shí)說(shuō)是不是因?yàn)闃?biāo)題才點(diǎn)進(jìn)來(lái)的雖然我這里沒(méi)有小電影,但是今天的內(nèi)容也是實(shí)打?qū)嵉母韶洠?/span>這叫授人以魚(yú)不如授人以漁,有了這技術(shù),小電影不分分鐘的事嘛

          前言

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

          知識(shí)擴(kuò)展

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

          m3u8是什么?

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

          從上面的原理圖中我們可以得到以下知識(shí)點(diǎn):

          • 首先m3u8并非是視頻格式,而是視頻文件的索引。
          • ts文件才是我們真正播放的視頻資源。ts是日本高清攝像機(jī)拍攝下進(jìn)行的封裝格式,全稱(chēng)為MPEG2-TSts即"Transport Stream"的縮寫(xiě)。MPEG2-TS格式的特點(diǎn)就是要求從視頻流的任一片段開(kāi)始都是可以獨(dú)立解碼的。

          m3u8通常分兩種格式,一種是單碼率(固定分辨率),一種是多碼率(包含多種分別率)。下面就是一個(gè)單碼率的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

          這個(gè)就是一個(gè)多碼率的m3u8文件,從多碼率的文件格式可以看出來(lái),多碼率中包括了多個(gè)單碼率是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其實(shí)是m3u文件的擴(kuò)展(參考文檔2),這可能就是為什么沒(méi)有找到m3u8相關(guān)詞條的原因吧,同時(shí)在m3u的詞條中發(fā)現(xiàn)了M#U文件的指令描述(每個(gè)字段的含義):

          #EXTM3U?//必需,表示一個(gè)擴(kuò)展的m3u文件

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

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

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

          #EXT-X-TARGETDURATION:5?//每個(gè)視頻分段最大的時(shí)長(zhǎng)(單位秒)

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

          #EXTINF:?//每個(gè)切片的時(shí)長(zhǎng)

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

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

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

          抓取、解析、下載

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

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

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

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

          解析m3u8文件

          解析m3u8文件最核心的地方是分析m3u8的文件結(jié)構(gòu),然后根據(jù)其文件內(nèi)容寫(xiě)出對(duì)應(yīng)的解析邏輯。這里我推薦直接用requests庫(kù)模擬調(diào)用,然后分析響應(yīng)結(jié)果,因?yàn)橛梦谋竟ぞ咧?lèi)的查看m3u8文件的話,換行符\n、制表符\t這些看起來(lái)不夠直觀,但是requests就不會(huì)有這個(gè)問(wèn)題,因?yàn)槲覀兘馕龅木褪?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">requests的響應(yīng)結(jié)果。

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

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

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

          解析ts視頻地址

          因?yàn)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">python代碼都很簡(jiǎn)單,代碼量也不多,所以就不展開(kāi)講了,看代碼注釋?xiě)?yīng)該可以看懂。這個(gè)方法主要是為了獲取ts視頻文件的地址。

          import?requests

          def?getTsFileUrlList(m3u8Url):
          ????#?組裝請(qǐng)求頭
          ????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'
          ????????????}
          ????#?請(qǐng)求?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:
          ??????#?以下拼接方式可能會(huì)根據(jù)自己的需求進(jìn)行改動(dòng)
          ??????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;

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

          下載文件

          這里的方法是下載并解密視頻資源,這里我加了一個(gè)解密操作,因?yàn)樽⑨寜蚯逦晕乙膊贿^(guò)多贅述了

          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ā)送下載請(qǐng)求
          ????????ts_video?=?requests.get(url?=?url,?headers=headers)
          ????????#?保存文件
          ????????with?open('{}/{}.ts'.format(fileSavePath,?str(index?+?1)),?'wb')?as?file:
          ????????????#?視頻資源解密
          ????????????context?=?decrypt(ts_video.content);
          ????????????#?文件寫(xiě)入
          ????????????file.write(context)
          ????????????print('正在寫(xiě)入第{}個(gè)文件'.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庫(kù),安裝方式如下:

          ?pip3?install?pycryptodome

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

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

          合并視頻

          合并視頻就更簡(jiǎn)單了,就是講前面我們保存的視頻合并成一個(gè)完整的視頻,合并完之后的格式是mp4

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

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

          272個(gè)ts文件合并成一個(gè)視頻文件:

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

          完整代碼如下:

          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:
          ??????#?以下拼接方式可能會(huì)根據(jù)自己的需求進(jìn)行改動(dòng)
          ??????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('正在寫(xiě)入第{}個(gè)文件'.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);

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

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

          總結(jié)

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

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

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

          最后,免費(fèi)為python做一個(gè)無(wú)償廣告。我一直覺(jué)得python是一門(mén)不錯(cuò)的語(yǔ)言,特別是作為腳本使用的時(shí)候,真的是太方便了,今天它也依然沒(méi)有讓我失望。

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

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

          最后的最后,再?gòu)?qiáng)調(diào)下,技術(shù)無(wú)罪,切勿用技術(shù)搞違法犯罪的事,不然日子真的就越來(lái)越有判頭了!

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

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

          重要的事情說(shuō)三遍!!!

          另外,今天忙著搞爬蟲(chóng)了,設(shè)計(jì)模式的類(lèi)圖還沒(méi)來(lái)得及補(bǔ),明天要加下油了。好了,鐵子們,晚安吧

          參考內(nèi)容

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

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


          - END -


          瀏覽 115
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久热精品在线视频 | 免费看的黄色视频 | 碰人人操 | 一级片免费播放 | 欧美成人96毛片 |