一、项目概述
有一天,我突然想找点事做,想起一直想学但是没有学的c语言,就决定来学一下。可是怎么学呢?看书的话太无聊,报班学呢又快吃土了没钱,不如去b站看看?果然,关键字c语言搜索,出现了很多c语言的讲课视频:
b站c语言讲课视频节选
b站是一个很神奇的地方,简直就是一个无所不有的宝库,几乎可以满足你一切的需求和视觉欲。不管你是想看动画、番剧 ,还是游戏、鬼畜 ,亦或科技和各类教学视频 ,只要你能想到的,基本上都可以在b站找到。对于程序猿或即将成为程序猿的人来说,b站上的编程学习资源是学不完的,可是b站没有提供下载的功能,如果想保存下载在需要的时候看,那就是一个麻烦了。我也遇到了这个问题,于是研究怎么可以实现一键下载视频,最终用python这门神奇的语言实现了。
当然了,项目实现之后,不是想学习编程、而是想看其他类别视频的小伙伴也可以用这款工具进行下载了。
这次项目不需要太多的环境配置,最主要的是有ffmpeg(一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序)并设置环境变量就可以了。ffmpeg主要是用于将下载下来的视频和音频进行合并形成完整的视频。
可点击或进入官网进行下载,并解压到你想保存的目录。
(1)复制ffmpeg的bin路径,如xxx
ffmpeg-20190921-ba24b24-win64-sharedbin
(2)此电脑右键点击属性,进入控制面板系统和安全系统
(3)点击高级系统设置→进入系统属性弹窗→点击环境变量→进入环境变量弹窗→选择系统变量下的path→点击编辑点击→进入编辑环境变量弹窗
(4)点击新建→粘贴之前复制的bin路径
(5)点击确定,逐步保存退出
动态操作示例如下:
ffmpeg 设置环境变量
除了ffmpeg,还需要安装pyinstaller库用于程序打包。可用以下命令进行安装:
pipinstallpyinstaller
如果遇到安装失败或下载速度较慢,可换源:
pipinstallpyinstaller-ihttps://pypi.doubanio.com/simple/
importjsonimportosimportreimportshutilimportsslimporttimeimportrequestsfromconcurrent.futuresimportthreadpoolexecutorfromlxmlimportetree
导入的库包括用于爬取和解析网页的库,还包括创建线程池的库和进行其他处理的库,大多数都是python自带的,如有未安装的库,可使用pip install xxx命令进行安装。
#设置请求头等参数,防止被反爬headers={'accept':'*/*','accept-language':'en-us,en;q=0.5','ur-agent':'mozilla/5.0(windowsnt10.0;wow64)applewebkit/537.36(khtml,likegecko)chrome/80.0.3987.116safari/537.36'}params={'from':'arch','id':'9698329271136034665'}
设置请求头等参数,减少被反爬的可能。
defre_video_info(text,pattern):'''利用正则表达式匹配出视频信息并转化成json'''match=re.arch(pattern,text)returnjson.loads(match.group(1))defcreate_folder(aid):'''创建文件夹'''ifnotos.path.exists(aid):os.mkdir(aid)defremove_move_file(aid):'''删除和移动文件'''file_list=os.listdir('./')forfileinfile_list:#移除临时文件iffile.endswith('_video.mp4'):os.remove(file)pasliffile.endswith('_audio.mp4'):os.remove(file)pass#保存最终的视频文件eliffile.endswith('.mp4'):ifos.path.exists(aid+'/'+file):os.remove(aid+'/'+file)shutil.move(file,aid)
主要包括两方面的基本处理,为正式爬取下载做准备:
利用正则表达式提取信息defdownload_video_batch(referer_url,video_url,audio_url,video_name,index):'''批量下载系列视频'''#更新请求头headers.update({"referer":referer_url})#获取文件名short_name=video_name.split('/')[2]print("%d.t视频下载开始:%s"%(index,short_name))#下载并保存视频video_content=requests.get(video_url,headers=headers)print('%d.t%st视频大小:'%(index,short_name),round(int(video_content.headers.get('content-length',0))/1024/1024,2),'tmb')received_video=0withopen('%s_video.mp4'%video_name,'ab')asoutput:headers['range']='bytes='+str(received_video)+'-'respon=requests.get(video_url,headers=headers)output.write(respon.content)#下载并保存音频audio_content=requests.get(audio_url,headers=headers)print('%d.t%st音频大小:'%(index,short_name),round(int(audio_content.headers.get('content-length',0))/1024/1024,2),'tmb')received_audio=0withopen('%s_audio.mp4'%video_name,'ab')asoutput:headers['range']='bytes='+str(received_audio)+'-'respon=requests.get(audio_url,headers=headers)output.write(respon.content)received_audio+=len(respon.content)returnvideo_name,indexdefdownload_video_single(referer_url,video_url,audio_url,video_name):'''单个视频下载'''#更新请求头headers.update({"referer":referer_url})print("视频下载开始:%s"%video_name)#下载并保存视频video_content=requests.get(video_url,headers=headers)print('%st视频大小:'%video_name,round(int(video_content.headers.get('content-length',0))/1024/1024,2),'tmb')received_video=0withopen('%s_video.mp4'%video_name,'ab')asoutput:headers['range']='bytes='+str(received_video)+'-'respon=requests.get(video_url,headers=headers)output.write(respon.content)#下载并保存音频audio_content=requests.get(audio_url,headers=headers)print('%st音频大小:'%video_name,round(int(audio_content.headers.get('content-length',0))/1024/1024,2),'tmb')received_audio=0withopen('%s_audio.mp4'%video_name,'ab')asoutput:headers['range']='bytes='+str(received_audio)+'-'respon=requests.get(audio_url,headers=headers)output.write(respon.content)received_audio+=len(respon.content)print("视频下载结束:%s"%video_name)video_audio_merge_single(video_name)
这部分包括系列视频的批量下载和单个视频的下载,两者的大体实现原理近似,但是由于两个函数的参数有差别,因此分别实现。在具体的实现中,首先更新请求头,请求视频链接并保存视频(无声音),再请求音频链接并保存音频,在这个过程中得到相应的视频和音频文件的大小。
defvideo_audio_merge_batch(result):'''使用ffmpeg批量视频音频合并'''video_name=result.result()[0]index=result.result()[1]importsubprocessvideo_final=video_name.replace('video','video_final')command='ffmpeg-i"%s_video.mp4"-i"%s_audio.mp4"-ccopy"%s.mp4"-y-loglevelquiet'%(video_name,video_name,video_final)subprocess.popen(command,shell=true)print("%d.t视频下载结束:%s"%(index,video_name.split('/')[2]))defvideo_audio_merge_single(video_name):'''使用ffmpeg单个视频音频合并'''print("视频合成开始:%s"%video_name)importsubprocesscommand='ffmpeg-i"%s_video.mp4"-i"%s_audio.mp4"-ccopy"%s.mp4"-y-loglevelquiet'%(video_name,video_name,video_name)subprocess.popen(command,shell=true)print("视频合成结束:%s"%video_name)
这个过程也是批量和单个分开,大致原理差不多,都是调用subprogress模块来生成子进程,popen类来执行shell命令,由于已经将ffmpeg加入环境变量,所以shell命令可以直接调用ffmpeg来合并音视频。
defbatch_download():'''使用多线程批量下载视频'''#提示输入需要下载的系列视频对应的idaid=input('请输入要下载的视频id(举例:链接/d/file/titlepic/aid=%2791748877%27 />只有一个视频,没有和它属于同一个系列的其他视频,如下图单个视频下载
此时,除了右下方的相关推荐中的视频,没有其他视频,右上方只有弹幕列表、没有视频列表。为了代码的复用,将单个视频下载时提示用户输入需求的代码单独提取出来作为single_input(),下载的函数另外作为single_download(aid, acc_quality)函数实现,在该函数中:
通过视频链接如
解析网页,得到相应的字符串并转化成json,如下:
视频信息json转化
字符串json格式化可使用进行在线转化。
获取到视频的标题、根据输入确定的视频质量、持续时长、视频链接和音频链接,并调用download_video_single()函数下载该视频。
(2)多个视频的下载:
这里,多个视频之间是没有关系的,多个视频的下载实际上是先获取到所有的aid,并进行循环,对每个视频链接传入参数调用单个视频下载的函数即可。同时设立线程池,大小为3,既不会对资源有太大的要求,也能实现多任务、提高下载效率。
(3)系列视频的下载
此时,多个视频属于同一系列,如是一个课程系列,如下:
系列视频
显然,此时右上方有视频列表,标明了有65个子视频,每个视频用p标识,如第2个视频就是
。对于所有视频,先获取到视频的相关信息,再加入进程池进行下载,并在任务结束之后回调函数video_audio_merge_batch()合并音视频,并进行文件整理。
7.主函数
defmain():'''主函数,提示用户进行三种下载模式的选择'''download_choice=input('请输入您需要下载的类型:n1代表下载单个视频,2代表批量下载系列视频,3代表微信昵称女批量下载多个不同视频,默认下载单个视频t')#批量下载系列视频ifdownload_choice=='2':batch_download()#批量下载多个单个视频elifdownload_choice=='3':multiple_download()#下载单个视频el:single_input()if__name__=='__main__':'''调用主函数'''main()
主函数中实现3种下载方式对应的函数的分别调用。
三、项目分析和说明
1.结果测试
对3种方式进行测试的效果如下:
项目测试一:单个视频测试
项目测试二:系列视频测试
项目测试三:多个不同视频测试
3种下载情景的测试效果均较好,下载速度也能与一般的下载速度相媲美。
代码可点击
进行下载。
改进说明
b站网站也一直在变化,所以对于下载可能也会有一些变化,所以将改进的地方在下面列举出来:
(1)网址参数变化
举例说明:
这段时间发现b站一个视频系列的链接变成,即是无规律的字符串(可能是经过某种算法编码或加密得到的),现在从链接中不能得到视频(系列)的aid,这时候可以借助浏览器工具抓包查看数据来找到该视频的aid,如下:
b站视频aid转bvid
在左侧寻找stat开头的请求,后边的参数即为aid,该请求api的完整链接为
,所以可以直接在该链接中获取aid,也可以查看该请求的具体内容,可以看到第一个数据就是aid,我们也可以看到随机字符串就是bvid,可能是建立了aid和bvid的一一映射,找到aid就可以正常下载了。
2.软件打包
在命令行中,使路径位于代码所在路径运行
pyinstallerbilibili_downloader_1.py
打印
136info:pyinstaller:3.6137info:python:3.7.4138info:platform:windows-10-10.0.18362-sp0140info:wrotexxxxbili_video_batch_downloadbilibili_downloader_1.spec205info:upxisnotavailable.209info:extendingpythonpathwithpaths['xxxxbili_video_batch_download','xxxxbili_video_batch_download']210info:checkinganalysis211info:buildinganalysisbecauanalysis-00.tocisnonexistent211info:initializingmoduledependencygraph...218info:cachingmodulegraphhooks...247info:analyzingba_library.zip...5499info:cachingmoduledependencygraph...5673info:runninganalysisanalysis-00.toc5702info:addingmicrosoft.windows.common-controlstodependentasmbliesoffinalexecutablerequiredbyxxxpythonpython37python.exe6231info:analyzingxxxxbili_video_batch_downloadbilibili_downloader_1.py7237info:processingpre-safeimportmodulehookurllib3.packages.six.moves10126info:processingpre-safeimportmodulehooksix.moves14287info:processingmodulehooks...14288info:loadingmodulehook"hook-certifi.py"...14296info:loadingmodulehook"hook-cryptography.py"...14936info:loadingmodulehook"hook-encodings.py"...15093info:loadingmodulehook"hook-lxml.etree.py"...15097info:loadingmodulehook"hook-pydoc.py"...15099info:loadingmodulehook"hook-xml.py"...15330info:lookingforctypesdlls15334info:analyzingrun-timehooks...15339info:includingrun-timehook'pyi_rth_multiprocessing.py'15344info:includingrun-timehook'pyi_rth_certifi.py'15355info:lookingfordynamiclibraries15736info:lookingforeggs15737info:usingpythonlibraryxxxpythonpython37python37.dll15757info:foundbindingredirects:[]15776info:warningswrittentoxxxxbili_video_batch_downloadbuildbilibili_downloader_1warn-bilibili_downloader_1.txt15942info:graphcross-referencewrittentoxxxxbili_video_batch_downloadbuildbilibili_downloader_1xref-bilibili_downloader_1.html15967info:checkingpyz15968info:buildingpyzbecaupyz-00.tocisnonexistent15968info:buildingpyz(zlibarchive)xxxxbili_video_batch_downloadbuildbilibili_downloader_1pyz-00.pyz16944info:buildingpyz(zlibarchive)xxxxbili_video_batch_downloadbuildbilibili_downloader_1pyz-00.pyzcompletedsuccessfully.16980info:checkingpkg16981info:buildingpkgbecaupkg-00.tocisnonexistent16981info:buildingpkg(carchive)pkg-00.pkg17030info:buildingpkg(carchive)pkg-00.pkgcompletedsuccessfully.17034info:bootloaderxxxpythonpython37libsite-packagespyinstallerbootloaderwindows-64bitrun.exe17034info:checkingexe17035info:buildingexebecauexe-00.tocisnonexistent17035info:buildingexefromexe-00.toc17037info:appendingarchivetoexexxxxbili_video_batch_downloadbuildbilibili_downloader_1bilibili_downloader_1.exe17046info:buildingexefromexe-00.toccompletedsuccessfully.17053info:checkingcollect17053info:buildingcollectbecaucollect-00.tocisnonexistent17055info:buildingcollectcollect-00.toc
出现info: building exe from exe-00.toc completed successfully. 即打包成功。在当前路径下找到dist或build目录下的bilibili_downloader_1目录下的bilibili_downloader_1.exe,即是打包后的软件。点击打开即可进行选择和输入,开始下载相应视频。测试示例如下:
项目打包下载测试
在bilibili_downloader_1.exe的同级目录下可以看到下载保存的视频。
3.改进分析
该项目是www.887551.com进行b站视频下载的首次尝试,难免有很多不足,在实现的过程中和后期的总结中,可以看出还存在一些问题:
还不能下载b站上的所有视频,目前局限于各种普通视频教程,不能下载直播视频、大会员番剧等,可以在后期进一步优化;代码过于繁琐,有不少功能类似的重复代码,可以进一步简化、提高代码的复用性;没有采取适当的措施应对b站的反爬,可能会因为请求过多而无法正常下载。
可以在后期进行优化,使整个程序更加健壮。4.合法性说明
本项目的出发点是方便地下载b站上的学习视频,可梦见亲人去世是什么意思以更好地学习各类教程,这对程序猿来说也是一种福利,但是绝不用与其他商业目的,所有读者可以参考执行思路和程序代码,但不能用于恶意和非法目的(恶意频繁下载视频、非法盈利等),如有违者请自行负责。本项目在实施的过程中可能参考了其他大佬的实现思路,如有侵犯他人利益,请联系更改或删除。本项目是b站视频批量下载系列的第一篇,有很多尚待改进的地方,后期会继续更新,欢迎各位读者交流指正,以期不断改进。
本文发布于:2023-04-05 21:16:29,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/77ef1320395177d149d1db5e4a59d714.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:b站视频怎么下载到电脑(超详介绍b站视频流程).doc
本文 PDF 下载地址:b站视频怎么下载到电脑(超详介绍b站视频流程).pdf
留言与评论(共有 0 条评论) |