前言
前兩天爾羽說讓我爬一下菜鳥窩的教程視頻,這次就跟大家來說說Python爬取視頻的經(jīng)驗(yàn)
正文
菜鳥窩上有很多教程視頻贡耽,但是這些視頻好像沒有直接的下載地址要门,而且有些教程視頻還是有期限的,那么問題就產(chǎn)生了
我看的速度比較慢而且視頻又很多,沒等我看完視頻就到期了怎么辦港庄?這時(shí)候?qū)懸粋€(gè)爬蟲將這些教程視頻下載下來就很好地解決了這個(gè)問題
當(dāng)然,對(duì)于某些視頻網(wǎng)站的VIP電影恕曲、視頻之類的鹏氧,一般情況下是無法在沒有開通VIP的情況下用爬蟲下載的,因?yàn)樯婕暗嚼鎲栴}佩谣,同時(shí)數(shù)據(jù)傳輸也是加密的把还;想要看的話還是得開通會(huì)員再進(jìn)行爬取
回到這次的目標(biāo)上來,我們要爬取的是
上面的24章茸俭,共計(jì)202個(gè)教程視頻
接下來我們來看看我們應(yīng)該如何獲取這些視頻
首先我們看一下這個(gè)界面的源代碼中沒有關(guān)于課程視頻的信息吊履,那么我們點(diǎn)進(jìn)去一個(gè)視頻看看
通過開發(fā)者工具我們可以看到左側(cè)都是這次加載視頻是動(dòng)態(tài)加載的信息,我們一個(gè)個(gè)來看
首先是url调鬓,我們可以看到這個(gè)鏈接是 Post 方式請(qǐng)求的(然鵝實(shí)際上再通過postman測(cè)試可以知道艇炎,并不用帶上什么參數(shù)請(qǐng)求,嚇唬人呢...)
這就是url返回的數(shù)據(jù)腾窝,其中 hd 缀踪、shd 代表高清居砖、超清的視頻類型,而當(dāng)你訪問這個(gè)鏈接后會(huì)自動(dòng)下載一個(gè) m3u8 文件驴娃,這介紹一下
m3u8 文件是指UTF-8編碼格式的M3U文件奏候。M3U文件是記錄了一個(gè)索引純文本文件,打開它時(shí)播放軟件并不是播放它托慨,而是根據(jù)它的索引找到對(duì)應(yīng)的音視頻文件的網(wǎng)絡(luò)地址進(jìn)行在線播放
而我們下載視頻的方式就是通過向m3u8文件中的這些 .ts 的鏈接發(fā)送請(qǐng)求而下載一個(gè)個(gè) ts視頻流 (暫時(shí)這么稱呼)
下一個(gè)就是 chapters 鼻由,這里呢則是包含了所有24章視頻的一些基本信息
注意這里的 vid 參數(shù),之后我們會(huì)用到
這個(gè)就是網(wǎng)頁(yè)上加載的m3u8 文件
這看似亂碼的ts文件下載下來后就是一個(gè)幾秒鐘的視頻了
而我們最后要做的就是將這些 ts 文件合成為一個(gè) mp4 文件
那么如何來操作呢厚棵?
思路
通過請(qǐng)求 chapters 的鏈接獲取每一個(gè)章節(jié)中每一個(gè)lesson的播放 url 地址(就是返回中帶有 hd 蕉世、shd的),取出并請(qǐng)求 hd 的鏈接婆硬,下載m3u8文件狠轻,匹配m3u8文件中的每一個(gè) ts ,請(qǐng)求 ts 文件對(duì)應(yīng)的鏈接并下載到本地彬犯,最后合成為一個(gè)mp4視頻
來跟著代碼看一下
首先小編是在本地先用代碼創(chuàng)建好最終合成視頻的存放的空文件夾以便訪問
def mkd():
for i in range(1, 25):
finalpath = 'D:\\Python\\PycharmProject\\FinalCniao5\\{}'.format(i)
# 判斷路徑文件是否存在向楼,不存在則創(chuàng)建
f = os.path.exists(finalpath)
if not f:
os.makedirs(finalpath)
print('make file success...')
else:
print('file already exists...')
接著創(chuàng)建對(duì)應(yīng)章節(jié)的文件夾
# 防止 requests 開得太多
s = requests.session()
r_chapters = s.get('https://www.cniao5.com/api/v1/course/10153/chapters')
json_chapters = r_chapters.json()
# print(json_chapters)
for chapter in json_chapters:
# 每一個(gè)章節(jié)
chapter_name = chapter['bsort']
print(chapter_name)
# 根據(jù)課程數(shù)創(chuàng)建對(duì)應(yīng)的課程文件夾
path1 = self.file_path1.format(chapter_name)
f = os.path.exists(path1)
if not f:
os.makedirs(path1)
print('make file success...')
else:
print('file already exists...')
對(duì)章節(jié)中的每一個(gè)課程,獲取其 id谐区、key湖蜕、file_id 創(chuàng)建對(duì)應(yīng)的課程文件夾(用來保存ts文件)
for lessons in chapter['lessons']:
# 章節(jié)下的每一個(gè)課程
lessons_name = 'lessons' + str(lessons['bsort'])
# 獲取其id
video_id = lessons['video_info']['vid']
# 獲取 key
key = lessons['key']
# 后面用到
file_id = lessons['video_info']['file_id']
print(lessons_name, video_id)
# 每個(gè)視頻創(chuàng)建一個(gè)視頻id的文件夾
path = 'D:\\Python\\PycharmProject\\Cniao5\\{}\\{}'.format(chapter_name, lessons_name)
f = os.path.exists(path)
# 基于中斷后,創(chuàng)建文件時(shí)判斷宋列,若存在該文件夾則跳過對(duì)該視頻的下載昭抒,若不存在則繼續(xù)
對(duì)于之后則需要分為兩種情況,我不知道菜鳥窩是怎么想的炼杖,你可以看到對(duì)于有的視頻 vid 有具體的數(shù)值灭返,有的則是 0
也就是說對(duì)于 vid 有值的我們可以很容易構(gòu)造 url 鏈接從而獲取 m3u8 文件進(jìn)而下載 ts 視頻;但是對(duì)于沒有的來說就麻煩了坤邪,我們不能直接構(gòu)造這個(gè) url 鏈接
而對(duì)于這一類視頻則是這樣的
這類視頻不是通過 m3u8 來處理視頻的而是直接給了一個(gè) mp4 的地址熙含,那么也就是說對(duì)于 vid 為0的視頻我們需要訪問
https://playvideo.qcloud.com/getplayinfo/v2/1255567694/5285890782726972640
才可以拿到這個(gè)視頻,那么這個(gè) url 中后面的兩個(gè)參數(shù)是什么呢
這個(gè) 5285890782726972640
我們?cè)谏蠄D中可以發(fā)現(xiàn)就是之前提到的 file_id 這也是我們?yōu)槭裁匆@取的原因艇纺;而前面的1255567694
你多看幾個(gè)就知道這個(gè)是不變的
而當(dāng)你去訪問這個(gè) MP4 的鏈接時(shí)菜鳥窩會(huì)告訴你怎静,你沒有權(quán)限請(qǐng)求這個(gè)鏈接,what黔衡?
而這時(shí)候你要知道所謂爬蟲就是模擬人對(duì)瀏覽器進(jìn)行的操作而獲取一定的結(jié)果消约,那么我們可以帶上請(qǐng)求頭來試試,小編是在用 fiddler 抓包后肯定了這一點(diǎn)员帮,最后測(cè)試發(fā)現(xiàn)只要帶上 header 中的 referer 就可以訪問
而這個(gè) referer 也是有講究的或粮,這個(gè)后面跟的奇怪的參數(shù)正是上述中你們都快忘了的 key ,這個(gè)是每個(gè) lesson 中都有的
所以對(duì)于這種情況捞高,之后只要把請(qǐng)求 MP4 鏈接后的內(nèi)容以二進(jìn)制方式保存就行
此外還要注意對(duì)于 ts 文件氯材,在請(qǐng)求時(shí)的前綴是
https://vodi97egsxf.vod.126.net/vodi97egsxf/
而在合并 ts 文件時(shí)渣锦,我用的是通過Python調(diào)用 windows 自帶的合成的命令來合成,但是需要注意合成時(shí)候的文件名一定按 001氢哮,002袋毙,...,010冗尤,...听盖,099,100...如此排列裂七;而如果按 1皆看,2,3背零,...腰吟,10,11徙瓶,...毛雇,99,100 則合并不會(huì)成功
所以在保存時(shí)就應(yīng)該注意指定文件的名稱即可
好了看到這里相信你應(yīng)該有了一個(gè)基本的認(rèn)識(shí)了侦镇,需要完整源碼的也可以聯(lián)系小編