如何利用 Python 批量下载 Bilibili up主视频
最近学习各种知识,已经从 Youtube 迁移到了 Bilibili 。之前一直以为B站是个二次元的世界。虽然现在也是,但是各种学习资源简直太多了。最主要的原因就是没有广告!有些视频真的很抢手,但是偶尔会有版权问题,会被B站下架,所以B站的收藏夹偶尔会出现视频丢失的情况。为了避免这种情况的发生,决定把优秀的资源下载到本地保存。所以又要请出我们的神器Python了。
利用 Python 的 Requests 库,基本上网络上的资源没什么不能下载的。即使有,那么加上 Selenium 也不成问题。
一、利用you-get下载哔哩哔哩播放列表
you-get 是一个开源程序,专门用来下载各种视频的,从名字上来看,就知道起初应该只是为了下载 Youtube 视频的,之后随着各种 contributer 的加入,发展成了一个可以下载各种视频网站的工具。可以在这里查看中文说明。
1. 安装 you-get
安装 you-get 之前,还得安装 you-get 的各种依赖才可以进行使用。
- python
- FFmpeg
2. 使用 you-get
使用方法也很简单,直接一句话代码下载即可。
you-get --playlist <url>
PS:关于 you-get 不知道为什么,有时候总是出现没速度的情况,而且关于文件名问题,没办法自定义。Forece 下载了几P,然后就不断的出现超时错误。于是就放弃了这个强大的工具。
二、利用 Python 下载B站播放列表视频
关于 Python 爬虫就不多说了,这里也写不下,大家自己去B站学吧。这里只是讲一下分析过程。
1. 分析网页
通过分析视频列表页,发现基本上所有信息都在 HTML 里边了。
1. 视频、音频地址
通过分析,发现视频、音频被拆分为两部分。而这段代码都在
<script>window.__playinfo__=
这段代码之后,进行 JSON 格式化之后大概是这样式的,通过分析,拿到当前播放视频的 Video URL 还有 Audio URL。
2. 合并文件
因为视频和音频是分离的,所以需要用到 FFmpeg 来将两个文件进行合并。记得需要将 FFmpeg 加入环境变量先。合并命令是:
ffmpeg -i video.mp4 -i audio.mp4 -c copy final.mp4
3. 视频列表信息
知道怎么下载单个视频后,就需要对整个列表进行分析。很幸运的是,在搜索相关资料的时候,发现了一个 API,
https://api.bilibili.com/x/player/pagelist?aid=xxxxxx
通过访问这个网址,就可以拿到一个 JSON 文件,里边就是播放列表里边的所有信息,不过需要传入一个 aid 值。 aid 值也很容易找到,在原本的 HTML 中就可以利用正则提取到。之后我们就通过遍历这个 JSON 文件,然后就能下载所有的视频了。
其实视频页面的 HTML 也能拿到这个列表,不过利用正则提取稍微麻烦了点。所以不如直接利用 API 获取信息。
4. 完整代码
import re import requests import json import os headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36', 'cookie': "" # YOUR COOKIES } def download_single_video(url, name): res = requests.get(url, headers=headers) video_pattern = '__playinfo__=(.*?)</script><script>' playlist_info = json.loads(re.findall(video_pattern, res.text)[0]) video_url = playlist_info['data']['dash']['video'][0]['baseUrl'] audio_url = playlist_info['data']['dash']['audio'][0]['baseUrl'] save_file(video_url, 'video') save_file(audio_url, 'audio') merge(name) print('{} 下载完毕'.format(name)) def save_file(url, type): download_content = requests.get(url, headers=headers).content with open('{}.mp4'.format(type), 'wb') as output: output.write(download_content) def merge(name): command = 'ffmpeg -i video.mp4 -i audio.mp4 -c copy "{}".mp4'.format(name) os.system(command) os.remove('video.mp4') os.remove('audio.mp4') def get_list_info(url): aid_pattern = 'window.__INITIAL_STATE__={"aid":(\d*?),' res = requests.get(url, headers=headers) aid = re.findall(aid_pattern, res.text)[0] playlist_json_url = 'https://api.bilibili.com/x/player/pagelist?aid={}'.format(aid) json_info = json.loads(requests.get(playlist_json_url, headers=headers).content.decode('utf-8'))['data'] return json_info if __name__ == '__main__': base_url = 'https://www.bilibili.com/video/BV14J4114768' json_info = get_list_info(base_url) for i in json_info: p = i['page'] name = 'P{} - {}'.format(p, i['part']) url = base_url + '?p={}'.format(p) download_single_video(url, name)