工欲善其事必先利其器,我們經常需要在B站上保存自己想要的“學習資料”。對於單一的視頻,我們可以用“B站下載助手”即時下載,安裝地址:https://chrome.google.com/webstore/detail/bilibili嗶哩嗶哩下載助手/bfcbfobhcjbkilcbehlnlchiinokiijp?hl=zh-CN
打開你要播放的視頻頁面,在頁面底部會彈出下載助手的主界面
操作比較傻瓜化,但是遇到多P視頻操作起來就不是很有好了,需要逐個點擊確認。課件什麼的一個個下很麻煩,有這工夫點開,視頻也都順便看完了,這時候就需要批量下載了。
解放雙手,首選Python,我們來看看Python中有什麼騷操作可以滿足我們的“學習需求”
安裝you-get
you-get是一個基於python的多媒體內容下載開源工具,在控制枱輸入pip3 install you-get ,我這裏已經安裝好了,
安裝FFmpeg
you-get是基於ffmpeg進行視頻音頻處理的,如果不裝ffmpeg,通常下載的視頻是聲音畫面分開的兩個文件,後續需要合併及轉碼就不能完成了。下載地址:https://www.ffmpeg.org/
下載測試
- 安裝完成後就可以進行下載了,先下載一個B站普通視頻,在命令行中輸入
you-get https://www.bilibili.com/video/BV1xK411773N
可以看到下載的是1080P的MP4文件(按默認最高畫質,有時候下載的是flv)。可以使用--info/-i以查看所有可用畫質與格式,使用--format以指定下載的格式
如果輸入的是一個多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。
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文件點擊運行,這樣就開始下載啦
我們看下效果,速度簡直飛起,500Mbps帶寬都跑滿了,而且同時把彈幕文件也下載下來了,保存成xml文件,本地也可以看彈幕了,美滋滋。不過對於大多數課程視頻,我們並不需要彈幕,可以在上面的bat文件加入一行 del *.xml 刪除之。
如果網絡負載過大,有時候會中斷,或者請求時間過長導致程序退出,沒關係,重新運行上面的bat就好了,you-get會自動斷點續傳,已下載的會跳過該文件。如果程序正常退出,那麼所有的視頻都下載好了。
文件重命名
不過等等,我們下載的視頻文件都帶了很長的父標題前綴,有時候文件列表裏很難完全顯示,需要把它簡化一下,更清楚地看到是第幾集,如上圖,只需要保留小括號裏邊的內容作為文件名即可。
新建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函數重命名文件。如果文件名中沒有小括號(已經處理過),則沿用舊文件名,這樣文件名就格式化好了
大會員視頻如何下載那些需要登錄才能下載的視頻呢,這時候就要用到cookies信息了。首先需要使用 firefox 火狐瀏覽器事先登錄視頻網站平台賬號,在開始運行中輸入%appdata%/Mozilla/firefox/profiles確定,會顯示類似下面這樣的文件夾
進入這個文件夾,找到 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()