上一篇文章简简单单的爬取了某个B站视频,这次在上一次的基础上,增加了爬取输入的BV号对应的视频。
上一篇里我们对网站进行分析,发现视频链接基本都存储在window.__playinfo__中,所以我们的目标也很明确。
我们需要等号后面的数据,而这个window参数又在script标签中,所以我们可以很轻而易举的写出正则表达式
\<script\>window\.__playinfo__=(.*?)\</script\> # 需要注意的是有些字符要加’\‘进行反转义
同理,我们视频的标题也可以通过分析推敲出来
\<script\>window\.__INITIAL_STATE__=(.*?);\(function\(\) # 因为在\</script\> 前还多了一个function方法,所以到function即可结束匹配
正则表达式推敲出来之后,后面的工作无非就是取爬取到的视频地址数据套进下载方法罢了,所以直接上代码
import requests
import re
import json
#移除SSL认证
requests.packages.urllib3.disable_warnings()
# 请求头,伪装成浏览器访问
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive'
}
# 爬取页面数据
def httpSpider(BV_mark):
# 直接爬取HTML文件,再分析提取视频链接
url = f"https://www.bilibili.com/video/{BV_mark}"
try:
response = requests.get(url, headers=headers)
# 服务器状态码的值为200,则表示服务器接受访问请求,此时会返回页面文本文件
if response.status_code == 200:
return response.content.decode('utf8')
except:
print("请求失败")
# 获取视频标题
def rtTille(context):
titlePattern = r'\<script\>window\.__INITIAL_STATE__=(.*?);\(function\(\)'
title = re.findall(titlePattern, context)[0]
titleData = json.loads(title)
return titleData['videoData']['title']
# 获取视频链接,date['data']['dash']['video'][3]['baseUrl']存放的是720p的视频链接地址,你也可以选择其他备用地址
def filterDate(context,title):
# .*表示任意匹配除换行符(\n、\r)之外的任何单个或多个字符
urlPattern = r'\<script\>window\.__playinfo__=(.*?)\</script\>'
urllist = re.findall(urlPattern, context)[0]
date = json.loads(urllist)
# 前两条数据(也就是存放有“id”:“80”的对应列表)里的视频链接貌似用不了,所以直接取第三条数据
videoUrl = date['data']['dash']['video'][3]['baseUrl']
audioUrl = date['data']['dash']['audio'][0]['baseUrl']
print(f'正在下载 "{title}" ......')
downView(videoUrl,f"{title}.mp4")
downView(audioUrl,f"{title}.mp3")
print(f'"{title}" 已下载完成.')
# 读写文件
def downView(url,title):
res = requests.get(url, headers=headers, verify=False)
with open(title,"wb")as f:
f.write(res.content)
f.close()
if __name__=="__main__":
BV_mark = input("请输入你要下载的视频(单个)的BV号:")
context = httpSpider(BV_mark)
title = rtTille(context)
filterDate(context, title)