Python爬蟲實戰,DecryptLogin模組,Python模擬登入實現載B站指定UP主的所有視訊
前言
下載B站上指定的UP主所上傳的所有視訊。廢話不多說,讓我們愉快地開始吧~
開發工具
** Python版本:**3.6.4
** 相關模組:**
DecryptLogin模組;
argparse模組;
以及一些python自帶的模組。
環境搭建
安裝Python並新增到環境變數,pip安裝需要的相關模組即可。
原理簡介
這裡簡單介紹一下原理吧,因為B站只有在使用者登入狀態下才能下載1080P的視訊。所以我們首先要利用我開源的DecryptLogin庫模擬登入B站(畢竟低畫質的視訊看著不舒服),這個很簡單,幾行程式碼就搞定了:
from DecryptLogin import login _, session = login.Login().bilibili(username, password)
接下來就是老生常談的抓包了,進入某個UP主的主頁:
首先我們來抓取UP主的基本資訊(抓取UP主所有的視訊時完全不需要這些資訊,只是用來確定你輸入的userid是否和你想抓取的使用者一致用的),這個很簡單,重新整理一下發現:
幾行程式碼就搞定了:
'''根據userid獲得該使用者基本資訊''' def __getUserInfo(self, userid): params = {'mid': userid, 'jsonp': 'jsonp'} res = self.session.get(self.user_info_url, params=params, headers=self.headers) res_json = res.json() user_info = { '使用者名稱': res_json['data']['name'], '性別': res_json['data']['sex'], '個性簽名': res_json['data']['sign'], '使用者等級': res_json['data']['level'], '生日': res_json['data']['birthday'] } return user_info
接下來就是下載該UP主的所有視訊了,因為感覺搞起來可能比較費時間(年底了時間比較緊張T_T),所以就直接去you-get的原始碼裡找了找有沒有現成的API了,發現主要需要以下三個介面:
'https://space.bilibili.com/ajax/member/getSubmitVideos'
'https://api.bilibili.com/x/web-interface/view'
'https://api.bilibili.com/x/player/playurl'
第一,二個介面用來獲取使用者所有的視訊的基本資訊,根據這些資訊然後再利用第三個介面來獲得視訊的下載連結,最後利用呼叫aria2c下載這些視訊就OK了。具體而言,程式碼實現如下:
'''下載目標使用者的所有視訊'''
def __downloadVideos(self, userid):
if not os.path.exists(userid):
os.mkdir(userid)
# 非會員使用者只能下載到高清1080P
quality = [('16', '流暢 360P'),
('32', '清晰 480P'),
('64', '高清 720P'),
('74', '高清 720P60'),
('80', '高清 1080P'),
('112', '高清 1080P+'),
('116', '高清 1080P60')][-3]
# 獲得使用者的視訊基本資訊
video_info = {'aids': [], 'cid_parts': [], 'titles': [], 'links': [], 'down_flags': []}
params = {'mid': userid, 'pagesize': 30, 'tid': 0, 'page': 1, 'order': 'pubdate'}
while True:
res = self.session.get(self.submit_videos_url, headers=self.headers, params=params)
res_json = res.json()
for item in res_json['data']['vlist']:
video_info['aids'].append(item['aid'])
if len(video_info['aids']) < int(res_json['data']['count']):
params['page'] += 1
else:
break
for aid in video_info['aids']:
params = {'aid': aid}
res = self.session.get(self.view_url, headers=self.headers, params=params)
cid_part = []
for page in res.json()['data']['pages']:
cid_part.append([page['cid'], page['part']])
video_info['cid_parts'].append(cid_part)
title = res.json()['data']['title']
title = re.sub(r"[‘’\/\\\:\*\?\"\<\>\|\s']", ' ', title)
video_info['titles'].append(title)
print('共獲取到使用者ID<%s>的<%d>個視訊...' % (userid, len(video_info['titles'])))
for idx in range(len(video_info['titles'])):
aid = video_info['aids'][idx]
cid_part = video_info['cid_parts'][idx]
link = []
down_flag = False
for cid, part in cid_part:
params = {'avid': aid, 'cid': cid, 'qn': quality, 'otype': 'json', 'fnver': 0, 'fnval': 16}
res = self.session.get(self.video_player_url, params=params, headers=self.headers)
res_json = res.json()
if 'dash' in res_json['data']:
down_flag = True
v, a = res_json['data']['dash']['video'][0], res_json['data']['dash']['audio'][0]
link_v = [v['baseUrl']]
link_a = [a['baseUrl']]
if v['backup_url']:
for item in v['backup_url']:
link_v.append(item)
if a['backup_url']:
for item in a['backup_url']:
link_a.append(item)
link = [link_v, link_a]
else:
link = [res_json['data']['durl'][-1]['url']]
if res_json['data']['durl'][-1]['backup_url']:
for item in res_json['data']['durl'][-1]['backup_url']:
link.append(item)
video_info['links'].append(link)
video_info['down_flags'].append(down_flag)
# 開始下載
out_pipe_quiet = subprocess.PIPE
out_pipe = None
aria2c_path = os.path.join(os.getcwd(), 'tools/aria2c')
ffmpeg_path = os.path.join(os.getcwd(), 'tools/ffmpeg')
for idx in range(len(video_info['titles'])):
title = video_info['titles'][idx]
aid = video_info['aids'][idx]
down_flag = video_info['down_flags'][idx]
print('正在下載視訊<%s>...' % title)
if down_flag:
link_v, link_a = video_info['links'][idx]
# --視訊
url = '"{}"'.format('" "'.join(link_v))
command = '{} -c -k 1M -x {} -d "{}" -o "{}" --referer="https://www.bilibili.com/video/av{}" {} {}'
command = command.format(aria2c_path, len(link_v), userid, title+'.flv', aid, "", url)
process = subprocess.Popen(command, stdout=out_pipe, stderr=out_pipe, shell=True)
process.wait()
# --音訊
url = '"{}"'.format('" "'.join(link_a))
command = '{} -c -k 1M -x {} -d "{}" -o "{}" --referer="https://www.bilibili.com/video/av{}" {} {}'
command = command.format(aria2c_path, len(link_v), userid, title+'.aac', aid, "", url)
process = subprocess.Popen(command, stdout=out_pipe, stderr=out_pipe, shell=True)
process.wait()
# --合併
command = '{} -i "{}" -i "{}" -c copy -f mp4 -y "{}"'
command = command.format(ffmpeg_path, os.path.join(userid, title+'.flv'), os.path.join(userid, title+'.aac'), os.path.join(userid, title+'.mp4'))
process = subprocess.Popen(command, stdout=out_pipe, stderr=out_pipe_quiet, shell=True)
process.wait()
os.remove(os.path.join(userid, title+'.flv'))
os.remove(os.path.join(userid, title+'.aac'))
else:
link = video_info['links'][idx]
url = '"{}"'.format('" "'.join(link))
command = '{} -c -k 1M -x {} -d "{}" -o "{}" --referer="https://www.bilibili.com/video/av{}" {} {}'
command = command.format(aria2c_path, len(link), userid, title+'.flv', aid, "", url)
process = subprocess.Popen(command, stdout=out_pipe, stderr=out_pipe, shell=True)
process.wait()
os.rename(os.path.join(userid, title+'.flv'), os.path.join(userid, title+'.mp4'))
print('所有視訊下載完成, 該使用者所有視訊儲存在<%s>資料夾中...' % (userid))
文章到這裡就結束了,感謝你的觀看,關注我每天分享Python模擬登入系列,下篇文章分享網易雲個人歌單下載器
為了感謝讀者們,我想把我最近收藏的一些程式設計乾貨分享給大家,回饋每一個讀者,希望能幫到你們。
乾貨主要有:
① 2000多本Python電子書(主流和經典的書籍應該都有了)
② Python標準庫資料(最全中文版)
③ 專案原始碼(四五十個有趣且經典的練手專案及原始碼)
④ Python基礎入門、爬蟲、web開發、大資料分析方面的視訊(適合小白學習)
⑤ Python學習路線圖(告別不入流的學習)
⑥ 兩天的Python爬蟲訓練營直播許可權
All done~完整原始碼+乾貨詳見個人簡介或者私信獲取相關檔案。。