爬虫本体
代码仅供学习交流使用,请不要大量爬取,也不可将之用于商业用途,如需转载视频请征求视频作者同意,所产生的法律纠纷与本人无关。
用到的包
#如果缺失请在cmd下使用pip install xxx进行安装
import requests
import re,os
import time
两个请求头
#用于抓取搜索结果页的视频入口
first_headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36'
}
#用于配置视频真实地址并下载
second_headers = {
"Accept-Encoding":"identify",
"Accept":"*/*",
"Connection":"keep-alive",
"Accept-Language":"cross-site",
"Sec-Fetch-Mode":"cors",
"Origin":"https://www.bilibili.com",
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36'
}
构建搜索页地址
keyword = input('请输入你要爬取的关键词:')
#检查文件夹是否存在,不存在则创建
if not os.path.exists(keyword):
os.mkdir(keyword)
#切换到目标路径
os.chdir('./' + keyword)
else:
os.chdir('./' + keyword)
URLS = ['https://search.bilibili.com/all?keyword={}&page={}'.format(keyword,i) for i in range(1,11)]
主要代码
def run():
#搜索页的循环
for URL in URLS:
try:
#获取目标页的网页数据
res = requests.get(url = URL,headers = first_headers)
res.encoding = res.apparent_encoding
html = res.text
#正则匹配视频入口和标题
pattern_url = re.compile('href="//(www.bilibili.com.*?search)"\stitle')
pattern_title = re.compile('search"\stitle="(.*?)"')
url_list = re.findall(pattern_url, html)
title_list = re.findall(pattern_title, html)
#循环爬取多个视频
for i in range(len(url_list)):
#清除标题中的不规则字符
title_list[i] = title_list[i].replace('\\', '')
#创建用于保存视频与音频的文件夹
if not os.path.exists(title_list[i]):
os.mkdir(title_list[i])
#已经下载过的则pass
else:
continue
#配置完整的视频地址
http_url = 'https://' + url_list[i]
#抓取视频地址返回的数据
video_html = requests.get(url = http_url,headers = first_headers).content.decode('utf-8')
try:
#匹配视频流Url
m4s_30080 = re.findall(r'''"baseUrl":"(.*?)"''',video_html,re.S)[0]
except Exception as e:
print(e)
#匹配音频流Url
mp3_30216 = re.findall(r'''"baseUrl":"(.*?)"''',video_html,re.S)[-2]
#将second_headers请求头配置完整
Referer_key = url_list[i]
#暂时将Range设置为0-5
Range_Key = 'bytes=0-5'
second_headers['Referer'] = 'https://' + Referer_key
second_headers['Range'] = Range_Key
#请求视频流地址
video_bytes = requests.get(m4s_30080,headers = second_headers).headers['Content-Range']
#请求音频流地址
audio_bytes = requests.get(mp3_30216,headers = second_headers).headers['Content-Range']
#匹配完整音视频的真实Range并更新请求头
video_total = re.findall(r"/(.*)?",video_bytes,re.S)[0]
audio_total = re.findall(r"/(.*)?",audio_bytes,re.S)[0]
second_headers['Range'] = video_total
stream = True
#用于判断视频大小并以该字节作为数据流大小
chunk_size = 1024
#将匹配到的Range转为int型数据
video_content_size = int(video_total)
audio_content_size = int(audio_total)
print('开始下载:' + title_list[i])
#输出音视频的大小总和
print("文件大小:" + str(round(float((video_content_size + audio_content_size) / chunk_size / 1024), 4)) + "[MB]")
#记录开始时间
start = time.time()
#请求完整视频地址
m4s_bytes = requests.get(m4s_30080,headers = second_headers,stream = stream)
#返回值不为416则代表有数据,一般为200
if m4s_bytes.status_code != 416:
#下载视频并命名为1.mp4
with open(title_list[i] + '/' + '1.mp4','wb') as f:
for data in m4s_bytes.iter_content(chunk_size=chunk_size):
f.write(data)
f.flush()
f.close()
#更新请求头用于下载音频
second_headers['Range'] = audio_total
#请求完整音频地址
mp3_bytes = requests.get(mp3_30216, headers = second_headers, stream = stream)
#下载音频并命名为1.mp3
with open(title_list[i] + '/' + '1.mp3','wb') as t:
t.write(mp3_bytes.content)
t.close()
#记录结束时间
end = time.time()
#输出耗时
print('下载完成,总耗时:' + str(end - start) + '秒\n')
#爬累了歇几秒...
time.sleep(3)
#如果只爬单个视频作为测试就把break取消注释
#break
#用于捕捉并忽略错误
except Exception as e:
print(e)
pass
#如果爬多页就把break注释掉
break
if __name__ == '__main__':
run()
音视频混流
18年以后B站将视频与音频分割开,无法直接获取完整文件 这里介绍两种方法对音频与视频进行混流 1、格式工厂,去软件商店或者百度搜索下载即可 2、使用的Python强大的音视频处理库moviepy写一个脚本
用到的包
#仍然使用pip install xxx进行安装,可能也需要安装ffmpeg模块
from moviepy.editor import VideoFileClip,AudioFileClip
import os,time
切换目录
#os模块取关键词目录下的所有文件夹
paths = os.listdir()[1]
#切换到关键词目录
os.chdir('./' + paths)
循环处理
def run():
for path in os.listdir():
try:
#定义混流后的文件名
filename = 'merge_file'
#文件的保存路径
filepath = path + '/' + filename
#检测是否已处理过,如果是则忽略
if os.path.exists(filepath + '.mp4'):
continue
#预处理的视频文件
video_file = path + '/' + '1.mp4'
#预处理的音频文件
audio_file = path + '/' + '1.mp3'
#加载音视频
video = VideoFileClip(video_file)
audio = AudioFileClip(audio_file)
#将音视频混流
new_video = video.set_audio(audio)
#保存混流后的视频,并禁用缓存
new_video.to_videofile(filepath + '.mp4',remove_temp = True)
#释放已加载的视频
video.close()
new_video.close()
#看情况是否需要休息几秒...
time.sleep(3)
except:
#如果前述未关闭已加载的文件就遇到错误,则重新执行
try:
video.close()
new_video.close()
#如果遇到错误则忽略
except:
pass
#输出遇到错误的视频并继续混流下一个
print(path + '\nerror')
pass
if __name__ == '__main__':
run()