共计 4542 个字符,预计需要花费 12 分钟才能阅读完成。
大家好,我是查理
明天咱们分享一个小工具,次要用于 B 站视频的下载,只须要输出对应视频的网页地址就能够进行下载到本地了。
目录:
-
- 原理简介
-
- 网页剖析
-
- 视频爬取
-
- 存入本地
-
- GUI 工具制作
-
- 残缺代码
1. 原理简介
原理很简略,就是获取视频资源的源地址,而后爬取视频的二进制内容,再写入到本地即可。
2. 网页剖析
关上该网页,而后 F12
进入 开发者模式 ,接着点开 网络 —> 全副 ,因为视频资源个别比拟大,我这里依据 大小 进行了 从大到小的排序
,找到了第一条这些可能和视频源地址无关。
而后,咱们复制找到的这条里的 url
局部不变的局部,回到元素中 ctrl+F
搜寻,找到了可能和视频源地址无关的节点。
果然,咱们复制这部分内容,用 json 在线解析工具发现真的有咱们须要的看似视频文件所在的地址。
而后,我复制这个地址用浏览器关上发现提醒 403
了。。
不过,没关系。。咱们看接下来的操作!
3. 视频爬取
在网页剖析局部,咱们能够在视频的 B 站 地址网页源代码里通过各种数据解析的形式来获取视频文件的源地址,这里我采纳的是 正则表达式。
import requests
import re
import json
url = 'https://www.bilibili.com/video/BV1BU4y1H7E3'
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36",
"referer": "https://www.bilibili.com"
}
resp = requests.get(url, headers=headers)
palyinfo = re.findall(r'<script>window.__playinfo__=(.*?)</script>', resp.text)[0]
palyinfo_data = json.loads(palyinfo)
因为正在表达式获取的后果是字符串,而实际上它是 json
(字典),所以这里须要再引入json
库来进行转化。
咱们再剖析数据,能够发现最终视频文件的信息,间接 key-value
操作就行了。比拟有意思的是视频和音频文件是离开的,咱们须要别离爬取后再合并即可。
# 视频与音频文件地址
video_url = json_data['data']['dash']['video'][0]['base_url']
audio_url = json_data['data']['dash']['audio'][0]['base_url']
有敌人可能会发现,base_url
貌似有好多个。是的,因为视频清晰度有很多种嘛。这里我选取的是第一种 超清 4K,大家能够依据本人需要进行抉择!
当然了,咱们把视频存入本地的时候还须要起个名字,这里轻易找个节点解析出文件名就行了。
# 视频题目
title = re.findall(r'<h1 title="(.*?)"class="video-title">', resp.text)[0]
4. 存入本地
既然咱们曾经解析取得了视频的文件地址、音频地址和文件名,那么间接就安顿下载吧!
不过,咱们在网页剖析的时候发现间接关上视频和音频文件地址会提醒403
,那么因为跳过去的起源不明确导致的,只需调整申请头为如下即可:
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36",
# 加上 referer 即可
"referer": "https://www.bilibili.com"
}
搞定这些玩意后,咱们就开始写文件写入本地的函数吧!
# 个别视频是 mp4,音频是 mp3
def down_file(file_url, file_type):
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36",
"referer": "https://www.bilibili.com"
}
resp = requests.get(url = file_url, headers=headers)
print(resp.status_code)
print(f'文件名称:{title}')
# 设置单次写入数据的块大小
chunk_size = 1024
# 获取文件大小
file_size = int(resp.headers['content-length'])
# 用于记录曾经下载的文件大小
done_size = 0
# 将文件大小转化为 MB
file_size_MB = file_size / 1024 / 1024
print(f'文件大小:{file_size_MB:0.2f} MB')
start_time = time.time()
with open(title + '.' + file_type, mode='wb') as f:
for chunk in resp.iter_content(chunk_size=chunk_size):
f.write(chunk)
done_size += len(chunk)
print(f'\r 下载进度:{done_size/file_size*100:0.2f}%',end='')
end_time = time.time()
cost_time = end_time-start_time
print(f'\n 累计耗时:{cost_time:0.2f} 秒')
print(f'下载速度:{file_size_MB/cost_time:0.2f}M/s')
运行后果:
# 视频下载
>>>down_file(video_url, 'mp4')
200
文件名称:【咒术回战】第 20 集五条悟帅的有些过分了
文件大小:42.10 MB
下载进度:100.00%
累计耗时:5.72 秒
下载速度:7.36M/s
# 音频下载
>>>down_file(audio_url, 'mp3')
200
文件名称:【咒术回战】第 20 集五条悟帅的有些过分了
文件大小:5.13 MB
下载进度:100.00%
累计耗时:0.80 秒
下载速度:6.42M/s
咱们在本地能够看到下载胜利的视频文件:
因为视频和音频是离开的,所以独自关上这个视频是没有声音的,咱们须要进行合并操作。
合并操作须要用到 moviepy
库,对于这个库咱们后续也会介绍它的更多利用,敬请期待~
from moviepy import *
from moviepy.editor import *
video_path = title + '.mp4'
audio_path = title + '.mp3'
# 读入视频
video = VideoFileClip(video_path)
# 提取音轨
audio = AudioFileClip(audio_path)
# 将音轨合并到视频中
video = video.set_audio(audio)
# 输入
video.write_videofile(f"{title}(含音频).mp4")
就这样搞定了:
Moviepy - Building video【咒术回战】第 20 集五条悟帅的有些过分了(含音频).mp4.
MoviePy - Writing audio in【咒术回战】第 20 集五条悟帅的有些过分了(含音频)TEMP_MPY_wvf_snd.mp3
MoviePy - Done.
Moviepy - Writing video【咒术回战】第 20 集五条悟帅的有些过分了(含音频).mp4
Moviepy - Done !
Moviepy - video ready【咒术回战】第 20 集五条悟帅的有些过分了(含音频).mp4
5. GUI 工具制作
这个吧,就是用我罕用的 pysimplegui
来操作了,比较简单。
import PySimpleGUI as sg
# 主题设置
sg.theme('SystemDefaultForReal')
# 布局设置
layout = [[sg.Text('抉择 B 站视频地址:',font=("微软雅黑", 12)),sg.InputText(key='url',size=(50,1),font=("微软雅黑", 10),enable_events=True) ],
# [sg.Output(size=(66, 8),font=("微软雅黑", 10))],
[sg.Button('开始下载',font=("微软雅黑", 10),button_color ='Orange'),
sg.Button('关闭程序',font=("微软雅黑", 10),button_color ='red'),]
]
# 创立窗口
window = sg.Window('B 站视频下载工具', layout,font=("微软雅黑", 12),default_element_size=(50,1))
# 事件循环
while True:
event, values = window.read()
if event in (None, '关闭程序'):
break
if event == '开始下载':
url = values['url']
print('获取视频信息')
title, video_url, audio_url = get_file_info(url)
print('下载视频资源')
down_file(title, video_url, 'mp4')
print('下载音频资源')
down_file(title, audio_url, 'mp3')
print('合并视频与音频')
merge(title)
print('有音频视频解决实现')
window.close()
6. 残缺代码
不够优雅,大家能够自行优化哈!