当前位置:   article > 正文

用 Python 处理 B 站下载视频

python读取b站缓存文件

bilibili(哔哩哔哩,又称B站)是2009年6月推出的一个AGC相关的弹幕视频分享网站,是年轻人潮流文化的娱乐社区,可能对于听过但是不经常上b站的童鞋来说,对于b站最大的影响的就是二次元、动漫、弹幕等等。但是作为国内知名的弹幕视频网站,b站已经不仅仅局限于动漫,还有着丰富的学习资源。

B站图标

作者本人常在b站搜索一些关于人工智能、机器学习类的视频资源,常常都是使用手机下载后离线观看,为了电脑观看方便也会使用“视频合并助手”一类的APP对视频进行转换处理后导入电脑观看,适逢春节假期再次下载视频想导入到电脑上观看,发现以前的视频转换APP已经失效,无法搜索到下载到手机里的b站视频资源,随后开始了下文描述的视频合成工作。

基本思路

  • 目的:合成哔哩哔哩APP缓存到手机的文件,并转换为MP4格式

  • 基本思路:

    1. 1.分析下载文件目录结构和缓存文件  
    2. 2.使用库来合成文件
  • 开发环境:

    1. 1.手机:华为Mate20x EMUI10   哔哩哔哩APP 版本:5.53.1
    2. 2.开发环境:MacBook Pro 2015,PYTHON3.7.6 64-bit, Visual Studio Code  1.41.1

0x00 哔哩哔哩APP缓存文件目录结构及文件分析

打开手机文件管理器,找到Android/data/tv.danmaku.bili/down文件夹,结构如下图所示:

app目录

其中以8位数字命名的文件夹用于单个视频专辑的存储,其一级子目录是从数字1开始递增命名,每个目录内存储的是缓存的分节文件(可以理解为每一集)。其二级子目录均是以数字16命名,这是很规律的。

在每一个视频专辑下有以下几个文件:

1.在一级子目录下有danmaku.xml和entry.json,其中danmaku.xml为弹幕文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <i>
  3.     <chatserver>chat.bilibili.com</chatserver>
  4.     <chatid>132379211</chatid>
  5.     <mission>0</mission>
  6.     <maxlimit>3000</maxlimit>
  7.     <state>0</state>
  8.     <real_name>0</real_name>
  9.     <source>k-v</source>
  10.     <d p="22.23400,1,25,16777215,1575199941,0,aaaeeaeb,25196110486700034">地气儿</d>
  11.     <d p="1318.88600,1,25,16777215,1578391805,0,48b91c28,26869566679810052">指定了版本的那个装不上,只能装最新的</d>
  12.     <d p="582.62400,1,25,16777215,1578964914,0,15eedcf5,27170040630476802">nice</d>
  13.     <d p="26.29000,1,25,16777215,1579009720,0,c1d89d8e,27193531775320068">哈哈哈确实</d>
  14. </i>

entry.json文件则是关于缓存视频的描述文件:

  1. {
  2.     "media_type"2,
  3.     "has_dash_audio"true,
  4.     "is_completed"true,
  5.     "total_bytes"21176174,
  6.     "downloaded_bytes"21176174,
  7.     "title""(全)基于python的Opencv项目实战",
  8.     "type_tag""16",
  9.     "cover""http:\/\/i2.hdslb.com\/bfs\/archive\/afae181e4bb00d7ca2e97f192e6f11dc2c3d8142.jpg",
  10.     "prefered_video_quality"16,
  11.     "guessed_total_bytes"0,
  12.     "total_time_milli"1152336,
  13.     "danmaku_count"0,
  14.     "time_update_stamp"1580398289030,
  15.     "time_create_stamp"1580348758458,
  16.     "avid"77390697,
  17.     "spid"0,
  18.     "seasion_id"0,
  19.     "bvid""",
  20.     "page_data": {
  21.         "cid"132379572,
  22.         "page"6,
  23.         "from""vupload",
  24.         "part""06、边缘检测",
  25.         "link""",
  26.         "rich_vid""",
  27.         "vid""",
  28.         "has_alias"false,
  29.         "weblink""",
  30.         "offsite""",
  31.         "tid"39,
  32.         "width"960,
  33.         "height"540,
  34.         "rotate"0,
  35.         "download_title""视频已缓存完成",
  36.         "download_subtitle""(全)基于python的Opencv项目实战 06、边缘检测"
  37.     }
  38. }

我们需要从这个json中提取“download_subtitle”字段作为文件的命名。
2.在以“16”命名的二级子目录下有3个文件,从文件的名称可以判断audio.m4s和vedio.m4s两个文件应该是缓存的音频和视频文件,我们可以尝试使用播放器播放这两个文件,发现能够成功的播放但是视频中没有声音,可以断定B站将一个视频的音频和视频分开存储了。

视频

音频

还剩下一个index.json文件

  1. {
  2.     "video": [{
  3.         "id"16,
  4.         "base_url""https:\/\/upos-sz-mirrorhw.bilivideo.com\/upgcxcode\/11\/92\/132379211\/132379211-1-30015.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEuENvNC8aNEVEtEvE9IMvXBvE2ENvNCImNEVEIj0Y2J_aug859r1qXg8xNEVE5XREto8GuFGv2U7SuxI72X6fTr859IB_&uipk=5&nbs=1&deadline=1580403879&gen=playurl&os=hwbv&oi=611071466&trid=69dea77b6c6a4049a6f88615e82ada05u&platform=android&upsig=1e3e3eedc71aba8b50ce51e67f3ca508&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform&mid=280178137",
  5.         "backup_url": ["https:\/\/upos-sz-mirrorks3.bilivideo.com\/upgcxcode\/11\/92\/132379211\/132379211-1-30015.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEuENvNC8aNEVEtEvE9IMvXBvE2ENvNCImNEVEIj0Y2J_aug859r1qXg8xNEVE5XREto8GuFGv2U7SuxI72X6fTr859IB_&uipk=5&nbs=1&deadline=1580403879&gen=playurl&os=ks3bv&oi=611071466&trid=69dea77b6c6a4049a6f88615e82ada05u&platform=android&upsig=6de0ffa1809d46318ca36387ca8d8634&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform&mid=280178137"],
  6.         "bandwidth"104293,
  7.         "codecid"7,
  8.         "size"19069578,
  9.         "md5""eab8c79d8ab56a973626a20e1dee6c25"
  10.     }],
  11.     "audio": [{
  12.         "id"30216,
  13.         "base_url""https:\/\/upos-sz-mirrorkodo.bilivideo.com\/upgcxcode\/11\/92\/132379211\/132379211-1-30216.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEuENvNC8aNEVEtEvE9IMvXBvE2ENvNCImNEVEIj0Y2J_aug859r1qXg8xNEVE5XREto8GuFGv2U7SuxI72X6fTr859IB_&uipk=5&nbs=1&deadline=1580403879&gen=playurl&os=kodobv&oi=611071466&trid=69dea77b6c6a4049a6f88615e82ada05u&platform=android&upsig=59e394e791a6ccb7c32b7d2eb1f0957d&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform&mid=280178137",
  14.         "backup_url": ["https:\/\/upos-sz-mirrorks3.bilivideo.com\/upgcxcode\/11\/92\/132379211\/132379211-1-30216.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEuENvNC8aNEVEtEvE9IMvXBvE2ENvNCImNEVEIj0Y2J_aug859r1qXg8xNEVE5XREto8GuFGv2U7SuxI72X6fTr859IB_&uipk=5&nbs=1&deadline=1580403879&gen=playurl&os=ks3bv&oi=611071466&trid=69dea77b6c6a4049a6f88615e82ada05u&platform=android&upsig=856c6fed7b7f7c1a4967a8e40cf8fc59&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform&mid=280178137"],
  15.         "bandwidth"67113,
  16.         "codecid"0,
  17.         "size"12272062,
  18.         "md5""5d7a6a8e6f4c2809ac61eeafa1d9eaae"
  19.     }]
  20. }

这个json文件包含了音频文件和视频文件的相关信息。

0x01 合成音视频文件

通过上述分析,我们找到了单个专辑的缓存文件,下面需要做的就是将音轨合并到视频中去,为此我们需要使用Moviepy这个库。MoviePy是一个用于视频编辑的python模块,你可以用它实现一些基本的操作(比如视频剪辑,视频拼接,插入标题),还可以实现视频合成,还有视频处理,抑或用它加入一些自定义的高级的特效。此外,MoviePy可以读写绝大多数常见的视频格式,甚至包括GIF格式!详细的使用说明可以参考MoviePy - 中文文档和官方文档。
首先需要安装Moviepy库,使用pip直接安装即可,所需要的依赖库如numpy等会在安装时自动下载并配置:

pip install moviepy

安装完毕后即可使用,我们先用单个文件尝试一下,代码如下:

  1. from moviepy.editor import VideoFileClip,AudioFileClip #从moviepy中导入editor包
  2. audioFile  = r"/Users/airwolf/Desktop/81427329/1/16/audio.m4s"   #指定需要读取的音频文件
  3. videoFile  = r"/Users/airwolf/Desktop/81427329/1/16/video.m4s"   #指定需要读取的视频文件
  4. outputfile = r"/Users/airwolf/Desktop/81427329/output.mp4"       #指定输出文件
  5. video_in = VideoFileClip(videoFile) #读取视频文件
  6. audio_in =AudioFileClip(audioFile) #读取音频文件
  7. video_out = video_in.set_audio(audio)   #video_out文件的输出是将音频文件合并到video_in文件的音轨中
  8. video.write_videofile(outputfile) #输出video_out文件

处理


此时我们用播放器打开输入文件output.mp4,发现音频文件已经合成到视频文件中了。

合成信息


下一步我们就着手批量的文件合成,首先将音视频合成的方法封装成一个函数:

  1. def set_audio(proc_file, output_path):
  2.     (file_name, audio_file, vedio_file) = proc_file
  3.     file_name = file_name.replace('.''-').replace('“'"").replace('”'"")#对文件名称中含有的影响命名的特殊字符进行处理
  4.     original_vedio = VideoFileClip(vedio_file)
  5.     audio = AudioFileClip(audio_file)
  6.     video = original_vedio.set_audio(audio)
  7.     outputfile = os.path.join(output_path, file_name)+".mp4"#形成输出文件名
  8.     video.write_videofile(outputfile)

函数的输入有2个参数,参数proc_file表示要处理的文件信息,按照[文件名称,音频文件名,视频文件名]的列表形式输入,output_path为合成后的MP4文件输出路径。接着需要遍历视频专辑下所有的子目录,把待处理的视频放入一个proc_fileList列表中:

  1. import os
  2. import json
  3. proc_fileLis=[]
  4. def get_proList(init_path):
  5.     folder = os.listdir(init_path)
  6.     for subfolder in folder:
  7.         name_path = os.path.join(init_path, subfolder)
  8.         json_file = os.path.join(name_path, "entry.json")
  9.         if os.path.exists(json_file):
  10.             file_info = []  #用于封装带处理的文件信息,格式为:[文件名,音频文件名,视频文件名]
  11.             with open(json_file, 'r') as f: #从json文件中提取文件名
  12.                 data = json.load(f)
  13.                 file_name = data["page_data"]["part"]
  14.                 file_info.append(file_name)
  15.             a_filename = os.path.join(name_path, "16/audio.m4s")
  16.             v_filename = os.path.join(name_path, "16/video.m4s")
  17.             file_info.append(a_filename)
  18.             file_info.append(v_filename)
  19.             proc_fileList.append(file_info)#将带处理文件加入到proc_fileList中

函数的输入参数init_path为待处理第一级目录,即上文所指的以8个数字命名的文件夹。
接着编写主函数:

  1. import sys
  2. if __name__ == "__main__":
  3.     init_path = sys.argv[1]
  4.     get_proList(init_path)
  5.     for proc_file in proc_fileList:
  6.         print(proc_file)
  7.         set_audio(proc_file,init_path)

最后保存为proc.py。
使用时打开终端,输入如下命令,即可完成视频的转换:

python proc.py 处理文件路径

作者简介:

Airwolf,非IT行业码农,国家嵌入式系统设计师。自小学6年级自学BASIC开启编程生涯,酷爱编程,喜欢用实用简洁的程序解决工作生活中的问题。

打赏码

Python中文社区作为一个去中心化的全球技术社区,以成为全球20万Python中文开发者的精神部落为愿景,目前覆盖各大主流媒体和协作平台,与阿里、腾讯、百度、微软、亚马逊、开源中国、CSDN等业界知名公司和技术社区建立了广泛的联系,拥有来自十多个国家和地区数万名登记会员,会员来自以工信部、清华大学、北京大学、北京邮电大学、中国人民银行、中科院、中金、华为、BAT、谷歌、微软等为代表的政府机关、科研单位、金融机构以及海内外知名公司,全平台近20万开发者关注。

▼ 点击成为社区注册会员      喜欢文章,点个在看

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/912842
推荐阅读
相关标签
  

闽ICP备14008679号