工欲善其事必先利其器,我們經常需要在B站上保存自己想要的“學習資料”。對於單一的視頻,我們可以用“B站下載助手”即時下載,安裝地址:https://chrome.google.com/webstore/detail/bilibili嗶哩嗶哩下載助手/bfcbfobhcjbkilcbehlnlchiinokiijp?hl=zh-CN

打開你要播放的視頻頁面,在頁面底部會彈出下載助手的主界面

下載安裝paddleNLP_文件名

操作比較傻瓜化,但是遇到多P視頻操作起來就不是很有好了,需要逐個點擊確認。課件什麼的一個個下很麻煩,有這工夫點開,視頻也都順便看完了,這時候就需要批量下載了。

解放雙手,首選Python,我們來看看Python中有什麼騷操作可以滿足我們的“學習需求”

安裝you-get

you-get是一個基於python的多媒體內容下載開源工具,在控制枱輸入pip3 install you-get ,我這裏已經安裝好了,

下載安裝paddleNLP_ide_02

安裝FFmpeg

you-get是基於ffmpeg進行視頻音頻處理的,如果不裝ffmpeg,通常下載的視頻是聲音畫面分開的兩個文件,後續需要合併及轉碼就不能完成了。下載地址:https://www.ffmpeg.org/

下載測試

  • 安裝完成後就可以進行下載了,先下載一個B站普通視頻,在命令行中輸入
you-get https://www.bilibili.com/video/BV1xK411773N

下載安裝paddleNLP_文件名_03


可以看到下載的是1080P的MP4文件(按默認最高畫質,有時候下載的是flv)。可以使用--info/-i以查看所有可用畫質與格式,使用--format以指定下載的格式

下載安裝paddleNLP_文件名_04


如果輸入的是一個多P視頻的地址,you-get會提示你使用--playlist參數

you-get: This is a multipart video. (use --playlist to download all parts.)

哦豁,這不就是我們尋找的批量下載嗎,趕緊試試

you-get --playlist https://www.bilibili.com/video/BV1B5411W7TW

然而這樣下載經常會遇到網絡延遲中斷,這時又得重新執行上面的命令。而且是逐個視頻下載的,經常會卡在某一個視頻上下不動(貌似服務器端有速率限制),網速並沒有很好地利用,此方法能用,但不好用,而且python還沒出手,還不夠風騷。

多線程下載

那怎樣才能發揮我們Python的功效,讓操作過程騷起來呢?既然一個命令行只能同時下載一個文件,那麼我們就採用多線程模式同時下載多個文件。下面這就走起來

import you_get
import threading
import os
import time

def download1080(count,url):
    print("thread "+ str(count) +" is running")
    os.system("you-get --format=dash-flv "+url)

def download720(count,url):
    print("thread "+ str(count) +" is running")
    os.system("you-get --format=dash-flv720 "+url)

def downloaddefault(count,url):
    print("thread "+ str(count) +" is running")
    os.system("you-get "+url)

def showinfo(count,url):
    print("thread "+ str(count) +" is running")
    os.system("you-get -i "+url)

def test(arg):
    print("thread "+ str(arg) +" is running")
    os.system("ping www.baidu.com")
    print("thread "+ str(arg) +" finish")


if __name__ == '__main__':

    url_seed = 'https://www.bilibili.com/video/BV1MJ411u7Bc?p='
    thread_list = []
    url_num = 33
    thread_num = 8

    for i in range(1,url_num+1):
        #為每個新URL創建下載線程
        url = url_seed + str(i)
        t = threading.Thread(target=download720, args=(i,url))
        #加入線程池並啓動
        thread_list.append(t)
        t.start()
        
        #print(thread_list[0])

        #當線程池滿時,等待線程結束
        while len(thread_list)>thread_num:  
            #移除已結束線程
            thread_list = [x for x in thread_list if x.is_alive()]
            time.sleep(3)
           # print("running threads_________" + str(thread_list))

        pass

這裏採用os.system()函數提交shell命令。首先定義幾個函數分別下載不同清晰度格式,"you-get --format=dash-flv "、"you-get --format=dash-flv720 "、"you-get --format=dash-flv480 "、"you-get --format=dash-flv360 "。

確定下載視頻的URL鏈接公共部分,去掉數字後綴

url_seed = 'https://www.bilibili.com/video/BV1MJ411u7Bc?p='

B站中多P視頻的URL鏈接有兩種形式,第一種是剛點開標題後出現的合集鏈接,第二種是點開右側播放列表任意p視頻時出現,這裏需要傳入的是第二種URL鏈接,下載對應的p=n的視頻

#點開總標題時出現
https://www.bilibili.com/video/BV1MJ411u7Bc

#點開各Part
https://www.bilibili.com/video/BV1MJ411u7Bc?p=1
https://www.bilibili.com/video/BV1MJ411u7Bc?p=2
https://www.bilibili.com/video/BV1MJ411u7Bc?p=3
......

thread_list列表充當一個簡單線程池,存放活動的下載線程。

url_num = 33 代表分P視頻的總數,在右側選集列表查看,這裏是33。

下載安裝paddleNLP_線程池_05


thread_num =8 定義了線程池的線程數量上限,根據自己電腦的核心數和網絡帶寬確定,通常4~8就夠用了。

下面就為每一個URL單獨創建下載線程,啓動下載,注意查看網頁上最高支持的清晰度,選取不同的目標函數,這裏最高清晰度為720P,選擇target=download720。當線程池滿了就等待先前的下載結束,每隔3秒查詢一次

for i in range(1,url_num+1):
        #為每個新URL創建下載線程
        url = url_seed + str(i)
        t = threading.Thread(target=download720, args=(i,url))
        #加入線程池並啓動
        thread_list.append(t)
        t.start()
        
        #print(thread_list[0])

        #當線程池滿時,等待線程結束
        while len(thread_list)>thread_num:  
            #移除已結束線程
            thread_list = [x for x in thread_list if x.is_alive()]
            time.sleep(3)

將上述代碼保存成download_with_you-get.py文件,下載新的合集時需要修改對應的url_seed,url_num和下載清晰度,然後在shell命令行中輸入

python download_with_you-get.py

或者將上述命令保存成bat文件點擊運行,這樣就開始下載啦

下載安裝paddleNLP_文件名_06


下載安裝paddleNLP_下載安裝paddleNLP_07


下載安裝paddleNLP_線程池_08

我們看下效果,速度簡直飛起,500Mbps帶寬都跑滿了,而且同時把彈幕文件也下載下來了,保存成xml文件,本地也可以看彈幕了,美滋滋。不過對於大多數課程視頻,我們並不需要彈幕,可以在上面的bat文件加入一行 del *.xml 刪除之。

如果網絡負載過大,有時候會中斷,或者請求時間過長導致程序退出,沒關係,重新運行上面的bat就好了,you-get會自動斷點續傳,已下載的會跳過該文件。如果程序正常退出,那麼所有的視頻都下載好了。

下載安裝paddleNLP_下載安裝paddleNLP_09

文件重命名

不過等等,我們下載的視頻文件都帶了很長的父標題前綴,有時候文件列表裏很難完全顯示,需要把它簡化一下,更清楚地看到是第幾集,如上圖,只需要保留小括號裏邊的內容作為文件名即可。

新建rename.py文件,內容如下

coding: utf-8
import os
path = os.getcwd() +'\\'     

for f in os.listdir(path):
    if f.endswith(u'.mp4'):
        oldname = path + f 
        #print(f)
        f1 = f.split("(")
        try:
            f2 = f1[1].split(")")
        except:
            f2 = f1
        if f2[0].endswith(u'.mp4'):
            newname = path + f2[0]
        else:
            newname=path + f2[0] + '.mp4'
        os.rename(oldname,newname) 
        print(oldname,'======>',newname)

遍歷當前文件夾下的所有文件,找出我們下載的MP4文件名,分割出小括號中間的內容作為新文件名,採用os.rename函數重命名文件。如果文件名中沒有小括號(已經處理過),則沿用舊文件名,這樣文件名就格式化好了

下載安裝paddleNLP_文件名_10


大會員視頻如何下載那些需要登錄才能下載的視頻呢,這時候就要用到cookies信息了。首先需要使用 firefox 火狐瀏覽器事先登錄視頻網站平台賬號,在開始運行中輸入%appdata%/Mozilla/firefox/profiles確定,會顯示類似下面這樣的文件夾

下載安裝paddleNLP_文件名_11


進入這個文件夾,找到 cookies.sqlite 文件,獲得完整文件路徑

// 每個人的文件夾名稱可能不一樣
86mdqb8b.default-release   
 
//完整文件路徑
C:\Users\pizh12thu\AppData\Roaming\Mozilla\Firefox\Profiles\86mdqb8b.default-release\cookies.sqlite

在shell中輸入以下內容,就可以下載大會員視頻了

set cookie=C:\Users\pizh12thu\AppData\Roaming\Mozilla\Firefox\Profiles\86mdqb8b.default-release\cookies.sqlite
you-get -c %cookie% https://www.bilibili.com/bangumi/play/ep75275

指定--format=dash-hdflv2就可以下載大會員HD畫質視頻,我們修改一下py文件,提交命令時加上“-c %cookie%”參數,記得字符串前面加上r強制不轉義,url_seed和url_num都做相應修改,target=downloadhd使用最高下載格式

def download1080(count,url):
    print("thread "+ str(count) +" is running")
    os.system(r"you-get -c %cookie% --format=dash-flv "+url)

def download720(count,url):
    print("thread "+ str(count) +" is running")
    os.system(r"you-get -c %cookie% --format=dash-flv720 "+url)

def downloadhd(count,url):
    print("thread "+ str(count) +" is running")
    os.system(r"you-get -c %cookie% --format=dash-hdflv2 "+url)

if __name__ == '__main__':

    url_seed = 'https://www.bilibili.com/bangumi/play/ep752' #後綴 + 74~85
    thread_list = []
    url_num = 85
    thread_num = 8

    for i in range(74,url_num+1):
        #為每個新URL創建下載線程
        url = url_seed + str(i)
        t = threading.Thread(target=downloadhd, args=(i,url))
        #加入線程池並啓動
        thread_list.append(t)
        t.start()

下載安裝paddleNLP_文件名_12

下載安裝paddleNLP_文件名_13