bilibili视频下载

2,163 阅读3分钟

喜欢看b站的小伙伴们,看到喜欢的视频时,可能想要下载下来,保存到自己的电脑。因为有的视频可能过了几天就被up主删除了,或者被b站删除了。然而b站没有提供下载的功能

于是作为网站开发者的我,连夜分析了一波b站的视频机制(发现机制和YouTube是相同的,所以这个方法也可以下载YouTube的视频),发现b站为了防止视频被别人获取,可以说是费尽了心思。然而前端是没有安全性可言的,任何网站都能够被pojie。现在假设一个10分钟的视频,b站首先把图像和声音分开发送,然后每次只发送部分内容,比如1分钟的内容。那么算下来,这个视频需要发10个图像包,10个声音包,加起来发送20次

我们来到b站,选择一个喜欢的视频,点击播放,在视频的页面按F12键打开控制台

打开Network选项,发现有很多网络请求,我们找到这种fetch类型的,而且文件比较大的这种,就是视频,它紧挨着的下面的请求就是这段视频对应的音频

鼠标放在视频的那一行,点击右键,选择如图的Copy as fetch
切换到console面板,右键粘贴,如图就是刚刚复制的内容,然后需要进行一点修改,第一行内容不删除会报错,第二行内容有长度限制,所以要删除限制,我们想下载整个完整的视频
字段修改后如下图,按回车键,下面会打印一个Promise,然后鼠标放在上面,右击,选择如图的选项
接着在控制台输入下面的代码,按回车,稍等一回儿,浏览器就会下载一个视频文件,视频就搞定了,但是它是没有声音的,所以我们继续下载音频

temp1.then(_=>_.blob()).then(_=>{
    var url = window.URL.createObjectURL(_)
    var a = document.createElement('a')
    a.href = url
    a.download = 'video'
    a.click()
})

然后我们选择音频,重复刚刚的操作
如图所示,粘贴的代码如下,这样会下载一个audio文件,这就是这个视频的音频文件

temp2.then(_=>_.blob()).then(_=>{
    var url = window.URL.createObjectURL(_)
    var a = document.createElement('a')
    a.href = url
    a.download = 'audio'
    a.click()
})

视频已经完整的下载下来了,接下来可以用一些视频播放软件,把2个文件合并到一起,比如vlc

b站的播放原理:使用浏览器的MediaSource方法,加入视频流和音频流,就可以同步播放,核心代码如下:

var video = document.querySelector('video');
var videoCodec = 'video/mp4; codecs="avc1.42E01E"';
var audioCodec = 'audio/mp4; codecs="mp4a.40.2"';
 
var mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
 
mediaSource.addEventListener('sourceopen', sourceOpen);
 
function sourceOpen(){
    var mediaSource = this;
 
    var videoBuffer = mediaSource.addSourceBuffer(videoCodec);
    var audioBuffer = mediaSource.addSourceBuffer(audioCodec);
 
    /*
    * buffer数据处理(append、remove等)完成时会触发 updateend 事件
    * 这里省略对audioBuffer的 updateended 事件等待
    */
    videoBuffer.addEventListener('updateend', function(){
        mediaSource.endOfStream();
        video.play();
    });
 
    /*
    *  这里省略网络数据请求的过程,且假设音视频都只有一个片段文件。
    */
    videoBuffer.appendBuffer(vbuf);
    audioBuffer.appendBuffer(abuf);
}var video = document.querySelector('video');
var videoCodec = 'video/mp4; codecs="avc1.42E01E"';
var audioCodec = 'audio/mp4; codecs="mp4a.40.2"';
 
var mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
 
mediaSource.addEventListener('sourceopen', sourceOpen);
 
function sourceOpen(){
    var mediaSource = this;
 
    var videoBuffer = mediaSource.addSourceBuffer(videoCodec);
    var audioBuffer = mediaSource.addSourceBuffer(audioCodec);
 
    /*
    * buffer数据处理(append、remove等)完成时会触发 updateend 事件
    * 这里省略对audioBuffer的 updateended 事件等待
    */
    videoBuffer.addEventListener('updateend', function(){
        mediaSource.endOfStream();
        video.play();
    });
 
    /*
    *  这里省略网络数据请求的过程,且假设音视频都只有一个片段文件。
    */
    videoBuffer.appendBuffer(vbuf);
    audioBuffer.appendBuffer(abuf);
}

花了2天周末的时间,分析b站的js源码,才摸清楚b站怎么合并视频和音频,期间学习了js的Blob,ArrayBuffer,TypeBuffer,DataView,MediaSource,非常收益