大家好,我是查理今天给大家分享一个小工具,主要用于B站视频下载,只需要输入网页地址即可相应的视频下载到本地。内容:原理介绍网页分析视频抓取并存储在本地GUI工具中制作完整代码1.原理介绍原理很简单,就是获取视频资源的源地址,然后抓取视频的二进制内容,然后写到本地。2、网页分析打开网页,然后F12进入开发者模式,然后点击网络->全部,因为视频资源一般都比较大,我按照大小从大到小排序,找到了第一种可能与视频源地址有关。然后,我们把找到的文章中url没变的部分复制过来,返回元素ctrl+F搜索,找到一个可能和视频源地址相关的节点。果然,我们复制了这部分内容,使用json在线分析工具发现,确实有我们需要的这个看似视频文件的地址。然后,我复制了这个地址,用浏览器打开,发现提示403。。但没关系。.让我们看看接下来会发生什么!3、视频爬取在网页分析部分,我们可以在视频站B的网页地址源码中通过各种数据分析方法获取视频文件的源地址,这里我使用的是正则表达式。importrequestsimportreimportjsonurl='https://www.bilibili.com/video/BV1BU4y1H7E3'headers={"User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/87.0.4280.66Safari/537.36","referer":"https://www.bilibili.com"}resp=requests.get(url,headers=headers)palyinfo=re.findall(r'<脚本>window.__playinfo__=(.*?)',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'',resp.text)[0]4.既然我们已经解析过了,就保存在本地视频的文件地址,音频地址,文件名,然后直接安排下载!但是我们在分析网页的时候发现直接打开视音频文件的地址会提示403,所以由于不清楚跳转的来源,只需要调整请求头如下:headers={"User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/87.0.4280.66Safari/537.36",#justaddreferer"referer":"https://www.bilibili.com"}完成这些之后,我们就开始写写文件到本地的函数吧!#一般视频是mp4,音频是mp3defdown_file(file_url,file_type):headers={"User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/87.0.4280.66Safari/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#将文件大小转换为MBfile_size_MB=file_size/1024/1024print(f'文件大小:{file_size_MB:0.2f}MB')start_time=time.time()withopen(title+'.'+file_type,mode='wb')asf:forchunkinresp.iter_content(chunk_size=chunk_size):f.write(chunk)done_size+=len(chunk)print(f'\rdownloadprogress:{done_size/file_size*100:0.2f}end',')end_time=time.time()cost_time=end_time-start_timeprint(f'\n累计耗时:{cost_time:0.2f}秒')print(f'下载速度:{file_size_MB/cost_time:0.2f}M/s')运行结果:#Videodownload>>>down_file(video_url,'mp4')200文件名:【法术归来】第20集无条武帅有点过分文件大小:42.10MB下载进度:100.00%累计耗时:5.72秒下载速度:7.36M/s#音频下载>>>down_file(audio_url,'mp3')200文件名:【法术归来】第20集无条无痕有点过分文件大小:5.13MB下载进度:100.00%累计耗时:0.80秒下载速度:6.42M/s可以看到成功了y下载的视频文件本地:由于视频和音频是分开的,所以单独打开这个视频是没有声音的。我们需要做一个合并操作合并操作需要moviepy库。后面我们会介绍这个库更多的应用,敬请期待~frommoviepyimport*frommoviepy.editorimport*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-构建视频[SpellBacktoBattle]第20集GojoWushuai有点太多了(带音频).mp4.MoviePy-在[SpellBacktoBattle]第20集WujoWushuai中编写音频是一个有点太多(包括音频)TEMP_MPY_wvf_snd.mp3MoviePy-完成。Moviepy-写视频【咒语归来】第20集无条无帅有点过分(含音频).mp4Moviepy-完成!Moviepy-视频准备好【咒语归来】第20话无条无帅有点过分(含音频).mp45.让我们使用GUI工具来实现。我用我常用的pysimplegui来操作,比较简单。importPySimpleGUIassg#Themesettingsg.theme('SystemDefaultForReal')#Layoutsettinglayout=[[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='橙色'),sg.Button('关闭程序',font=("微软雅黑",10),button_color='red'),]]]#创建窗口window=sg.Window('B站视频下载工具',layout,font=("微软雅黑",12),default_element_size=(50,1))#事件循环whileTrue:event,values=window.read()ifeventin(None,'closeprogram'):breakifevent=='startdownload':url=values['url']print('获取视频信息')title,video_url,audio_url=get_file_info(url)print('下载视频资源')down_file(title,video_url,'mp4')print('下载音频资源')down(title,audio_url,'mp3')print('Mergevideoandaudio')merge(title)print('音视频处理完成')window.close()6.完整代码不够优雅,可以使用你自己线路优化哈!