2025年4月5日 星期六 乙巳(蛇)年 正月初六 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 精彩资源

用二进制流的形式下载网络上的视频-只要视频可以播放就可以下载下来!

时间:11-02来源:作者:点击数:46

1.引言

  • 荔枝微课上面有很多很好的资源,不过上面的视频在手机APP或者网页上播放不太方便,此外很多付费购买的课程是存在一定的期限的,所以我们要么抓紧时间看,要么把它下载下来本地播放,看起来就非常nice了。但是现在他上面的m3u8文件是加密的,如果你没有key的话,是无法进行下载的。我之前是使用一些解析网站(例如豆宝)来下载的,但是那个费用太贵了,一个视频需要0.4元,二三十个视视频就得十几块,不至于付不起,但很抗拒下载这种自己已经付费买过的课,就是不愿意二次付费。
  • 此外,我还尝试过去淘宝上找代下载的,以为万能的淘宝上会便宜一点,只是没想到那个更贵,下载36个视频,30元起步,下载一个视频要一块钱,这和明抢有啥区别?
  • 之前之所以想找解析网站和淘宝待下载,是因为自己的重心在学习励志微课的教程上,而不是想要折腾下载方式,但是没想到这竟然成了自己学习的拦路虎,那自己必须得把它干掉才行。
  • 无奈基于此,遂下午花了两个小时时间来研究具体的下载方式。我想既然视频可以播放出来,那么它一定通过一个过道来传输这个画面。那么我们只要在这个过道的部位设置一个hook,将其保存下来,那岂不是任何可以播放的视频,我们都可以下载下来呢?本教程的解决下载问题的思路就是这样的:我们这里采用二进制流的方法来下载上面的课程,只要这个视频可以在我们的浏览器上正常播放,我们就可以把它下载下来。
  • 但必须承认,这种方式其实也是存在一定的缺点的,一是浏览器必须缓存完视频之后才可以下载,不过这个问题不大,我们可以开倍速播放,最高可以支持到16倍速。
  • 二是下载下来的视频文件和音频文件是分离的,需要之后再手动将视频文件和音频文件合并,这个也问题不大,我们可以写一个脚本来批量完成这个工作。
  • 免责声明:本博客只做技术交流,请勿将代码用于非法用途,更不可用于商业用途。使用代码所造成的一切后果由使用者自行承担。

2.操作

2.1 安装油猴插件无限制下载器

代码

  • // ==UserScript==
  • // @name         Unlimited_downloader
  • // @name:zh-CN   无限制下载器
  • // @namespace    ooooooooo.io
  • // @version      0.1.9
  • // @description  Get video and audio binary streams directly, breaking all download limitations. (As long as you can play, then you can download!)
  • // @description:zh-Cn  直接获取视频和音频二进制流,打破所有下载限制。(只要你可以播放,你就可以下载!)
  • // @author       dabaisuv
  • // @match        *://*/*
  • // @exclude      https://mail.qq.com/*
  • // @exclude      https://wx.mail.qq.com/*
  • // @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  • // @grant        none
  • // @run-atdocument-start
  • // ==/UserScript==
  • (function () {
  •    'use strict';
  •    console.log(`Unlimited_downloader: begin......${location.href}`);
  •    //Setting it to 1 will automatically download the video after it finishes playing.
  •    window.autoDownload = 1;
  •    window.isComplete = 0;
  •    window.audio = [];
  •    window.video = [];
  •    window.downloadAll = 0;
  •    window.quickPlay = 1.0;
  •    const _endOfStream = window.MediaSource.prototype.endOfStream
  •    window.MediaSource.prototype.endOfStream = function () {
  •       window.isComplete = 1;
  •       return _endOfStream.apply(this, arguments)
  •    }
  •    window.MediaSource.prototype.endOfStream.toString = function() {
  •        console.log('endOfStream hook is detecting!');
  •       return _endOfStream.toString();
  •    }
  •    const _addSourceBuffer = window.MediaSource.prototype.addSourceBuffer
  •    window.MediaSource.prototype.addSourceBuffer = function (mime) {
  •       console.log("MediaSource.addSourceBuffer ", mime)
  •       if (mime.toString().indexOf('audio') !== -1) {
  •          window.audio = [];
  •          console.log('audio array cleared.');
  •       } else if (mime.toString().indexOf('video') !== -1) {
  •          window.video = [];
  •          console.log('video array cleared.');
  •       }
  •       let sourceBuffer = _addSourceBuffer.call(this, mime)
  •       const _append = sourceBuffer.appendBuffer
  •       sourceBuffer.appendBuffer = function (buffer) {
  •          console.log(mime, buffer);
  •          if (mime.toString().indexOf('audio') !== -1) {
  •             window.audio.push(buffer);
  •          } else if (mime.toString().indexOf('video') !== -1) {
  •             window.video.push(buffer)
  •          }
  •          _append.call(this, buffer)
  •       }
  •       sourceBuffer.appendBuffer.toString = function () {
  •          console.log('appendSourceBuffer hook is detecting!');
  •          return _append.toString();
  •       }
  •       return sourceBuffer
  •    }
  •    window.MediaSource.prototype.addSourceBuffer.toString = function () {
  •       console.log('addSourceBuffer hook is detecting!');
  •       return _addSourceBuffer.toString();
  •    }
  •    function download() {
  •       let a = document.createElement('a');
  •       a.href = window.URL.createObjectURL(new Blob(window.audio));
  •       a.download = 'audio_' + document.title + '.mp4';
  •       a.click();
  •       a.href = window.URL.createObjectURL(new Blob(window.video));
  •       a.download = 'video_' + document.title + '.mp4';
  •       a.click();
  •       window.downloadAll = 0;
  •       window.isComplete = 0;
  •       // window.open(window.URL.createObjectURL(new Blob(window.audio)));
  •       // window.open(window.URL.createObjectURL(new Blob(window.video)));
  •       // window.downloadAll = 0
  •       // GM_download(window.URL.createObjectURL(new Blob(window.audio)));
  •       // GM_download(window.URL.createObjectURL(new Blob(window.video)));
  •       // window.isComplete = 0;
  •       // const { createFFmpeg } = FFmpeg;
  •       // const ffmpeg = createFFmpeg({ log: true });
  •       // (async () => {
  •       //     const { audioName } = new File([new Blob(window.audio)], 'audio');
  •       //     const { videoName } = new File([new Blob(window.video)], 'video')
  •       //     await ffmpeg.load();
  •       //     //ffmpeg -i audioLess.mp4 -i sampleAudio.mp3 -c copy output.mp4
  •       //     await ffmpeg.run('-i', audioName, '-i', videoName, '-c', 'copy', 'output.mp4');
  •       //     const data = ffmpeg.FS('readFile', 'output.mp4');
  •       //     let a = document.createElement('a');
  •       //     let blobUrl = new Blob([data.buffer], { type: 'video/mp4' })
  •       //     console.log(blobUrl);
  •       //     a.href = URL.createObjectURL(blobUrl);
  •       //     a.download = 'output.mp4';
  •       //     a.click();
  •       // })()
  •       // window.downloadAll = 0;
  •    }
  •    setInterval(() => {
  •       if (window.downloadAll === 1) {
  •          download();
  •       }
  •    }, 2000);
  •    //    setInterval(() => {
  •    //        if(window.quickPlay !==1.0){
  •    //              document.querySelector('video').playbackRate = window.quickPlay;
  •    // }
  •    //
  •    //   }, 2000);
  •    if (window.autoDownload === 1) {
  •       let autoDownInterval = setInterval(() => {
  •          //document.querySelector('video').playbackRate = 16.0;
  •          if (window.isComplete === 1) {
  •             download();
  •          }
  •       }, 2000);
  •    }
  •    (function (that) {
  •       let removeSandboxInterval = setInterval(() => {
  •          if (that.document.querySelectorAll('iframe')[0] !== undefined) {
  •             that.document.querySelectorAll('iframe').forEach((v, i, a) => {
  •                let ifr = v;
  •                // ifr.sandbox.add('allow-popups');
  •                ifr.removeAttribute('sandbox');
  •                const parentElem = that.document.querySelectorAll('iframe')[i].parentElement;
  •                a[i].remove();
  •                parentElem.appendChild(ifr);
  •             });
  •             clearInterval(removeSandboxInterval);
  •          }
  •       }, 1000);
  •    })(window);
  •    // Your code here...
  • })();
  • 点击油猴脚本管理器,选择新建一个脚本
  • 删除新建脚本中已有的内容,然后把上面的代码粘贴进去,点击保存
  • 之后再打开或者刷新荔枝微课视频所在的网页,会发现这个脚本已经自动启动了

2.2下载单个视频

  • 下载单个视频很简单,只需要慢慢地把这个视频播放完,就会自动下载下来视频和音频了
  • 缓存完之后,这里会显示插件想要下载多个文件,我们点击允许
  • 可以看到我下载下载了一个视频和一个音频

2.3合并视频和音频

  • 合并视频、音频,我们借助ffmpeg来完成,这个工具很出名,而且不是本教程的介绍重点,因此具体ffmpeg的安装方法请自行百度吧
  • 我们这里使用的操作语法为ffmpeg -i video.mp4 -i audio.mp4 -c:v copy -c:a aac -strict experimental output.mp4
  • video.mp4为我们下载的视频文件,audio.mp4为我们下载的音频文件,output.mp4为我们想要保存的输出文件
  • 结合我的具体文件名,我这里的命名为
  • ffmpeg -i "video_Zotero IF Pro Max 插件安装.mp4" -i "audio_Zotero IF Pro Max 插件安装.mp4" -c:v copy -c:a aac -strict experimental output.mp4

正在合并

合并完成

- 点击之后是可以正常播放的

2.4加速下载

  • 如果我们是想一边看视频一边下载,那你慢慢看无可厚非。但如果你是想先把网页上的视频下载下来之后在本地观看,那么我们可以让网页倍速播放,这样很短的时间就可以把视频播放完,也就下载完
  • 安装这个油猴脚本[HTML5视频播放器增强脚本] ,之后按C是加速播放,按X是减速,按Z是还原HTML5视频播放器增强脚本HTML5视频播放器增强脚本
  • 速度的极限是16倍速,可以大大节省我们缓存视频的时间
  • 此外,脚本与脚本之间是不影响工作的。我们可以新建几个页面,上面播放不同级的视频,从而进行多线程缓存。这样只要你的电脑性能够强,网速够快,就可以在非常短的时间内把所有的视频都下载完

而且这上面的视频如果不太长的话,建议就使用一倍速或者二倍速播放就行了,这样稳当点,不会中间出错,毕竟短视频总共播放完也不用多长时间

2.5下载一系列视频

  • 下载一系列视频和下载单个视频的操作是一样的,只需要缓存完一个视频,再缓存一个视频就好了。好在荔枝微课上面播放以外一个视频之后,是可以自动播放另一个的。所以我们只需要让浏览器在上面以16倍速挂着,不用多长时间就可以把这个视频缓存完了,也就下载完了
  • 把所有视频都缓存完毕之后,会下载下来两类文件,一个是音频文件,另一个是视频文件。如下图文件夹所示

2.6批量合并

  • 我们按照上面的方法是可以单个对视频进行合并的,但是那样操作太繁琐。特别是当我们有十几个甚至几十个视频的时候,那简直要死人。因此我这里写成了一个脚本,可以直接从下载的视频中提取出来文件名,然后调用命令对其进行合并
  • 这里可以直接用我写的Python脚本来进行合并 只需要把视频和音频文件混合放在一个文件夹中,然后将脚本放在当前目录下运行脚本,之后就会自动将这些个视频和音频文件合并到一起,并放到merge文件夹下面

正在进行多线程合并

全部合并完毕,36个视频一共耗时138秒,也就是2分钟,其实还挺快的

  • C:\Users\Lenovo\AppData\Local\Packages\45479liulios.17062D84F7C46_p7pnf6hceqser\LocalState\history\temp\Snipaste_2023-10-12_18-36-58.png
  • 脚本如下
  • import os
  • import glob
  • import subprocess
  • from concurrent import futures
  • import time
  • def make_dir(path):
  •     import os
  •     dir = os.path.exists(path)
  •     if not dir:
  •         os.makedirs(path)
  • def process_file(file):
  •     if (file_prefix in file):
  •         print('--------------------')
  •         video_name = os.path.basename(file)
  •         audio_name = video_name.replace('video_', 'audio_')
  •         base_name = video_name.replace('video_', '')
  •         print('base_name:', base_name)
  •         print('video_name:', video_name)
  •         print('audio_name:', audio_name)
  •         video_path = os.path.join(folder_path, video_name)
  •         audio_path = os.path.join(folder_path, audio_name)
  •         output_path = os.path.join(output_folder, base_name)
  •         print('output_path:', output_path)
  •         ffmpeg_command = f'ffmpeg -i "{video_path}" -i "{audio_path}" -c:v copy -c:a aac -strict experimental "{output_path}"'
  •         # 使用subprocess运行命令
  •         print('ffmpeg_command:', ffmpeg_command)
  •         subprocess.run(ffmpeg_command, shell=True)
  • folder_path = ''
  • file_prefix = 'video_'
  • file_extension = '*.mp4'  # 假设你只关注扩展名为.mp4的文件
  • output_folder = 'merge'
  • make_dir(output_folder)
  • files = glob.glob(os.path.join(folder_path, file_extension))
  • start_time = time.time()
  • with futures.ThreadPoolExecutor() as executor:
  •     executor.map(process_file, files)
  • end_time = time.time()
  • total_time = end_time - start_time
  • print(f"处理完成,总共使用的时间为:{total_time}秒")
  • 效果如下
  • 可以看到,音频和视频已经合并成一个独立的文件了

3.结语

  • 到这里,这个荔枝微课就全部下载下来了,这个方法永远使用,只要这个视频可以在你电脑上正常播放,就可以把它下载下来。而且不止可以下载荔枝微课的视频,其他任何的网页视频都可以下载下来。Just Enjoy It!

4.报错

  • 为什么下载下来的音频上面有变声的现象?
  • 和网站有关系,测试B站上的视频不存在这个问题
  • 换其他浏览器试一下 经过试验发现,火狐浏览器是可以正常下载下来这个荔枝微课上面的音频的,没有任何问题
  • 为什么使用倍速播放的时候播放不出来视频?
  • 一个视频不要上来,就16倍速,这样可能会直接把网页给干蒙,应该先用原速度把视频播放出来之后再换16倍速
  • 或者刷新一下就好了
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门