前言後臺有網友留言,問m3u8文件到底是什麼文件,為何有的瀏覽器能直接播放,但有的就只提示下載?其實m3u8文件是指用UTF-8編碼格式的M3U文件,而M3U文件則是記錄了一個索引的純文本文件,它裡面記錄的索引通常是一系列視頻文件的地址,對於支持在線播放的視頻播放器比如potplayer、kmplayer等都可以直接用打開網址的方式來在線觀看,一些內置播放功能的手機瀏覽器也是支持直接播放的,而PC端的瀏覽器多半會提示下載該類文件。由於我國網絡的特殊性,某些優秀的外語影視劇無法在一些大型視頻網站觀看,因此就有一些人想出一些辦法,將其存儲在自建的伺服器上,然而個人的財力畢竟有限,在受制於各種成本的壓力下,將一個較大的視頻分割成上千個小視頻後,分段存儲在伺服器上,就可以較大程度上緩解一些壓力。對於視頻觀看者而言,這樣的視頻在線觀看體驗並不是特別好,將其離線下載於本地就是一個較好的辦法。這一篇文章中,我們來研究一下如何用Python來自動下載這類視頻的技術。人工處理m3u8文件首先將m3u8文件下載,比如以一部可供英語聽力學習的情景劇《Holmes **》為例(此處僅做技術用例參考,所測試下載文件已經刪除),我們得到的m3u8地址是這樣的:https://***.com/2020***/***/index.m3u8,將其輸入瀏覽器地址後,下載得到的m3u8文件如下圖所示:
從上圖可以看出,在這個得到的文件中並沒有視頻的索引文件,但卻隱藏著一個新的m3u8地址,因此,需要將該地址重新匹配到原地址的https://***.com/2020***/***/字串之後,形成新的m3u8地址,即:https://***.com/2020***/***/1000k/hls/index.m3u8,然後再將該地址輸入瀏覽器地址欄,即可下載得到新的m3u8地址,是這樣的:
![]()
上述圖片所示的地址即是對應的分割好的小視頻地址,接下來就需要將其匹配到剛才得到的網址上,比如第五個視頻地址即為:https://***.com/2020***/***/1000k/hls/906ffc7faa0000004.ts,將其輸入瀏覽器地址欄後,即可下載一個小視頻,截圖如下:
![]()
可是,這樣被分割後的視頻有多少個呢?用程序統計的結果是1858個,如果每一個都用手工下載,那是一個巨大的工作量。
程序自動下載用Python來完成這項工作,會顯得非常簡單。首先我們解析一次m3u8文件,如果它裡面有隱藏的地址,那就再讀取一次,代碼如下:
import requests
URL_M3U8 = 'https://***.com/2020***/***/index.m3u8'def read_m3u8(urlm3u8): m3u8filename = urlm3u8.split('/')[-1] urlprex = urlm3u8[:len(urlm3u8)-len(m3u8filename)-1] m3u8file_data = requests.get(urlm3u8) m3u8filename = urlm3u8.split('/')[-1] open(m3u8filename, 'wb').write(m3u8file_data.content)
lstfile = [] with open(m3u8filename) as f: for item in f.readlines(): if item[0] != r'#': if item[0] != '/': item = '/' + item.strip() lstfile.append(urlprex + item) return lstfile
def read_main(urlm3u8): m3u8filename = urlm3u8.split('/')[-1] urlprex = urlm3u8[:len(urlm3u8)-len(m3u8filename)-1] lstfile = read_m3u8(urlm3u8) if len(lstfile) == 1: with open(m3u8filename) as f: for item in f.readlines(): if item[0] != '#': if item[0] != '/': urlprex += '/' lstfile = read_m3u8(urlprex + item.strip()) return lstfile
lstfile = read_main(URL_M3U8)在得到所有小視頻的列表後,可以用下述代碼將所有的文件下載到指定的文件夾:for i, item in enumerate(lstfile): print("第{}個文件正在下載,共{}個文件。".format(i+1,len(lstfile))) myfile = requests.get(item) open(r'tmp/'+item.split('/')[-1], 'wb').write(myfile.content)下載完成後,為了視頻觀看的連續性,需要將所有小視頻合併成一個大視頻文件:import os, globlstfile = sorted(glob.glob(r'tmp/*.ts'), key=os.path.getmtime)mergecmd = 'copy /b ' + '+'.join(lstfile) + ' new.ts'os.system(mergecmd)注意,由於視頻文件的先後順序要保證,因此,將抓取的文件按照其創建的時間進行了排序,之後調用copy命令進行了合併,以上代碼在windows 10中測試成功。小結本文對m3u8文件進行了分析,並介紹了如何用Python自動提取其中地址並進行離線下載的技術。在此聲明,以上方法僅供純技術探討,不得作為盜取正版視頻的方法,請尊重版權,否則後果自負。