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__的js