日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python爬取bilibili数据_如何使用Python爬取bilibili视频(详细教程)

發布時間:2023/12/8 python 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python爬取bilibili数据_如何使用Python爬取bilibili视频(详细教程) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Python爬取bilibili視頻

摘要

為了解決PC端的bilibili無法下載視頻的問題,使用python語言可以實現一個能夠爬取bilibili某個視頻資源(不包括會員視頻)的程序。采用整個視頻下載與分片拼接視頻兩種思路實現程序,比較兩種方式的下載效率,最終采用分片下載視頻再拼接成為一個視頻的方式實現了bilibili視頻(不包括會員視頻)的下載。實現bilibili視頻下載,可以用于離線觀看或者收集視頻素材用于剪輯,具有一定實際的用途。

引言

由于bilibili只能通過手機app下載視頻緩存,電腦打開需要將緩存從手機將文件傳到電腦,不方便。

本文從如何借助chorme瀏覽器的開發者工具與搜索引擎了解bilibili請求視頻資源的方式、如何使用python的各種庫模擬瀏覽器發送請求去獲取bilibili服務器的視頻資源、運行實現的python爬蟲程序并下載一個視頻三個步驟介紹bilibili視頻爬蟲的實現。

系統結構

使用到的工具

IntelliJ IDEA 2018.2.4 x64(集成開發環境)

Python3.8(編程語言)

requests庫(發送http請求)

lxml庫(xpath解析)

json庫(解析json數據)

ffmpeg(合并音頻和視頻)

實現功能的原理

通過輸入視頻編號再拼接成為url,通過用python的request庫使用url模擬瀏覽器請求訪問視頻頁面。使用lxml庫與json庫從返回的響應信息中提取到視頻資源的鏈接,再去模擬瀏覽器請求獲取音頻和視頻資源,再將獲得的音頻和視頻資源合并保存到本地。

實現代碼

1.了解url結構

使用chorme瀏覽器,先到bilibili首頁隨便點開一個視頻如圖3.1所示。圖3.1

進入視頻頁面后,點進第二p,開始分析該頁面的請求的結構如圖3.2所示。圖3.2

可以看到請求由url和一個參數p拼接而成。

2.編寫輸入程序

訪問頁面需要的url結構為https://www.bilibili.com/video/BV號?p=,我們下載視頻的話可以輸入視頻p數的分類來下載多個分p視頻,總結以上需要輸入程序的信息就包括視頻BV號、起始p、結束p這三個信息,編寫代碼如下。

if __name__ == '__main__':

# 輸入bilibili視頻的BV號

bv = input('視頻BV號:')

url='https://www.bilibili.com/video/'+bv

# 選擇視頻從第幾p開始到第幾p結束

startPart=input('起始P:')

endPart = input('終止P;')

print("url:",url)

print("startPart:",startPart)

print("endPart:",endPart)

輸出結果如圖3.3所示。圖3.3

3.解析網頁,找到下載視頻的鏈接

在chorme瀏覽器按下F12打開開發者工具,查找頁面元素,找到在head標簽的第3個script標簽里面存有視頻播放信息,劃紅線的baseUrl既是視頻資源鏈接如圖3.4所示。圖3.4

根據網上搜索了解到bilibili2018年后的視頻分為音頻與視頻,但是在此標簽里面沒有找到與音頻有關的鍵,這里我直接拷貝標簽文本,放到文本編輯器notepad++中,查找“audio”發現了音頻鍵值對,如圖3.5所示。圖5

其中“baseUrl”后面的內容就是音頻資源鏈接,如圖3.6所示。3.6

這里我需要先通過發送請求獲取網頁二進制文本信息,然后再通過解析文本獲取需要的鏈接。

增加函數getBiliBiliVideo,使用到的庫有json、os、requests、etree,代碼如下。

import json

import requests

from lxml import etree

# 防止因https證書問題報錯

requests.packages.urllib3.disable_warnings()

headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3970.5 Safari/537.36',

'Refer'

'er': 'https://www.bilibili.com/'

}

'''

獲取bilibili視頻的主要函數

@param url 視頻頁面url 結構為:url?參數

@param p 視頻p數

@param bv 視頻bv數

'''

def getBiliBiliVideo(url,p,bv):

session = requests.session()

res = session.get(url=url,headers=headers,verify=False)

_element = etree.HTML(res.content)

# 獲取window.__playinfo__的json對象,[20:]表示截取'window.__playinfo__='后面的json字符串

videoPlayInfo = str(_element.xpath('//head/script[3]/text()')[0].encode('utf-8').decode('utf-8'))[20:]

videoJson = json.loads(videoPlayInfo)

# 獲取視頻鏈接和音頻鏈接

try:

# 2018年以后的b站視頻由.audio和.video組成 flag=0表示分為音頻與視頻

videoURL = videoJson['data']['dash']['video'][0]['baseUrl']

audioURl = videoJson['data']['dash']['audio'][0]['baseUrl']

flag=0

except Exception:

# 2018年以前的b站視頻音頻視頻結合在一起,后綴為.flv flag=1表示只有視頻

videoURL = videoJson['data']['durl'][0]['url']

flag=1

print("videoURL:",videoURL)

print("audioURl:",audioURl)

print("flag:",flag)

if __name__ == '__main__':

getBiliBiliVideo("https://www.bilibili.com/video/BV1MJ411b7F6?p=2",2,"BV1MJ411b7F6")

輸出結果圖3.7所示。

輸出結果圖3.7所示。3.7

成功獲取鏈接。

4.下載視頻與音頻

再去查看視頻資源的網絡請求,發現一共有兩種請求方式,一種是GET,如圖3.8所示。3.8

另一種是OPTION,如圖3.9所示。3.9

所以視頻資源可能需要先發送OPTION請求,獲取服務器許可后再請求資源,許可的保持時間較長,所以只發一次Option請求就可以了,如圖3.10所示。3.10

這里有兩種下載視頻的方式:

第一種是利用416報錯碼分片下載,留意在請求頭劃紅線的這兩個參數,如圖3.11所示。3.11

Referer用于寫明來源,Range用于規定分片的字節大小以及范圍,每下載一定字節的資源,就修改Range,直到最后一次字節數大于剩下的資源時,服務器返回416報錯,再重新將Range設置為’Range’: ‘bytes=上一次開始的索引-’。把最后剩下的資源下載下來。每獲得一個視頻的分片就給他拼接到文件最后,最后得到完整文件。

第二種是不加入Range參數,直接下載整個的音頻與視頻,只需要注釋掉添加請求頭Range參數的語句即可。

增加函數為fileDownload,增加導入的庫有json、os、requests、etree、os,代碼如下。

import json

import os

import requests

from lxml import etree

# 防止因https證書問題報錯

requests.packages.urllib3.disable_warnings()

headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3970.5 Safari/537.36',

'Refer'

'er': 'https://www.bilibili.com/'

}

'''獲取bilibili視頻的主要函數@param url 視頻頁面url 結構為:url?參數@param p 視頻p數@param bv 視頻bv數'''

def getBiliBiliVideo(url,p,bv):

session = requests.session()

res = session.get(url=url,headers=headers,verify=False)

_element = etree.HTML(res.content)

# 獲取window.__playinfo__的json對象,[20:]表示截取'window.__playinfo__='后面的json字符串

videoPlayInfo = str(_element.xpath('//head/script[3]/text()')[0].encode('utf-8').decode('utf-8'))[20:]

videoJson = json.loads(videoPlayInfo)

# 獲取視頻鏈接和音頻鏈接

try:

# 2018年以后的b站視頻由.audio和.video組成 flag=0表示分為音頻與視頻

videoURL = videoJson['data']['dash']['video'][0]['baseUrl']

audioURl = videoJson['data']['dash']['audio'][0]['baseUrl']

flag=0

except Exception:

# 2018年以前的b站視頻音頻視頻結合在一起,后綴為.flv flag=1表示只有視頻

videoURL = videoJson['data']['durl'][0]['url']

flag=1

# 指定文件生成目錄,如果不存在則創建目錄

dirname = ("E:/result").encode("utf-8").decode("utf-8")

if not os.path.exists(dirname):

os.makedirs(dirname)

print('文件夾創建成功!')

# 獲取每一集的名稱

name = bv + "-" + str(p)

# 下載視頻和音頻

print('正在下載 "'+name+'" 的視頻····')

fileDownload(homeurl=url,url=videoURL, name='E:/result/'+name + '_Video.mp4', session=session)

if flag == 0:

print('正在下載 "'+name+'" 的音頻····')

fileDownload(homeurl=url,url=audioURl, name='E:/result/'+name+ '_Audio.mp3', session=session)

print(' "'+name+'" 下載完成!')

'''使用session保持會話下載文件@param homeurl 訪問來源@param url 音頻或視頻資源的鏈接@param name 下載后生成的文件名@session 用于保持會話'''

def fileDownload(homeurl,url, name, session=requests.session()):

# 添加請求頭鍵值對,寫上 refered:請求來源

headers.update({'Referer': homeurl})

# 發送option請求服務器分配資源

session.options(url=url, headers=headers,verify=False)

# 指定每次下載1M的數據

begin = 0

end = 1024*512 - 1

flag = 0

while True:

# 添加請求頭鍵值對,寫上 range:請求字節范圍

headers.update({'Range': 'bytes=' + str(begin) + '-' + str(end)})

# 獲取視頻分片

res = session.get(url=url, headers=headers,verify=False)

if res.status_code != 416:

# 響應碼不為為416時有數據

begin = end + 1

end = end + 1024*512

else:

headers.update({'Range': str(end + 1) + '-'})

res = session.get(url=url, headers=headers,verify=False)

flag=1

with open(name.encode("utf-8").decode("utf-8"), 'ab') as fp:

fp.write(res.content)

fp.flush()

# data=data+res.content

if flag==1:

fp.close()

break

if __name__ == '__main__':

getBiliBiliVideo("https://www.bilibili.com/video/BV1MJ411b7F6?p=2",2,"BV1MJ411b7F6")

輸出結果如圖3.12所示。3.12

通過第一種分片下載視頻得到音頻與視頻如圖3.13所示。3.13

而通過第二種直接下載視頻得到的視頻出現異常, 如圖3.14所示,中途還是停止了下載,不考慮這個方法。3.14

5.合并視頻與音頻

對于bilibili2018年以后的視頻需要再多一步音頻與視頻合并的操作,這里通過ffmpeg來實現這個功能。3.15

下載zip包到自定義文件夾下解壓,找到bin目錄,如圖3.16所示。3.16

將bin的完整目錄添加到系統環境變量Path中,如圖3.17所示。3.17

Win+R運行cmd指令輸入ffmpeg -version查看到如圖3.18所示則配置成功。3.18

編寫函數命名為combineVideoAudio,導入庫subprocess、os,使用subprocess.call()執行ffmpeg命令,然后使用os.remove()將原本的音頻和視頻刪除,代碼如下。

import subprocess

import os

'''

用于合并音頻與視頻

@param videopath 視頻路徑

@param audiopath 音頻路徑

@param outpath 生成合并視頻的路徑

'''

def combineVideoAudio(videopath,audiopath,outpath):

subprocess.call(("D:/python/ffmpeg-3.4.2-win64-static/bin/ffmpeg -i " + videopath + " -i " + audiopath + " -c copy "+ outpath).encode("utf-8").decode("utf-8"),shell=True)

os.remove(videopath)

os.remove(audiopath)

if __name__ == '__main__':

combineVideoAudio("E:/result/BV1MJ411b7F6-2_Video.mp4","E:/result/BV1MJ411b7F6-2_Audio.mp3","E:/result/BV1MJ411b7F6-2_output.mp4")

合并第4步下載的音頻和視頻,截取執行結果如圖3.19與3.20所示。3.193.20

能夠正常觀看視頻,如圖3.21所示。3.21

6.最終代碼

import json

import os

import subprocess

import requests

from lxml import etree

# 防止因https證書問題報錯

requests.packages.urllib3.disable_warnings()

headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3970.5 Safari/537.36',

'Refer'

'er': 'https://www.bilibili.com/'

}

'''

獲取bilibili視頻的主要函數

@param url 視頻頁面url 結構為:url?參數

@param p 視頻p數

@param bv 視頻bv數

'''

def getBiliBiliVideo(url,p,bv):

session = requests.session()

res = session.get(url=url,headers=headers,verify=False)

_element = etree.HTML(res.content)

# 獲取window.__playinfo__的json對象,[20:]表示截取'window.__playinfo__='后面的json字符串

videoPlayInfo = str(_element.xpath('//head/script[3]/text()')[0].encode('utf-8').decode('utf-8'))[20:]

videoJson = json.loads(videoPlayInfo)

# 獲取視頻鏈接和音頻鏈接

try:

# 2018年以后的b站視頻由.audio和.video組成

videoURL = videoJson['data']['dash']['video'][0]['baseUrl']

audioURl = videoJson['data']['dash']['audio'][0]['baseUrl']

flag=0

except Exception:

# 2018年以前的b站視頻音頻視頻結合在一起,后綴為.flv

videoURL = videoJson['data']['durl'][0]['url']

flag=1

# 指定文件生成目錄,如果不存在則創建目錄

dirname = ("E:/result").encode("utf-8").decode("utf-8")

if not os.path.exists(dirname):

os.makedirs(dirname)

print('文件夾創建成功!')

# 獲取每一集的名稱

name = bv + "-" + str(p)

# 下載視頻和音頻

print('正在下載 "'+name+'" 的視頻····')

fileDownload(homeurl=url,url=videoURL, name='E:/result/'+name + '_Video.mp4', session=session)

if flag == 0:

print('正在下載 "'+name+'" 的音頻····')

fileDownload(homeurl=url,url=audioURl, name='E:/result/'+name+ '_Audio.mp3', session=session)

print('正在組合 "'+name+'" 的視頻和音頻····')

combineVideoAudio('E:/result/' + name + '_Video.mp4','E:/result/' + name + '_Audio.mp3','E:/result/' + name + '_output.mp4')

print(' "'+name+'" 下載完成!')

'''

使用session保持會話下載文件

@param homeurl 訪問來源

@param url 音頻或視頻資源的鏈接

@param name 下載后生成的文件名

@session 用于保持會話

'''

def fileDownload(homeurl,url, name, session=requests.session()):

# 添加請求頭鍵值對,寫上 refered:請求來源

headers.update({'Referer': homeurl})

# 發送option請求服務器分配資源

session.options(url=url, headers=headers,verify=False)

# 指定每次下載1M的數據

begin = 0

end = 1024*512 - 1

flag = 0

while True:

# 添加請求頭鍵值對,寫上 range:請求字節范圍

headers.update({'Range': 'bytes=' + str(begin) + '-' + str(end)})

# 獲取視頻分片

res = session.get(url=url, headers=headers,verify=False)

if res.status_code != 416:

# 響應碼不為為416時有數據

begin = end + 1

end = end + 1024*512

else:

headers.update({'Range': str(end + 1) + '-'})

res = session.get(url=url, headers=headers,verify=False)

flag=1

with open(name.encode("utf-8").decode("utf-8"), 'ab') as fp:

fp.write(res.content)

fp.flush()

# data=data+res.content

if flag==1:

fp.close()

break

'''

用于合并音頻與視頻

@param videopath 視頻路徑

@param audiopath 音頻路徑

@param outpath 生成合并視頻的路徑

'''

def combineVideoAudio(videopath,audiopath,outpath):

subprocess.call(("D:/python/ffmpeg-3.4.2-win64-static/bin/ffmpeg -i " + videopath + " -i " + audiopath + " -c copy "+ outpath).encode("utf-8").decode("utf-8"),shell=True)

os.remove(videopath)

os.remove(audiopath)

if __name__ == '__main__':

# 輸入bilibili視頻的BV號

bv = input('視頻BV號:')

url='https://www.bilibili.com/video/'+bv

# 選擇視頻從第幾p開始到第幾p結束

startPart=input('起始P:')

endPart = input('終止P;')

for p in range(int(startPart),int(endPart) + 1):

getBiliBiliVideo(url + '?p=' + str(p),p,bv)

總結

目前實現的爬取視頻功能已經可以滿足我離線觀看視頻,不用借助手機就可下載到視頻素材的需求。當然,這個程序還存在一些可以后續添加的功能,比如輸入多個BV號再逐個下載;實現循環輸入,下載完一個視頻后繼續輸入號,繼續下載;顯示彈幕等,這些功能根據以后的需求再進行添加。

如果你喜歡這期的Python 教程,請持續關注我,如果對你有幫助,麻煩點個關注加收藏,

領取學習資料和進交流群可以關注微信公共號:

總結

以上是生活随笔為你收集整理的python爬取bilibili数据_如何使用Python爬取bilibili视频(详细教程)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。