Python3 網絡爬蟲:視頻下載,那些事兒!

點擊上方“Python爬蟲與數據挖掘”,進行關注

回覆“書籍”即可獲贈Python從入門到進階共10本電子書

一腔熱血勤珍重,灑去猶能化碧濤。

1

前言

你知道的視頻下載“姿勢”,有哪些嗎?

本文絕對有你意想不到的玩法!

2

陳年往事

視頻下載,跟圖片下載其實並無差別,甚至更簡單。

玩過視頻下載的,應該對「you-get」並不陌生。

「you-get」支持各大視頻網站的視頻下載,國內外加起來近 80 家。像國內的愛奇藝、騰訊視頻、抖音、快手、B站、A站,國外的 Youtube、Twitter、TED、Instagram等等。

你只需要一行命令,就可以輕鬆下載想要的視頻。

you-get https://www.bilibili.com/video/BV1NZ4y1j7nw

比如,下載“黑人擡棺原版視頻”。

簡單好用!

URL:https://github.com/soimort/you-get

有了「you-get」就“無敵”了嗎?

並非如此,「you-get」對於短視頻下載較好。對於愛奇藝、騰訊視頻裏面的長視頻內容,支持就有些侷限。比如 VIP 付費內容,只能下載個 6 分鐘時長的片頭。

付費的 VIP 內容,也可以下載嗎?

當然可以。

早在 2 年前,我就搭建過視頻解析網站。

甭管是愛奇藝、騰訊、還是優酷,也甭管是免費視頻還是付費視頻,只要給個視頻網址鏈接,分分鐘解析播放。

用自己搭建的這個解析網站,白嫖了半年的視頻。後來,用我這個網站看視頻的人越來越多,索性就給它停了。

說實話,自己白嫖就算了,還帶着大家一起白嫖,就有些過分了。

後來付費意識逐漸增強,不想再做白嫖黨,也就辦了愛奇藝的年度會員。

這種視頻解析網站現在仍然有很多,但大多數都早已不能用了。

在網絡上,有個叫「視頻解析接口」的東西

這些大大小小的視頻解析網站,其實就是調用的這些第三方「視頻解析接口」實現的。

背後的原理也並不複雜,就是拿着一些 VIP 會員賬號,在後臺解析視頻,然後分享給別人看的。

隨着版權意識、版權管理的加強,以及技術的更新迭代,這類「視頻解析接口」也就逐漸失效了。

在網絡上,還有個叫「資源採集網」的東西。

「視頻解析接口」大量失效,那幫搞「灰產」的人另闢蹊徑,既然視頻無法解析,那就搜索資源吧。

現在,與其叫它們「視頻解析接口」,不如叫它們「視頻搜索接口」。

這些「視頻搜索接口」拿着視頻地址,去「資源採集網」匹配資源。

「資源採集網」其實就是一個大型網絡爬蟲,它會採集網絡上的視頻資源,並將它們整合到一起。

這裏的說頭,太多了。扯遠了,迴歸正題。

3

視頻下載

背景講完了,那就進入今天的主題,從「資源採集網」下載我們想要的視頻。

以「越獄第一季」爲例,越獄算是帶我入坑的美劇之一,Miller 太帥了。

本文要爬的網站名叫「ok 資源網」,長這樣:

URL:http://www.jisudhw.com/

思路也不復雜,搜索、解析、下載。

1、搜索

想要下載視頻,首先得找到資源,採用站內搜索很簡單。

抓搜索的請求包也特別簡單,教一個小技巧:

第一步輸入要搜索的內容,第二步打開並清理 Network,第三步點擊搜索按鈕。

Network 裏第一個彈出的就是搜索的請求包。

可以看到,這是一個 POST 請求。

之前的實戰內容,無論是下載小說,還是下載圖片,都是 GET 請求。

GET 請求,就是字面意思,從服務器獲取數據。POST 請求,也是字面意思,給服務器發送數據。


因爲我們是搜索嘛,得告訴服務器,咱搜索啥,給服務器傳遞數據,就是通過 POST。

能 POST 的數據有很多,可以是簡單的字符串、也可以是一張圖片。

POST 啥數據,那就看服務器要啥數據,要啥給啥,就這麼簡單。

看一下搜索的結果頁,不難發現,搜索結果存儲在 class 屬性爲 xing_vb4 的 span 標籤裏。

沒有難度啊,直接搞起。根據瀏覽器抓包結果,填寫 data 信息即可。由於網站也有簡單的 Header 反爬蟲,所以一些必要的 Headers 信息也要填寫。

import requests
from bs4 import BeautifulSoup


search_keyword = '越獄第一季'
search_url = 'http://www.jisudhw.com/index.php'
serach_params = {
    'm': 'vod-search'
}
serach_headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36',
    'Referer': 'http://www.jisudhw.com/',
    'Origin': 'http://www.jisudhw.com',
    'Host': 'www.jisudhw.com'
}
serach_datas = {
    'wd': search_keyword,
    'submit': 'search'
}


r = requests.post(url=search_url, params=serach_params, headers=serach_headers, data=serach_datas)


r.encoding = 'utf-8'
server = 'http://www.jisudhw.com'
search_html = BeautifulSoup(r.text, 'lxml')
search_spans = search_html.find_all('span', class_='xing_vb4')
for span in search_spans:
    url = server + span.a.get('href')
    name = span.a.string
    print(name)
    print(url)

順利拿到詳情頁地址:

2、解析

解析詳情頁,獲得下載鏈接,我們先看下詳情頁都有啥。

URL:http://www.jisudhw.com/?m=vod-detail-id-15409.html

視頻詳情頁,至少有兩種播放類型,一種是 m3u8 ,一種是 kuyun 。

拿到其中一種鏈接即可,我們以 m3u8 爲例進行說明。

可以看到,視頻鏈接都放在了 input 標籤裏,直接匹配:

import requests
from bs4 import BeautifulSoup


detail_url = 'http://www.jisudhw.com/?m=vod-detail-id-15409.html'
r = requests.get(url = detail_url)
r.encoding = 'utf-8'
detail_bf = BeautifulSoup(r.text, 'lxml')
num = 1
serach_res = {}
for each_url in detail_bf.find_all('input'):
    if 'm3u8' in each_url.get('value'):
        url = each_url.get('value')
        if url not in serach_res.keys():
            serach_res[url] = num
        print('第%03d集:' % num)
        print(url)
        num += 1

將結果都存放到了字典裏,這樣方便後續視頻鏈接和視頻名稱的一一對應。

3、下載

視頻下載,一般而言,無非兩種情況。

一種,鏈接明確是以 mp4、mkv、rmvb 這類視頻格式後綴爲結尾的鏈接,這種下載很簡單,跟圖片下載方法一樣,就是視頻文件要比圖片大而已。

另一種,鏈接是以 m3u8 這類分段視頻後綴結尾的鏈接。啥是分段視頻?

抓包看一下就知道了,打開視頻播放鏈接:

http://youku.com-youku.net/share/f0d48bde60d407c45af7ca00d1ef927b

現在很多視頻都是分段存儲的,你看視頻的時候,其實是在加載一個個 ts 視頻片段,一個片段是幾秒鐘的視頻。

這種視頻要怎麼下載?怎麼將 ts 視頻片段組合成一個視頻?

其實,如果知道方法,就很簡單。

m3u8 這種格式的視頻,就是由一個個 ts 視頻片段組成的。

一個 m3u8 文件並不大,你可以把它理解爲鏈表,每個 ts 視頻片段文件,都有下一個時序的 ts 視頻片段的地址。

記住一點,解決音頻和視頻的一些問題,可以看看 FFmpeg,它的中文名叫多媒體視頻處理工具。

FFmpeg 有非常強大的功能包括視頻採集、視頻格式轉換、視頻抓圖、給視頻加水印等功能。

這種 ts 視頻片段合成,格式轉換問題,交給 FFmpeg 就好了。

要使用 FFmpeg,需要先安裝配置一番。

下載地址:https://ffmpeg.zeranoe.com/builds/

安裝好後,記得配置環境變量。

FFmpeg 也有 Python API 接口,名字叫 ffmpy3,安裝好 FFmpeg 後,可以直接通過 pip 安裝。

pip install ffmpy3

都弄好,就可以愉快的玩耍了。

比如想要下載 m3u8 文件。

URL:

http://youku.com-youku.net/20180614/11920_4c9e1cc1/index.m3u8

可以在命令行輸入如下指令:

ffmpeg -i "http://youku.com-youku.net/20180614/11920_4c9e1cc1/index.m3u8" "第001集.mp4"

視頻會保存爲「第001集.mp4」。

如果用 Python 接口,也只需要兩行代碼:

import ffmpy3
ffmpy3.FFmpeg(inputs={'http://youku.com-youku.net/20180614/11920_4c9e1cc1/index.m3u8': None}, outputs={'第001集.mp4':None}).run()

FFmpeg 自動整合 ts 分段視頻,並保存爲 mp4 格式的視頻。

是不是很簡單?

4

整合代碼

代碼整合在一起,開始下載電視劇。

import os
import ffmpy3
import requests
from bs4 import BeautifulSoup
from multiprocessing.dummy import Pool as ThreadPool


search_keyword = '越獄第一季'
search_url = 'http://www.jisudhw.com/index.php'
serach_params = {
    'm': 'vod-search'
}
serach_headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36',
    'Referer': 'http://www.jisudhw.com/',
    'Origin': 'http://www.jisudhw.com',
    'Host': 'www.jisudhw.com'
}
serach_datas = {
    'wd': search_keyword,
    'submit': 'search'
}




video_dir = ''
    
r = requests.post(url=search_url, params=serach_params, headers=serach_headers, data=serach_datas)
r.encoding = 'utf-8'
server = 'http://www.jisudhw.com'
search_html = BeautifulSoup(r.text, 'lxml')
search_spans = search_html.find_all('span', class_='xing_vb4')
for span in search_spans:
    url = server + span.a.get('href')
    name = span.a.string
    print(name)
    print(url)
    video_dir = name
    if name not in os.listdir('./'):
        os.mkdir(name)
        
    detail_url = url
    r = requests.get(url = detail_url)
    r.encoding = 'utf-8'
    detail_bf = BeautifulSoup(r.text, 'lxml')
    num = 1
    serach_res = {}
    for each_url in detail_bf.find_all('input'):
        if 'm3u8' in each_url.get('value'):
            url = each_url.get('value')
            if url not in serach_res.keys():
                serach_res[url] = num
            print('第%03d集:' % num)
            print(url)
            num += 1


def downVideo(url):
    num = serach_res[url]
    name = os.path.join(video_dir, '第%03d集.mp4' % num)
    ffmpy3.FFmpeg(inputs={url: None}, outputs={name:None}).run()
            
# 開8個線程池
pool = ThreadPool(8)
results = pool.map(downVideo, serach_res.keys())
pool.close()
pool.join()

由於視頻太大了,要是一個一個地下載,有些慢,適當開個線程,8 線程下載。

來吧,一起看「越獄」吧!

5

最後

本文僅是探討一些關於視頻下載的技術,切勿濫用。

支持正版,從我做起。

------------------- End -------------------

往期精彩文章推薦:

歡迎大家點贊,留言,轉發,轉載,感謝大家的相伴與支持

想加入Python學習羣請在後臺回覆【入羣

萬水千山總是情,點個【在看】行不行

/今日留言主題/

隨便說一兩句吧~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章