MATLAB技巧:一键下载B站高清视频(下篇)

0 前言

N久以前分享了Matlab中利用现成的B站视频解析网站 贝贝bilibili-B站视频下载 来爬取视频,还没看到这个分享的朋友,可以戳下方的推文链接

推文链接: 如何用Matlab一键下载B站高清视频(上)

  • 利用模拟鼠标键盘的方法有一定的局限性,即不能干涉程序与当前交互的浏览器界面
  • 利用浏览器交互的方法只能适用于系统上,等系统并不适用;再一个问题是创建服务器对象时可能会报如下报错:

对于这个问题,目前解决的方法之一是需要重置:在中的选项卡中选择 重置设置,然后重启电脑,无脑般地就可以用了。

当然有的电脑按照上面的设置后依然会报错,具体原因未知,目前我还没有找到其他解决的方法,不知道大家有没有好的解决方案呢?

接下来......

惨不忍睹的大型翻车现场:

限制反爬,添加了验证码!一个好的解析网站就该这样。只不过对于投机取巧的程序而言只能......

鉴于前面的两种方法都不太令人满意,何止是不太满意,根本是无法满意!那今天我们就介绍一种更常规的方法,利用API提供的接口,只需发送一个合理的请求就能得到b站视频的下载链接。

截止目前,网络上有很多爬取B站视频的帖子,大多数是利用Python的,有少部分是利用Matlab的。那为何我们还要再分一杯羹呢?原因有二:

  1. 此处的目的是学习和分享如何利用MATLAB爬取B站视频
  2. 已有的MATLAB爬取得到的B站视频是非1080P的,并且只针对单P视频

这篇推文主要的参考资料是:一款开源的基于Python的爬取B站视频工具,我们参考的B站视频API接口就来源于此。

另外,已有方法《MATLAB爬虫程序,批量获取文本、图片和视频(中)》《MATLAB爬虫程序,批量获取文本、图片和视频(下)》爬取下来的B站视频是非1080P的,下面是我们的方法和该方法下载同一视频的信息比较:(源视频地址: https://www.bilibili.com/video/BV11f4y1r7e8)

已有方法

我们的方法

已有方法

我们的方法

当然,我们的主要需求是下载多P视频,这就迫使我们得造这个轮子了!友情提示:不到万不得已,不要造轮子!

下面就让我们一起看看造轮子的过程吧!

1 API接口

要想下载b站上某个UP主的视频,那首先得进入到他/她的空间里,我们以"尚硅谷" 为例,其空间地址是 ,其中的数字编号 是每一个UP主独一无二的,称为

在下载视频时往往需要两个重要的参数:(号)我们在 如何用Matlab一键下载B站高清视频(上)

中已经见过,即单个视频或者多p视频都对应着一个,而对于多p视频则有不同的号来决定具体的视频地址,当然单个视频仅有一个号。

下面说明通过UP主的号来得到

简单抓一次包吧,我们再谷歌浏览器中输入空间地址,按后,查看选项卡,仔细看看每一个响应,最后会定位到下面的信息:

我们将响应的用新的窗口打开就会得到我们需要的号的重要信息了:

总结一下

指定up主的空间信息接口:

有了这两个参数就可以查询号了, 因为不会在正常访问时查看到,于是也需要调用特定接口来获取:

接口使用很简单,只有一个参数:aid(av号)或 bvid(bv号)二选一

例如:

通过上面的接口,我们就能获得

有了参数,我们就可以构建接口请求了:

其中,参数表示视频的质量,值设定为80可以获得高清1080p的视频,但需要注意的是我们请求时得提供

否则下载的视频是480p的非高清

注意:已有方法中提供的接口为

这两个接口在结尾处有一定的区别,大家可以都尝试做一做。

2 实现过程

接下来还是聊下代码实现吧,这个是根据我的需求来写的:

  • 下载UP主所有发布的视频(这类UP一般是没有多p视频的,如
  • 下载UP主的某个教学视频(这类UP一般是有多p视频的,如

--- 脚本入口

--- 设置请求头函数

--- 由bv或者av号获取cid号的功能实现

--- 实现下载单p视频

--- 实现下载多p视频

对于函数,源码如下:

 

function options = setWebOptions(cookie)

 randNum = randperm(23);

 randNum(randNum>=10);

 options = weboptions('Timeout', randNum(1));

 options.UserAgent = ...

     'Mozilla/5.0 (Windows NT 10.0; Win64; x64) appleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36';

 options.RequestMethod = 'get';

 options.HeaderFields = {'Cookie', cookie; 'Origin', 'https://www.bilibili.com'; ...

     'accept', 'application/json'; ...

     'accept-encoding', 'gzip, deflate, br'; ...

     'accept-language', 'en-US,en;q=0.8'; ...

     'content-type', 'application/json'; ...

     'Referer', 'https://www.bilibili.com'};

 end  % end functions

function options = setWebOptions(cookie)
 randNum = randperm(23);
 randNum(randNum>=10);
 options = weboptions('Timeout', randNum(1));
 options.UserAgent = ...
     'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36';
 options.RequestMethod = 'get';
 options.HeaderFields = {'Cookie', cookie; 'Origin', 'https://www.bilibili.com'; ...
     'accept', 'application/json'; ...
     'accept-encoding', 'gzip, deflate, br'; ...
     'accept-language', 'en-US,en;q=0.8'; ...
     'content-type', 'application/json'; ...
     'Referer', 'https://www.bilibili.com'};
 end  % end functions

需要传入参数,获取的方法也很简单,祖传方法===>首先登陆B站,然后按键刷新,在请求头中找到,如下图,然后把那划红线的一坨东西粘贴过来即可。

 

function mainInfo = bilibiliVideoInfo(mid, numberOfPage)
 %bilibiliVideoInfo  return some main data fou user from bilibili.com
 %  Inputs:
 %        mid string (mid = '517327498';)
 %        numberOfPage int (numberOfPage = 1|2|3|, ..., |n-1|n);
 %  Outputs:
 %        mainInfo struct (mainInfo.title|mainInfo.facePic|mainInfo.bvid)
 %  Usage:
 %        >>mainInfo = bilibiliVideoInfo('517327498', 5);
 %          mainInfo =
 %          title: {143×1 cell}
 %          facePic: {143×1 cell}
 %          bvid: {143×1 cell}
 %
 % -------------------------------------------
 %  Set request options
 % -------------------------------------------
 randNum = randperm(23);
 randNum(randNum>=10);
 options = weboptions('Timeout', randNum(1));
 options.UserAgent = ...
     'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36';
 options.RequestMethod = 'get';

 % -------------------------------------------
 %  Set crawl mainly data
 % -------------------------------------------
 mainInfo.title = [];
 mainInfo.facePic = [];
 mainInfo.bvid = [];

 for page = 1 : numberOfPage
     disp(['  | Climbing to the ', num2str(page), 'th page']);
     pause(0.2)
     % API
     dataUrl = ['https://api.bilibili.com/x/space/arc/search?', 'mid=', mid, '&ps=30&tid=0&pn=', num2str(page)];
     res = webread(dataUrl, options);
     allInfo = res.data.list.vlist;
     mainInfo.title = [mainInfo.title; {allInfo.title}'];
     mainInfo.facePic = [mainInfo.facePic; {allInfo.pic}'];
     mainInfo.bvid = [mainInfo.bvid; {allInfo.bvid}'];
 end  % end for

 % mainInfo.facePic = regexprep(mainInfo.facePic, '//(.+?)', 'http://$1');
 disp('  ')
 end  % end function

 

function getSinglePageVideo(mid, numberOfPage, numberOfVideoStart, saveDir, cookie)

 %getSingleVideo   Get a single page video

 %   Inputs:

 %        mid string (mid = '517327498';)

 %        numberOfPage int (numberOfPage = 1|2|3|, ..., |n-1|n);  

 %        numberOfVideoStart int ---Video starting number

 %        saveDir string

 %        cookie string

 %   Outputs:

 %        none

 %

 %% Set request options

 options = setWebOptions(cookie);

 

 %% Set parameters

 apiUrl = 'https://api.bilibili.com/x/player/playurl?';

 

 %%

 if ~exist(saveDir, 'dir')

     mkdir(saveDir);

 end

 

 if ~exist([saveDir, '/facepics'], 'dir')

     mkdir([saveDir, '/facepics']);

 end

 %% Get video's url by cid and bvd number

 mainInfo = bilibiliVideoInfo(mid, numberOfPage);

 numberOfBvid = length(mainInfo.bvid);

 

 %

 pat = '(?:\|)|(?:\\)|(?:\:)|(?:\*)|(?:\?)|(?:")|(?:<)|(?:>)|(?:/)';

 

 for ii = numberOfVideoStart : numberOfBvid

     bvid = mainInfo.bvid{ii};

     title = regexprep(mainInfo.title{ii}, pat, '_');

     res = webread(['https://api.bilibili.com/x/web-interface/view?bvid=', bvid]);

     % Get cid number

     cid = num2str(res.data.pages.cid);

     res = webread([apiUrl, 'bvid=', bvid, '&cid=', cid, '&qn=80&otype=json']);

     % Get player url

     playUrl = res.data.durl.url;

     % Save face pictures

     disp(['  |-->Saving ', num2str(ii), 'th|', num2str(numberOfBvid), ' picture']);

     faceImg = imread(mainInfo.facePic{ii});

     imwrite(faceImg, [saveDir, '/facepics/', num2str(ii), '_', title, '.png']);

     % Save video

     disp(['  |-->Saving ', num2str(ii), 'th|', num2str(numberOfBvid), ' video']);

     websave([saveDir, '/', num2str(ii), '_', title, '.mp4'], playUrl, options);

     disp('   ------Save finished!----------')

     disp('                                 ')

 end  % end for

 end  % end function

 

function getSinglePageVideo(mid, numberOfPage, numberOfVideoStart, saveDir, cookie)
 %getSingleVideo   Get a single page video
 %   Inputs:
 %        mid string (mid = '517327498';)
 %        numberOfPage int (numberOfPage = 1|2|3|, ..., |n-1|n);
 %        numberOfVideoStart int ---Video starting number
 %        saveDir string
 %        cookie string
 %   Outputs:
 %        none
 %
 %% Set request options
 options = setWebOptions(cookie);

 %% Set parameters
 apiUrl = 'https://api.bilibili.com/x/player/playurl?';

 %%
 if ~exist(saveDir, 'dir')
     mkdir(saveDir);
 end

 if ~exist([saveDir, '/facepics'], 'dir')
     mkdir([saveDir, '/facepics']);
 end
 %% Get video's url by cid and bvd number
 mainInfo = bilibiliVideoInfo(mid, numberOfPage);
 numberOfBvid = length(mainInfo.bvid);

 %
 pat = '(?:\|)|(?:\\)|(?:\:)|(?:\*)|(?:\?)|(?:")|(?:<)|(?:>)|(?:/)';

 for ii = numberOfVideoStart : numberOfBvid
     bvid = mainInfo.bvid{ii};
     title = regexprep(mainInfo.title{ii}, pat, '_');
     res = webread(['https://api.bilibili.com/x/web-interface/view?bvid=', bvid]);
     % Get cid number
     cid = num2str(res.data.pages.cid);
     res = webread([apiUrl, 'bvid=', bvid, '&cid=', cid, '&qn=80&otype=json']);
     % Get player url
     playUrl = res.data.durl.url;
     % Save face pictures
     disp(['  |-->Saving ', num2str(ii), 'th|', num2str(numberOfBvid), ' picture']);
     faceImg = imread(mainInfo.facePic{ii});
     imwrite(faceImg, [saveDir, '/facepics/', num2str(ii), '_', title, '.png']);
     % Save video
     disp(['  |-->Saving ', num2str(ii), 'th|', num2str(numberOfBvid), ' video']);
     websave([saveDir, '/', num2str(ii), '_', title, '.mp4'], playUrl, options);
     disp('   ------Save finished!----------')
     disp('                                 ')
 end  % end for
 end  % end function

鉴于篇幅原因,的源代码在这里就不展示了,想要获得获得文中所有代码的朋友门,请在公众号后台回复:bilibili视频(下) (注:和 bilibli视频(上)有区别,抱歉,这里b后面少了个i,纠正一下)

需要说明的一点是:对于以标题作为视频名称保存需要注意文件名是否合法的问题,因此代码中用正则表达式 将标题进行了过滤。

最后调用脚本源码如下:

% ------------------------------------------------

 %  Main script for obtain video from bilibili

 % ------------------------------------------------

 clear

 clc

 close all

 

 isSendMail = true;

 cookie = ' ';  % 需要将cookie粘贴到这里

 

 % ------------------------------------------------

 %  Obtain single page video

 % ------------------------------------------------

 mid = ' ';

 numberOfPage = [];

 numberOfVideoStart = [];

 saveDir = '保存视频的文件夹名称';

 getSinglePageVideo(mid, numberOfPage, numberOfVideoStart, saveDir, cookie);

 

 % ------------------------------------------------

 %  Obtain  multi-page video

 % ------------------------------------------------

 bvid = 'BV1Cy4y117vt';

 numberOfVideoStart = 1;

 saveDir = 'shangguigu_zidingyi';

 getMultiPageVideo(bvid, numberOfVideoStart, saveDir, cookie);

 

% ------------------------------------------------
 %  Main script for obtain video from bilibili
 % ------------------------------------------------
 clear
 clc
 close all

 isSendMail = true;
 cookie = ' ';  % 需要将cookie粘贴到这里

 % ------------------------------------------------
 %  Obtain single page video
 % ------------------------------------------------
 mid = ' ';
 numberOfPage = [];
 numberOfVideoStart = [];
 saveDir = '保存视频的文件夹名称';
 getSinglePageVideo(mid, numberOfPage, numberOfVideoStart, saveDir, cookie);

 % ------------------------------------------------
 %  Obtain  multi-page video
 % ------------------------------------------------
 bvid = 'BV1Cy4y117vt';
 numberOfVideoStart = 1;
 saveDir = 'shangguigu_zidingyi';
 getMultiPageVideo(bvid, numberOfVideoStart, saveDir, cookie);

通过这种方法我爬取了一部分罗老师说刑法的视频,也爬取了有关尚硅谷的前端教学视频

部分视频部分视频

整个过程最让我受益的是爬取下来的这些视频,看了其中一部分,特别是,除了罗老师的讲课有趣味,更重要的是让人增加一些法律、刑法方面的知识,知法懂法才能更好的做一个守法的合格公民嘛

感兴趣的朋友们可以拿到代码后亲自运行下载视频对照一下,用这种方法下载的视频原格式是1080p的,这与 贝贝bilibili-B站视频下载 网站解析出来的格式的1080p稍微有些区别,比如文件大小,但视频质量上两者差别不大。

今天的分享就到这里了,有问题请朋友们后台发消息留言,祝大家生活愉快!

参考文献

https://github.com/5ime/bilidown

https://mp.weixin.qq.com/s/3EavntbM07J6PpLScYnb5w

https://mp.weixin.qq.com/s/SIYlNO3ZR82VF1D4nYzIgQ

QR Code
微信扫一扫,欢迎咨询~

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 155-2731-8020
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

手机不正确

公司不为空