bilibili-download 哔哩哔哩视频下载器(批量下载专栏视频)
环境jdk14
maven构建
接口文档地址:https://github.com/1015770492/bilibili-download/blob/master/doc/bilibili-Api文档.md
原理是下载视频文件(不带声音)和音频文件,然后通过第三方工具ffmpeg
合并视频文件和音频文件为一个文件
ffmpeg官网地址
自定义的http请求工具类部分代码展示;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;public class BiliBiliHttpUtils {/*** 没有就创建目录,有则返沪true* @param destDirName* @return*/public static boolean createDirect(String destDirName) {File file = new File(destDirName);if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}return true;}/*** 下载文件的作用,需要3个参数 资源原路径,真正下载的url,保存本地的路径** @param refererUrl 视频的参考路径,* @param url 真正下载的url链接,可以是m4s文件和audio文件,下载后需要合并* @param savePath 保存的路径* @return 下载成功则返回true,中间报异常退出则返回false*/public static boolean downloadFile(String refererUrl, String url, String savePath) {System.out.print("下载文件:");System.out.println(savePath);//打印保存的文件路径RestTemplate restTemplate = new RestTemplate();HttpHeaders headers = new HttpHeaders();headers.add("referer", refererUrl);//设置请求头HttpEntity<String> entity = new HttpEntity<String>("", headers);System.out.println("发送请求获取文件的输入流");ResponseEntity<Resource> in = restTemplate.exchange(url, HttpMethod.GET, entity, Resource.class);if (in.getStatusCode() == HttpStatus.OK) {try (InputStream is = in.getBody().getInputStream()) {//java9新特性自动关闭流boolean flag = createDirect(savePath);if (flag) {try (FileOutputStream fos = new FileOutputStream(savePath);) {System.out.println("正在写入文件...");is.transferTo(fos);//写入输出流return true;//写入成功返回true} catch (IOException e) {e.printStackTrace();System.out.println("写入中断");}}} catch (IOException e) {e.printStackTrace();System.out.println("创建文件夹失败");}System.out.println("文件写入完成");} else {System.out.println("状态码" + in.getStatusCode());System.out.println(in.toString());}return false;//默认返回失败}/*** 获取url中的 bvid** @param url* @return* @throws Exception*/public static String getBVID(String url) throws Exception {Pattern BVIDPartPattern = Pattern.compile("BV[a-z|0-9|A-Z]*");Matcher matcher = BVIDPartPattern.matcher(url);String bvid;if (matcher.find()) {bvid = matcher.group();} else {throw new Exception("传入的url中不包含bvid");}return bvid;}/*** 传入视频的播放地址,例如url: "https://www.bilibili.com/video/BV1m4411H7pi" 获取其中包含BV的这串字符串** @param url* @return* @throws Exception*/public static JSONObject getCidJSON(String url) throws Exception {String bvid = getBVID(url);//从url中转换成最终请求的url接口String requestUrl = new StringBuilder("http://api.bilibili.com/x/web-interface/view?bvid=").append(bvid).toString();String jsonString = new RestTemplate().getForEntity(requestUrl, String.class).getBody();JSONObject parse = JSONObject.parseObject(jsonString);return parse.getJSONObject("data");//返回data部分}/*** 传入cid的json数组,获取所有下载链接--》一个cid对应一个视频,一个视频有多个清晰度的播放源** @param cidJSONObject* @return*/public static List<JSONObject> getPlayUrlList(JSONObject cidJSONObject) {String bvid = cidJSONObject.getString("bvid");//视频的idString title = cidJSONObject.getString("title");//标题--》用来做文件夹String picUrl = cidJSONObject.getString("pic");//封面图片JSONArray pages = cidJSONObject.getJSONArray("pages");//包含这一系列视频的cid内容//如果传入的cid过多并行流会导致http请求过大,容易被服务器拒绝try (Stream<JSONObject> jsonObjectStream = pages.stream().map(o -> {JSONObject obj = (JSONObject) o;String cid = obj.getString("cid");//获取cidString part = obj.getString("part");//获取视频名 前缀System.out.println(part);//映射//获取播放地址的apiString requestUrl = new StringBuilder("https://api.bilibili.com/x/player/playurl?cid=").append(cid).append("&bvid=").append(bvid).append("&qn=80&fnver=0&fnval=16&fourk=1").toString();String jsonString = new RestTemplate().getForEntity(requestUrl, String.class).getBody();//执行太快了JSONObject data = JSONObject.parseObject(jsonString).getJSONObject("data");//获取api返回的jaon中的data对象/*** 添加自定义的属性,方便保存*/data.put("cid", cid);//将cid添加到返回的数据中data.put("directName", title);//添加视频的标题作为文件夹data.put("videoName", part);//添加视频的名称return data;//将添加了自定义属性的json返回,作为新的流})) {// System.out.println(cidJSONObject);return jsonObjectStream.collect(Collectors.toList());//将收集到的url封装起来}}}
合并图像和音频文件代码展示
import java.io.File;
import java.io.IOException;
import java.util.concurrent.*;public class MergeVideoAndAudioUtils {static ExecutorService executorService = Executors.newFixedThreadPool(20);public static boolean merge(String videoPath, String audioPath, String savePath) throws ExecutionException, InterruptedException {File directory = new File("");//设定为当前文件夹String currentAbsolutePath = directory.getAbsolutePath();
// System.out.println(currentAbsolutePath);String relativePath = "src/main/java/top/huashengshu/bilibili/utils/merge/util/ffmpeg.exe";String ffmpegAbsolutePath = new StringBuilder(currentAbsolutePath).append("/").append(relativePath).append(" -i \"").append(videoPath).append("\" -i \"").append(audioPath).append("\" -c copy \"").append(savePath).append("\"").toString();//合并音视频文件得命令CompletableFuture<Process> processFuture = CompletableFuture.supplyAsync(() -> {Process process = null;try {Runtime runtime = Runtime.getRuntime();//获取cmd窗口System.out.println(ffmpegAbsolutePath);//打印一下命令process = runtime.exec(ffmpegAbsolutePath);//执行合并命令} catch (IOException e) {e.printStackTrace();return process;//异常返回}return process;}, executorService);Process process = processFuture.get();//获取上一个的process对象CompletableFuture.runAsync(() -> {while (process.isAlive()) {}//判断合并命令是否执行完成,如果完成则会跳出循环clearGarbageFile(videoPath,savePath);//清理垃圾文件clearGarbageFile(audioPath,savePath);//清理垃圾文件},executorService);return true;//将合并结果返回}public static boolean clearGarbageFile(String filePath,String mp4Path) {File mp4File = new File(mp4Path);if (mp4File.exists()) {File tempFile = new File(filePath);if (tempFile.exists()){tempFile.delete();//文件存在,删除文件}else {System.out.println("文件不存在:"+filePath);}}else {System.out.println("没有合并成:"+mp4Path);}return true;}}
使用方式
调用BiliBiliUtils
的patchDownload
方法即可
/*** 测试案例** @param args*/
public static void main(String[] args) {String referUrl = "https://www.bilibili.com/video/BV1oi4y1u7Bq";//测试用的urlBiliBiliUtils.patchDownload(referUrl, "D:/");//将referUrl系列的所有视频存到D:/盘
}
项目没有完全完成,在改进中,并且会有后期版本,采用vue+ElementUI的静态页面,调用工具类实现批量下载视频,暂时没有实现登录功能
bilibili-download 哔哩哔哩视频下载器(批量下载专栏视频)相关推荐
- 使用Flickr下载器批量下载Flickr的相册
相信用过Flickr下载图片的人都知道从Flickr上下载原图的操作有点小麻烦.楼主花了许久时间在网上寻找批量下载工具,一直没找到合适的.于是就自己动手写了个Win10应用:Flickr下载器,功能是 ...
- Earthdata(NASA)网站数据使用IDM(Internet Download Manager)下载器批量下载方法(MERRA-2为例)
最近给亲近的人写了教程,想着也给大家分享一下. MERRA-2 网址: GES DISC 这个网址是下载MERRA-2 instM_3d_asm_Np类型的数据文件,具体各部分字母代表什么,看下载列表 ...
- 手机下载神器批量下载图片教程
手机版IDM下载神器批量下载图片漫画实际操作教程,现在介绍两个批量下载图片的方法 视频教程: 手机IDM下载器批量下载图片漫画实际操作 首先,打开你要下载图片的网页,同时打开手机版idm下载器和手机记 ...
- 自媒体批量下载短视频软件,批量下载短视频有诀窍
自媒体批量下载短视频软件,批量下载短视频有诀窍,现在随着短视频的爆火,越来越多的自媒体人和公司都注意到短视频这个平台流量有多大,短视频很容易变现也很容易引流,接下来我们来看看自媒体批量下载短视频软件有 ...
- android源码下载方法 批量下载 基于windows os
安装win版的Gitbash, 在这里 http://msysgit.googlecode.com/files/Git-1.6.0.2-preview20080923.exe. 选择默认安装路径(否则 ...
- Google Earth谷歌地球卫片下载器--可下载全球历史卫星,无偏移、高精度
Google Earth谷歌地球卫片下载器--可下载全球历史卫星,无偏移.高精度 Google Earth谷歌地球卫片下载器 (build662)升级正式发布,水经注万能地图下载器升级正式发布,水经注 ...
- GUI 界面的免费音乐下载 支持批量下载
GUI 界面的免费音乐下载 支持批量下载 导包 import urllib import requests import wx import urllib import requests import ...
- python 爬取菜鸟教程python100题,百度贴吧图片反爬虫下载,批量下载
每天一点点,记录学习 python 爬取菜鸟教程python100题 近期爬虫项目,看完请点赞哦: 1:python 爬取菜鸟教程python100题,百度贴吧图片反爬虫下载,批量下载 2:pytho ...
- python批量下载bilibili视频_如何批量下载bilibili的视频?
貌似现在 you-get 已经支持批量下载了.通过下面命令就可以批量下载了 you-get --playlist 网址 本来是带这个需求来的,看到 Venchi 的答案,装了 Python3 之后发现 ...
- CS231n公开课系列1_视频+课件+作业下载+GitHub批量下载工具
主要内容: PPT download notes download assignment download GitHub批量下载工具 CS231n是斯坦福大学教授针对使用深度学习处理图像(计算机视觉处 ...
最新文章
- 根据镜像安装oracle插件,docker镜像alpine中安装oracle客户端
- 计算路由汇总的方法(CIDR)
- 全flash站制作剖析
- Win8怎么查看IP地址
- 【linux学习笔记八】常用命令
- 全球首款采用离心风扇/90Hz刷新率的电竞手机红魔3发布
- 《时代周刊》四份NFT杂志封面拍卖结束,总售价为276 ETH
- DataSet的Join操作
- Python入门之面向对象module,library,package之间区别
- UBUNTU上新建GIT库
- 十大硬盘数据恢复软件
- 机器人学基础——坐标
- 电工/模电/数电/电气控制/PLC/单片机综合实验装置
- 拯救你的SD卡,找回丢失的文件
- 360众测靶场云文件服务器,360 政企安全官网_帮助应对高级威胁攻击
- 基于halcon的HSV颜色匹配实例
- Hive有分区文件到时select不到数据问题-----修复分区命令 msck repair table xxxxx
- 日计划安排 --- 凡事预则立,不预则废
- 《三体》中的经典名句
- 【Android 10 源码】healthd 模块 BatteryService 初始化