抓取Bilibili哔哩哔哩网站视频(Java和Python双版本实现)

news/2024/5/20 23:53:46/文章来源:https://blog.csdn.net/XiumingLee/article/details/106014889

1、B站视频真实地址分析

我一直觉得编程语言只是一种工具,重要的是思想🐶。下面先来分析下B站视频的真实地址。

1.1 获取视频的信息数据

使用PC通过浏览器随便打开一个B站的视频,右键检查或者是按F12,查看网页源代码。我们会发现有一个script标签内的内容是这样的。

嗯,仿佛这就是视频的信息了。下面我们将其复制出来,格式化一下。

window.__playinfo__ = {"data": {"accept_format": "flv720,flv480,mp4","accept_description": ["高清 720P", "清晰 480P", "流畅 360P"],"accept_quality": [64, 32, 16],"dash": {"video": [{"id": 64,"baseUrl": "http://cn-sdbz-cu-v-05.bilivideo.com/upgcxcode/18/80/187918018/187918018-1-30064.m4s?expires=1589032200&platform=pc&ssig=7TagzkxicmXQCX-eJG1rWw&oi=1894210281&trid=4b3d732f515544e49c843d5f2c87f64bu&nfc=1&nfb=maPYqpoel5MI3qOUX6YpRA==&mid=388810686&logo=80000000","base_url": "http://cn-sdbz-cu-v-05.bilivideo.com/upgcxcode/18/80/187918018/187918018-1-30064.m4s?expires=1589032200&platform=pc&ssig=7TagzkxicmXQCX-eJG1rWw&oi=1894210281&trid=4b3d732f515544e49c843d5f2c87f64bu&nfc=1&nfb=maPYqpoel5MI3qOUX6YpRA==&mid=388810686&logo=80000000","backupUrl": ["http://cn-sdyt-cu-v-11.bilivideo.com/upgcxcode/18/80/187918018/187918018-1-30064.m4s?expires=1589032200&platform=pc&ssig=7TagzkxicmXQCX-eJG1rWw&oi=1894210281&trid=4b3d732f515544e49c843d5f2c87f64bu&nfc=1&nfb=maPYqpoel5MI3qOUX6YpRA==&mid=388810686&logo=40000000", "http://cn-hbcd2-cu-v-07.bilivideo.com/upgcxcode/18/80/187918018/187918018-1-30064.m4s?expires=1589032200&platform=pc&ssig=7TagzkxicmXQCX-eJG1rWw&oi=1894210281&trid=4b3d732f515544e49c843d5f2c87f64bu&nfc=1&nfb=maPYqpoel5MI3qOUX6YpRA==&mid=388810686&logo=40000000"],"backup_url": ["http://cn-sdyt-cu-v-11.bilivideo.com/upgcxcode/18/80/187918018/187918018-1-30064.m4s?expires=1589032200&platform=pc&ssig=7TagzkxicmXQCX-eJG1rWw&oi=1894210281&trid=4b3d732f515544e49c843d5f2c87f64bu&nfc=1&nfb=maPYqpoel5MI3qOUX6YpRA==&mid=388810686&logo=40000000", "http://cn-hbcd2-cu-v-07.bilivideo.com/upgcxcode/18/80/187918018/187918018-1-30064.m4s?expires=1589032200&platform=pc&ssig=7TagzkxicmXQCX-eJG1rWw&oi=1894210281&trid=4b3d732f515544e49c843d5f2c87f64bu&nfc=1&nfb=maPYqpoel5MI3qOUX6YpRA==&mid=388810686&logo=40000000"],"bandwidth": 1883922,"mimeType": "video/mp4","mime_type": "video/mp4","width": 720,"height": 1280,"SegmentBase": {"Initialization": "0-974", "indexRange": "975-1162"},"segment_base": {"initialization": "0-974", "index_range": "975-1162"},"codecid": 7},], "audio": [{"id": 30280,"baseUrl": "http://cn-sdyt-cu-v-05.bilivideo.com/upgcxcode/18/80/187918018/187918018-1-30280.m4s?expires=1589032200&platform=pc&ssig=ud9zkd5aAUp7mB4yPjI_LA&oi=1894210281&trid=4b3d732f515544e49c843d5f2c87f64bu&nfc=1&nfb=maPYqpoel5MI3qOUX6YpRA==&mid=388810686&logo=80000000","base_url": "http://cn-sdyt-cu-v-05.bilivideo.com/upgcxcode/18/80/187918018/187918018-1-30280.m4s?expires=1589032200&platform=pc&ssig=ud9zkd5aAUp7mB4yPjI_LA&oi=1894210281&trid=4b3d732f515544e49c843d5f2c87f64bu&nfc=1&nfb=maPYqpoel5MI3qOUX6YpRA==&mid=388810686&logo=80000000","backupUrl": ["http://cn-hbcd2-cu-v-14.bilivideo.com/upgcxcode/18/80/187918018/187918018-1-30280.m4s?expires=1589032200&platform=pc&ssig=ud9zkd5aAUp7mB4yPjI_LA&oi=1894210281&trid=4b3d732f515544e49c843d5f2c87f64bu&nfc=1&nfb=maPYqpoel5MI3qOUX6YpRA==&mid=388810686&logo=40000000", "http://cn-sdjn2-cu-v-05.bilivideo.com/upgcxcode/18/80/187918018/187918018-1-30280.m4s?expires=1589032200&platform=pc&ssig=ud9zkd5aAUp7mB4yPjI_LA&oi=1894210281&trid=4b3d732f515544e49c843d5f2c87f64bu&nfc=1&nfb=maPYqpoel5MI3qOUX6YpRA==&mid=388810686&logo=40000000"],"backup_url": ["http://cn-hbcd2-cu-v-14.bilivideo.com/upgcxcode/18/80/187918018/187918018-1-30280.m4s?expires=1589032200&platform=pc&ssig=ud9zkd5aAUp7mB4yPjI_LA&oi=1894210281&trid=4b3d732f515544e49c843d5f2c87f64bu&nfc=1&nfb=maPYqpoel5MI3qOUX6YpRA==&mid=388810686&logo=40000000", "http://cn-sdjn2-cu-v-05.bilivideo.com/upgcxcode/18/80/187918018/187918018-1-30280.m4s?expires=1589032200&platform=pc&ssig=ud9zkd5aAUp7mB4yPjI_LA&oi=1894210281&trid=4b3d732f515544e49c843d5f2c87f64bu&nfc=1&nfb=maPYqpoel5MI3qOUX6YpRA==&mid=388810686&logo=40000000"],"bandwidth": 319474,"mimeType": "audio/mp4","mime_type": "audio/mp4","SegmentBase": {"Initialization": "0-919", "indexRange": "920-1107"},"segment_base": {"initialization": "0-919", "index_range": "920-1107"},},]}}, "session": "996ecc0413599104d175e5c254e70fb7", "videoFrame": {}
}

我删除了一些没有的信息,通过上面的信息我们可以得到以下几点信息:

  1. B站的视频是音视频分离的。
  2. 我们可以从js中获取真实音视频地址。
  3. 提供了"高清 720P", "清晰 480P", "流畅 360P"方式供我们选择。不要问我为什么没有1080P的,俺也不知道😢。

下面我们再来看一下B站自己发送请求的信息。

我们发现每次请求时都携带了,此次请求文件的字节位置信息。

1.2 抓取B站视频的思路

  1. 请求想要下载视频的地址,获取页面html。
  2. 从页面中解析出视频的基本信息,音视频的url地址等信息。
  3. 下载音视频文件,发送请求时带上请求的范围(range)。(注:本文的实现中,没有使用多线程,直接请求的整个文件)
  4. 将下载完成的音视频文件合并成完成的视频文件。

1.3 用到的第三方库和软件

  1. 第三方软件
  • ffmpeg:用于合并音视频文件。官方网址:http://ffmpeg.org/。
    • ffmpeg:是处理音视频的利器,感兴趣可以搜索相关资料了解下。本文只要你下载下来,将ffmpeg位置写到代码变量里就可以了。
  1. Python
  • requests:用于发送Http请求
  • ffmpeg-python:方便操作ffmpeg
  • HTMLParser:python自带的HTML解析工具
  1. Java
  • hutool:一个国人开源的Java工具包。强烈推荐。

  • jsoup:Java解析HTML的利器

2、代码实现

注:本文中代码下载音视频均采用的单线程的方式,如果使用多线程,一定要计算好每个请求的请求范围,以及下载完成后,合并文件时的顺序。

2.1 Python的实现

解析html

class BiliHTMLParser(HTMLParser):"""继承自HTMLParser。用于解析html"""def __init__(self):super().__init__()self.isTitle = 0self.videoName = ""  # 视频名称self.videoInfo = {}  # 视频信息def handle_starttag(self, tag, attrs):if tag != 'title':returnself.isTitle += 1def handle_endtag(self, tag):if tag == 'title' and self.isTitle:self.isTitle -= 1def handle_data(self, data):"""获取当前页面的视频信息:param data: tag中的数据:return:"""if data and self.isTitle:  # 用于获取视频名称self.videoName = dataif data.startswith('window.__playinfo__='):infoStr = data.split('window.__playinfo__=')[-1]  # 截取`window.__playinfo__=`之后的字符串self.videoInfo = json.loads(infoStr)  # 字符串转字典dict

获取视频信息

def getVideo(videoInfo, videoName):""":param videoInfo: 视频信息字典dict:param videoName: 视频名称:return:"""# 获取视频的url和初始的大小范围videoBaseUrl = videoInfo['data']['dash']['video'][0]['baseUrl']videoBaseRange = videoInfo['data']['dash']['video'][0]['SegmentBase']['Initialization']# 获取音频的url和初始的大小范围audioBaseUrl = videoInfo['data']['dash']['audio'][0]['baseUrl']audioBaseRange = videoInfo['data']['dash']['audio'][0]['SegmentBase']['Initialization']# 文件下载videoSize = getVideoInfo(videoBaseUrl, videoBaseRange)videoFileName = downloadFile(videoBaseUrl, videoSize, "video", videoName)audioSize = getVideoInfo(audioBaseUrl, audioBaseRange)audioFileName = downloadFile(audioBaseUrl, audioSize, "audio", videoName)# 合并文件outFilePath = "./%s/%s.mp4" % (videoName, videoName)mergeFiles(videoFileName, audioFileName, outFilePath)def getVideoInfo(baseUrl, range):"""获取视频或音频文件的总大小:param baseUrl::param range::return:"""headers = {'Referer': videoUrl,'Range': 'bytes=%s' % (range),}videoRes = requests.get(url=baseUrl, headers=headers)# 获取视频总大小headersInfo = videoRes.headerstotal = headersInfo['Content-Range'].split('/')[-1]print('资源的总字节数:%s' % total)return total

下载音视频

def downloadFile(url, totalSize, type, videoName):"""下载资源:param url: 资源url:param totalSize: 资源总大小:param type: video/audio:param videoName: 视频名称:return:"""headers = {'Referer': videoUrl,'Range': "bytes=%s-%s" % (str(0), str(totalSize))}fileDir = "./%s" % videoNameif not os.path.exists(fileDir):os.mkdir(fileDir)fileName = "./%s/%s-%s.mp4" % (videoName, videoName, type)if not os.path.exists(fileName):res = requests.get(url=url, headers=headers, stream=True)print("开始下载:%s" % type)data = res.contentwith open(fileName, 'wb') as file_obj:file_obj.write(data)print("完成%s的下载" % type)return fileName

合并音视频

def mergeFiles(videoFilePath, audioFilePath, outFilePath):"""合并音视频"""print("开始合并音视频")videoFile = ffmpeg.input(videoFilePath)audioFile = ffmpeg.input(audioFilePath)stream = ffmpeg.output(videoFile, audioFile, outFilePath, vcodec='copy', acodec='copy')ffmpeg.run(stream, cmd=ffmpegPath)print("合并音视频完成")

2.2 Java实现

解析Html

    /** 解析HTML获取相关信息 */private static void htmlParser(){HttpResponse res = HttpRequest.get(VIDEO_URL).timeout(2000).execute();String html = res.body();Document document = Jsoup.parse(html);Element title = document.getElementsByTag("title").first();// 视频名称VIDEO_INFO.videoName = title.text();// 截取视频信息Pattern pattern = Pattern.compile("(?<=<script>window.__playinfo__=).*?(?=</script>)");Matcher matcher = pattern.matcher(html);if (matcher.find()) {VIDEO_INFO.videoInfo = new JSONObject(matcher.group());} else {System.err.println("未匹配到视频信息,退出程序!");return;}getVideoInfo();}

获取视频信息

    /** 解析视频和音频的具体信息 */private static void getVideoInfo(){// 获取视频的基本信息JSONObject videoInfo = VIDEO_INFO.videoInfo;JSONArray videoInfoArr = videoInfo.getJSONObject("data").getJSONObject("dash").getJSONArray("video");VIDEO_INFO.videoBaseUrl = videoInfoArr.getJSONObject(0).getStr("baseUrl");VIDEO_INFO.videoBaseRange = videoInfoArr.getJSONObject(0).getJSONObject("SegmentBase").getStr("Initialization");HttpResponse videoRes = HttpRequest.get(VIDEO_INFO.videoBaseUrl).header("Referer", VIDEO_URL).header("Range", "bytes=" + VIDEO_INFO.videoBaseRange).header("User-Agent", USER_AGENT).timeout(2000).execute();VIDEO_INFO.videoSize = videoRes.header("Content-Range").split("/")[1];// 获取音频基本信息JSONArray audioInfoArr = videoInfo.getJSONObject("data").getJSONObject("dash").getJSONArray("audio");VIDEO_INFO.audioBaseUrl = audioInfoArr.getJSONObject(0).getStr("baseUrl");VIDEO_INFO.audioBaseRange = audioInfoArr.getJSONObject(0).getJSONObject("SegmentBase").getStr("Initialization");HttpResponse audioRes = HttpRequest.get(VIDEO_INFO.audioBaseUrl).header("Referer", VIDEO_URL).header("Range", "bytes=" + VIDEO_INFO.audioBaseRange).header("User-Agent", USER_AGENT).timeout(2000).execute();VIDEO_INFO.audioSize = audioRes.header("Content-Range").split("/")[1];downloadFile();}

下载音视频

    /** 下载音视频 */private static void downloadFile(){// 保存音视频的位置SAVE_PATH = "." + File.separator + VIDEO_INFO.videoName;File fileDir = new File(SAVE_PATH);if (!fileDir.exists()){fileDir.mkdirs();}// 下载视频File videoFile = new File(SAVE_PATH + File.separator + VIDEO_INFO.videoName + "_video.mp4");if (!videoFile.exists()){System.out.println("--------------开始下载视频文件--------------");HttpResponse videoRes = HttpRequest.get(VIDEO_INFO.videoBaseUrl).header("Referer", VIDEO_URL).header("Range", "bytes=0-" + VIDEO_INFO.videoSize).header("User-Agent", USER_AGENT).execute();videoRes.writeBody(videoFile);System.out.println("--------------视频文件下载完成--------------");}// 下载音频File audioFile = new File(SAVE_PATH + File.separator + VIDEO_INFO.videoName + "_audio.mp4");if (!audioFile.exists()){System.out.println("--------------开始下载音频文件--------------");HttpResponse audioRes = HttpRequest.get(VIDEO_INFO.audioBaseUrl).header("Referer", VIDEO_URL).header("Range", "bytes=0-" + VIDEO_INFO.audioSize).header("User-Agent", USER_AGENT).execute();audioRes.writeBody(audioFile);System.out.println("--------------音频文件下载完成--------------");}mergeFiles(videoFile,audioFile);}

合并视频

    private static void mergeFiles(File videoFile,File audioFile){System.out.println("--------------开始合并音视频--------------");String outFile = SAVE_PATH + File.separator + VIDEO_INFO.videoName + ".mp4";List<String> commend = new ArrayList<>();commend.add(FFMPEG_PATH);commend.add("-i");commend.add(videoFile.getAbsolutePath());commend.add("-i");commend.add(audioFile.getAbsolutePath());commend.add("-vcodec");commend.add("copy");commend.add("-acodec");commend.add("copy");commend.add(outFile);ProcessBuilder builder = new ProcessBuilder();builder.command(commend);try {builder.inheritIO().start().waitFor();System.out.println("--------------音视频合并完成--------------");} catch (InterruptedException | IOException e) {System.err.println("音视频合并失败!");e.printStackTrace();}}

3、源码地址

GitHub源码地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_902742.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu docker 简单的静态网站--Nginx部署流程

1.建立web容器 docker run -p 80 --name web -i -t ubuntu /bin/bash -p 设置端口为80 创建要操作的文件目录存放静态文件 mkdir www/html 2安装相应的工具 nginx vim apt-get install -y nginx apt-get install -y vim 3.写简单的静态文件配置nginx 3.1进入1中的h…

聚合购物一站式采购平台HTML网站源码

聚合购物一站式采购平台HTML网站源码 点击下载源码

浏览器翻译插件免费下载网站链接

点击进入下载网站&#xff0c;免费下载&#xff0c;无广告亲测好用 http://web.yeekit.com/ 将下载的插件拖进相应浏览器中即可进行插件安装

一步步构建大型网站架构

之前我简单向大家介绍了各个知名大型网站的架构&#xff0c;亿万用户网站MySpace的成功秘密、Flickr架构、YouTube网站架构、PlentyOfFish 网站架构学习、WikiPedia技术架构学习笔记。这几个都很典型&#xff0c;我们可以从中获取很多有关网站架构方面的知识&#xff0c;看了之…

网站升级HTTPS,免费SSL证书Let’s Encrypt安装使用教程:Apache和Nginx配置方法

推荐方式 参考&#xff1a;https://certbot.eff.org/#ubuntutrusty-nginx 此处只记录ubuntu14.04安装方法 安装 $ sudo apt-get update $ sudo apt-get install software-properties-common $ sudo add-apt-repository ppa:certbot/certbot $ sudo apt-get update $ sudo apt…

php + nginx 网站并发压力测试及优化

一、测试工具&#xff1a; Apache 压力测试工具ab ab是针对apache的性能测试工具&#xff0c;可以只安装ab工具。 ubuntu安装ab apt-get install apache2-utils centos安装ab yum install httpd-tools ab的参数详细解释 格式&#xff1a; ./ab [options] [http://]host…

域名过期了,但是备案信息还是我的,网站被人举报涉黄怎么办?

一、名下闲置域名被举报涉黄 2020年12月3日&#xff0c;宁静祥和的下午&#xff0c;正在按部就班地敲着代码&#xff0c;突然被一通电话打乱了思绪。 电话里说是XX市委网信办的&#xff0c;说我名下有个域名 ws65535.xyz 被人举报包含色情内容。 最初我以为是骗子&#xff08…

如何从初识C++进化成C++的高手?你可以从这几个网站上进阶

如何从一个C小白进化成C大神&#xff1f;你可以从这几个网站上进阶 摘要&#xff1a;所谓欲练神功&#xff0c;挥刀自宫&#xff0c;如不自宫&#xff0c;也能成功&#xff0c;本篇文章所介绍的独门秘籍绝不用自宫&#xff0c;看后掌握了&#xff0c;直接进入编程宗师行列&…

科研人论文必备神器(软件、网站、插件等)

科研人论文必备神器&#xff08;软件、网站、插件等&#xff09; 仅真实地推荐高效、有用的内容&#xff0c;无广告 文章目录 科研人论文必备神器&#xff08;软件、网站、插件等&#xff09;文献查找1.谷歌学术2.Web of Science&#xff08;WOS&#xff09;3.PubMed4.知网5.百…

爬取近千张女神赫本的美照,做成网站并给其中的黑白照片上色,好玩!

对于赫本相信大家都非常熟悉了&#xff0c;绝对是一代女神&#xff0c;今天我们就来爬取女神的近千张美照&#xff0c;在一饱眼福的同时&#xff0c;还可以学习下如何做网站&#xff0c;对于老旧的黑白照片&#xff0c;还有一键上色功能可以玩&#xff0c;真是一举多得 照片爬…

2021全球网站流量最高的网站,Python 带你看一看

世界上流量最大的网站有哪些&#xff0c;也许我们都能脱口而出&#xff0c;比如 Google&#xff0c;YouTube&#xff0c;Facebook 还有 PxxnHub 等等&#xff0c;今天我们就通过多个维度来看看&#xff0c;那些叱咤全球的流量网站&#xff01; 数据获取 首先我们还是先抓取数据…

JavaWeb12(使用过滤器通过动态代理模式解决网站字符集编码乱码问题、注解、类加载器、全盘负责托管机制)

最近复习期末考&#xff0c;都好久没更了。还剩最后一科计算机视觉&#xff0c;2号考完就结束啦&#xff0c;趁着复习空档更新一波。 目录 Part01:使用过滤器通过动态代理模式解决网站字符集编码乱码问题1、面试题&#xff1a;增强一个对象的方法有几种&#xff1f;* 继承&…

ygbook生成xml格式的sitemap网站地图

原本ygbook是有自动生成sitemap地图这个功能的&#xff0c;网址是&#xff1a;域名/sitemap/baidu 但是这种方式只有百度支持&#xff0c;其他的都不支持&#xff0c;不信看下面的图 360上传提示 看图上面的红色字体&#xff0c;除了百度&#xff0c;其他搜索引擎只支持.xml格…

Linux宝塔禁止国外ip访问服务器,屏蔽国外ip访问网站代码(亲测有效)

当网站做到一定程度时&#xff0c;说不准就会引来某些不良人士的攻击&#xff0c;以及扫描漏洞&#xff0c;或者是当你网站有起色后&#xff0c;会有某些禽兽直接采集你的网站&#xff0c;偏偏特么的采集网站比自己的网站权重还高&#xff0c;这简直没法忍。但是你们发现没&…

网站静态资源CDN分离时图标不显示

其实网站图标不显示的问题我遇到很多次了&#xff0c;一般出现这种问题说明我网站已经到一定程度了&#xff0c;流量大了就要开始做动静分离&#xff0c;把网站的css、js、图片、字体等等全部静态资源脱离出来单独放到一个服务器&#xff0c;因为存放静态资源的服务器带宽都很大…

搜索引擎优化基础,第 2 部分: SEO 关键词和基础设施策略

作为一名 Web 站点开发人员&#xff0c;使您的 Web 站点得到搜索引擎的关注是获得成功的关键因素之一。在这个共分四部分的系列中&#xff0c;您将学习对 Web 站点进行有机优化所需的基础知识。在第 1 部分中&#xff0c;您了解了为什么白帽 SEO 技术对站点有益的背景知识。在第…

css教程–十步学会用css建站(全)

Update : 本篇已得到原作者Steve Dennis 的翻译准予&#xff0c;在此Jorux表示感谢&#xff01; 本教程主要参考Creating a CSS Layout from scratch &#xff0c;由Jorux翻译&#xff0c;以意译为主&#xff0c;其间加入了不少Jorux的个人观点&#xff0c;省略了一些多余的说…

参考调查网站

1、Tezaa 是一个提供在线投票服务的网络社区。通过Tezaa 进行投票或者评论&#xff0c;你可以和他人分享你对各种问题的观点&#xff0c;也可以征求他人对于你自己问题的观点&#xff0c;帮助自己作出正确的选择。 2、Quibblo&#xff1a;在线投票调查社区 (1) :http://www.qui…

大型网站架构演变和知识体系

之前也有一些介绍大型网站架构演变的文章&#xff0c;例如 LiveJournal 的、 ebay 的&#xff0c;都是非常值得参考的&#xff0c;不过感觉他们讲的更多的是每次演变的结果&#xff0c;而没有很详细的讲为什么需要做这样的演变&#xff0c;再加上近来感觉有不少同学都很难明白为…

二十个你必须知道的SEO概念

如果你拥有一个网站或独立博客&#xff0c;或者你的工作多少和互联网有关&#xff0c;那你一定耳濡目染多多少少对SEO&#xff08;搜索引擎优化&#xff09;有一定了解。本文将列举其中20个 SEO领域最常用的名词和概念&#xff0c;如果你打算熟悉和了解他们请继续阅读。当然&am…