m3u8视频文件破解爬取教程(请尊重知识产权,切勿违法),该方法需要基础开发知识

news2024/9/25 17:12:03
// ==UserScript==
// @name         media-source-extract
// @namespace    https://github.com/Momo707577045/media-source-extract
// @version      0.8.2
// @description  https://github.com/Momo707577045/media-source-extract 配套插件
// @author       Momo707577045
// @include      *
// @exclude      http://blog.luckly-mjw.cn/tool-show/media-source-extract/player/player.html
// @downloadURL	 https://blog.luckly-mjw.cn/tool-show/media-source-extract/media-source-extract.user.js
// @updateURL	   https://blog.luckly-mjw.cn/tool-show/media-source-extract/media-source-extract.user.js
// @grant        none
// @run-at document-start
// ==/UserScript==

(function () {
  'use strict';
  (function () {
    if (document.getElementById('media-source-extract')) {
      return
    }
    
    // 轮询监听 iframe 的加载
    setInterval(() => {
      try {
        Array.prototype.forEach.call(document.getElementsByTagName('iframe'), (iframe) => {
          // 若 iframe 使用了 sandbox 进行操作约束,删除原有 iframe,拷贝其备份,删除 sandbox 属性,重新载入
          // 若 iframe 已载入,再修改 sandbox 属性,将修改无效。故通过新建 iframe 的方式绕过
          if(iframe.hasAttribute('sandbox')){
            const parentNode = iframe.parentNode;
            const tempIframe = iframe.cloneNode()
            tempIframe.removeAttribute("sandbox");
            iframe.remove()
            parentNode.appendChild(tempIframe);
          }
        })
      } catch (error) {
        console.log(error)
      }
    }, 1000)


    let sumFragment = 0 // 已经捕获的所有片段数
    let isClose = false // 是否关闭
    let isStreamDownload = false // 是否使用流式下载
    let _sourceBufferList = [] // 媒体轨道
    const $showBtn = document.createElement('div') // 展示按钮
    const $btnDownload = document.createElement('div') // 下载按钮
    const $btnStreamDownload = document.createElement('div') // 流式下载按钮
    const $downloadNum = document.createElement('div') // 已捕获视频片段数
    const $tenRate = document.createElement('div') // 十倍速播放
    const $closeBtn = document.createElement('div') // 关闭
    const $container = document.createElement('div') // 容器
    $closeBtn.innerHTML = `
    <img style="
      padding-top: 4px;
      width: 24px;
      display: inline-block;
      cursor: pointer;
    " src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAk1BMVEUAAADROyVeAAAAMHRSTlMA1Sq7gPribxkJx6Ey8onMsq+GTe10QF8kqJl5WEcvIBDc0sHAkkk1FgO2ZZ+dj1FHfPqwAAACNElEQVRIx6VW6ZqqMAwtFlEW2Rm3EXEfdZa+/9PdBEvbIVXu9835oW1yjiQlTWQE/iYPuTObOTzMNz4bQFRlY2FgnFXRC/o01mytiafP+BPvQZk56bcLSOXem1jpCy4QgXvRtlEVCARfUP65RM/hp29/+0R7eSbhoHlnffZ8h76e6x1tyw9mxXaJ3nfTVLd89hQr9NfGceJxfLIXmONh6eNNYftNSESRmgkHlEOjmhgBbYcEW08FFQN/ro6dvAczjhgXEdQP76xHEYxM+igQq259gLrCSlwbD3iDtTMy+A4Yuk0B6zV8c+BcO2OgFIp/UvJdG4o/Rp1JQYXeZFflPEFMfvugiFGFXN587YtgX7C8lRGFXPCGGYCCzlkoxJ4xqmi/jrIcdYYh5pwxiwI/gt7lDDFrcLiMKhBJ//W78ENsJgVUsV8wKpjZBXshM6cCW0jbRAilICFxIpgGMmmiWGHSIR6ViY+DPFaqSJCbQ5mbxoZLIlU0Al/cBj6N1uXfFI0okLppi69StmumSFQRP6oIKDedFi3vRDn3j6KozCZlu0DdJb3AupJXNLmqkk9+X9FEHLt1Jq8oi1H5n01AtRlvwQZQl9hmtPY4JEjMDs5ftWJN4Xr4lLrV2OHiUDHCPgvA/Tn/hP4zGUBfjZ3eLJ+NIOfHxi8CMoAQtYfmw93v01O0e7VlqqcCsXML3Vsu94cxnb4c7ML5chG8JIP9b38dENGaj3+x+TpiA/AL/fen8In7H8l3ZjdJQt2TAAAAAElFTkSuQmCC">`
    $showBtn.innerHTML = `
    <img style="
      padding-top: 4px;
      width: 24px;
      display: inline-block;
      cursor: pointer;
    " src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIBAMAAABfdrOtAAAAElBMVEUAAAD///8+Uq06AAAABXRSTlMA2kCAv5tF5NoAAAErSURBVHja7dzNasJAFIbhz8Tu7R0Eq/vQNHuxzL6YnPu/ldYpAUckxJ8zSnjfdTIPzHrOUawJdqmDJre1S/X7avigbM08kMgMSmt+iPWKbcwTsb3+KswXseOFLb2RnaTgjXTxtpwRq7XMgWz9kZ8cSKcwE6SX+SMGAgICAvJCyHdz2ud0pEx+/BpFaj2kEgQEBAQEBAQEBOT1kXWSkhbvk1vptOLs1LEWNrmVRgIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBeTayTqpufogxduqM3q2AgICAgICAgICA3IOko4ZXkB/pqOHzhyZBQEBAQLIieVahtDNBDnrLgZT+yC4HUkmtN9JnWUiVZbVWliVhseCJdPqvCH5IV2tQNl4r6Bod+wWq9eeDik+xFQAAAABJRU5ErkJggg==">`

    // 十倍速播放
    function _tenRatePlay() {
      let playbackRate = 10
      if ($tenRate.innerHTML === '十倍速捕获') {
        $tenRate.innerHTML = '恢复正常播放'
      } else {
        playbackRate = 1
        $tenRate.innerHTML = '十倍速捕获'
      }

      let $domList = document.getElementsByTagName('video')
      for (let i = 0, length = $domList.length; i < length; i++) {
        const $dom = $domList[i]
        $dom.playbackRate = playbackRate
      }
    }

    // 获取顶部 window title,因可能存在跨域问题,故使用 try catch 进行保护
    function getDocumentTitle() {
      let title = document.title;
      try {
        title = window.top.document.title
      } catch (error) {
        console.log(error)
      }
      return title
    }

    // 流式下载
    function _streamDownload() {
      var _hmt = _hmt || [];
      (function () {
        var hm = document.createElement("script");
        hm.src = "https://hm.baidu.com/hm.js?1f12b0865d866ae1b93514870d93ce89";
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(hm, s);
      })();

      // 对应状态未下载结束的媒体轨道
      const remainSourceBufferList = []
      _sourceBufferList.forEach((target) => {
        // 对应的 MSE 状态为已下载完成状态
        if (target.MSEInstance.readyState === 'ended') {
          target.streamWriter.close()
        } else {
          remainSourceBufferList.push(target)
        }
      })
      // 流式下载,释放已下载完成的媒体轨道,回收内存
      _sourceBufferList = remainSourceBufferList
    }

    // 普通下载
    function _download() {
      var _hmt = _hmt || [];
      (function () {
        var hm = document.createElement("script");
        hm.src = "https://hm.baidu.com/hm.js?1f12b0865d866ae1b93514870d93ce89";
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(hm, s);
      })();

      _sourceBufferList.forEach((target) => {
        const mime = target.mime.split(';')[0]
        const type = mime.split('/')[1]
        const fileBlob = new Blob(target.bufferList, { type: mime }) // 创建一个Blob对象,并设置文件的 MIME 类型
        const a = document.createElement('a')
        a.download = `${getDocumentTitle()}.${type}`
        a.href = URL.createObjectURL(fileBlob)
        a.style.display = 'none'
        document.body.appendChild(a)
        // 禁止 click 事件冒泡,避免全局拦截
        a.onclick = function (e) {
          e.stopPropagation();
        }
        a.click()
        a.remove()
      })
    }

    // 监听资源全部录取成功
    let _endOfStream = window.MediaSource.prototype.endOfStream
    window.MediaSource.prototype.endOfStream = function () {
      if (isStreamDownload) {
        alert('资源全部捕获成功,即将下载!')
        setTimeout(_streamDownload) // 等待 MediaSource 状态变更
        _endOfStream.call(this)
        return
      }

      if (confirm('资源全部捕获成功,即将下载!') == true) {
        _download()
      } else {
        // 不下载资源
      }
      _endOfStream.call(this)
    }

    // 录取资源
    let _addSourceBuffer = window.MediaSource.prototype.addSourceBuffer
    window.MediaSource.prototype.addSourceBuffer = function (mime) {
      _appendDom()

      let sourceBuffer = _addSourceBuffer.call(this, mime)
      let _append = sourceBuffer.appendBuffer
      let bufferList = []
      const _sourceBuffer = {
        mime,
        bufferList,
        MSEInstance: this,
      }

      // 如果 streamSaver 已提前加载完成,则初始化对应的 streamWriter
      try {
        if (window.streamSaver) {
          const type = mime.split(';')[0].split('/')[1]
          _sourceBuffer.streamWriter = streamSaver.createWriteStream(`${getDocumentTitle()}.${type}`).getWriter()
        }
      } catch (error) {
        console.error(error)
      }

      _sourceBufferList.push(_sourceBuffer)
      sourceBuffer.appendBuffer = function (buffer) {
        sumFragment++
        $downloadNum.innerHTML = `已捕获 ${sumFragment} 个片段`

        if (isStreamDownload && _sourceBuffer.streamWriter) { // 流式下载
          _sourceBuffer.streamWriter.write(new Uint8Array(buffer));
        } else { // 普通 blob 下载
          bufferList.push(buffer)
        }
        _append.call(this, buffer)
      }
      return sourceBuffer
    }
    window.MediaSource.prototype.addSourceBuffer.toString = function () {
      return 'function addSourceBuffer() { [native code] }'
    }

    // 添加操作的 dom
    function _appendDom() {
      if (document.getElementById('media-source-extract')) {
        return
      }
      $container.style = `
      position: fixed;
      top: 50px;
      right: 50px;
      text-align: right;
      z-index: 9999;
      `
      const baseStyle = `
      float:right;
      clear:both;
      margin-top: 10px;
      padding: 0 20px;
      color: white;
      cursor: pointer;
      font-size: 16px;
      font-weight: bold;
      line-height: 40px;
      text-align: center;
      border-radius: 4px;
      background-color: #3498db;
      box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.3);
    `
      $tenRate.innerHTML = '十倍速捕获'
      $downloadNum.innerHTML = '已捕获 0 个片段'
      $btnStreamDownload.innerHTML = '特大视频下载,边下载边保存'
      $btnDownload.innerHTML = '下载已捕获片段'
      $btnDownload.id = 'media-source-extract'
      $tenRate.style = baseStyle
      $downloadNum.style = baseStyle
      $btnDownload.style = baseStyle
      $btnStreamDownload.style = baseStyle
      $btnStreamDownload.style.display = 'none'
      $showBtn.style = `
      float:right;
      clear:both;
      display: none;
      margin-top: 4px;
      height: 34px;
      width: 34px;
      line-height: 34px;
      text-align: center;
      border-radius: 4px;
      background-color: rgba(0, 0, 0, 0.5);
      `
      $closeBtn.style = `
      float:right;
      clear:both;
      margin-top: 10px;
      height: 34px;
      width: 34px;
      line-height: 34px;
      text-align: center;
      display: inline-block;
      border-radius: 50%;
      background-color: rgba(0, 0, 0, 0.5);
      `

      $btnDownload.addEventListener('click', _download)
      $tenRate.addEventListener('click', _tenRatePlay)

      // 关闭控制面板
      $closeBtn.addEventListener('click', function () {
        $downloadNum.style.display = 'none'
        $btnStreamDownload.style.display = 'none'
        $btnDownload.style.display = 'none'
        $closeBtn.style.display = 'none'
        $tenRate.style.display = 'none'
        $showBtn.style.display = 'inline-block'
        isClose = true
      })

      // 显示控制面板
      $showBtn.addEventListener('click', function () {
        if (!isStreamDownload) {
          $btnDownload.style.display = 'inline-block'
          $btnStreamDownload.style.display = 'inline-block'
        }
        $downloadNum.style.display = 'inline-block'
        $closeBtn.style.display = 'inline-block'
        $tenRate.style.display = 'inline-block'
        $showBtn.style.display = 'none'
        isClose = false
      })

      // 启动流式下载
      $btnStreamDownload.addEventListener('click', function () {
        (function () {
          var hm = document.createElement("script");
          hm.src = "https://hm.baidu.com/hm.js?1f12b0865d866ae1b93514870d93ce89";
          var s = document.getElementsByTagName("script")[0];
          s.parentNode.insertBefore(hm, s);
        })();
        isStreamDownload = true
        $btnDownload.style.display = 'none'
        $btnStreamDownload.style.display = 'none'
        _sourceBufferList.forEach(sourceBuffer => {
          if (!sourceBuffer.streamWriter) {
            const type = sourceBuffer.mime.split(';')[0].split('/')[1]
            sourceBuffer.streamWriter = streamSaver.createWriteStream(`${getDocumentTitle()}.${type}`).getWriter()
            sourceBuffer.bufferList.forEach(buffer => {
              sourceBuffer.streamWriter.write(new Uint8Array(buffer));
            })
            sourceBuffer.bufferList = []
          }
        })
      })

      document.getElementsByTagName('html')[0].insertBefore($container, document.getElementsByTagName('head')[0]);
      $container.appendChild($btnStreamDownload)
      $container.appendChild($downloadNum)
      $container.appendChild($btnDownload)
      $container.appendChild($tenRate)
      $container.appendChild($closeBtn)
      $container.appendChild($showBtn)

      // 加载 stream 流式下载器
      try {
        let $streamSaver = document.createElement('script')
        $streamSaver.src = 'https://upyun.luckly-mjw.cn/lib/stream-saver.js'
        document.body.appendChild($streamSaver);
        $streamSaver.addEventListener('load', () => {
          $btnStreamDownload.style.display = 'inline-block'
        })
      } catch (error) {
        console.error(error)
      }
    }
  })()
})();

油猴插件,点击自动安装

  • 检测到符合条件的视频资源,自动注入代码。
  • 之后再也不需要自己注入代码啦,降低使用成本。
  • 可能有 Bug,但可以试试。如果使用中有问题,在 github 中提 issues 给我呗。 我们一起完善它。
  • 插件源码: https://github.com/Momo707577...
  • 如果没成功检测到,咱们就用回老方法试试。再给我提个 bug。
  • 手动添加油猴插件步骤

    • 点击 tamper-monkey「油猴」icon,点击「添加新脚本」

    • 在当前位置,粘贴上述链接中的源码

    • 点击「文本」,「保存」

    • 得到如下结果,即为添加成功

背景

  • 之前笔者实现了m3u8 视频在线提取工具,可对 m3u8 视频进行提取,合并,下载。实现整个视频下载流程。
  • 后续还实现了非定制性的 ASE 解密功能(不提供定制性服务,定制性解密,属于破解,侵权行为,需尊重知识产权)
  • 但上述工具仍存在一定的通用性问题。为彻底解决通用性,实现无差别视频提取,开发了这个工具。

特点

  • 优点,通用性强,无差别提取,只要使用到 MES 主流媒体播放技术的视频,均可捕获。
  • 优点,足够简单,在视频播放的最后一个步骤进行拦截,规避视频加载,加密,解密等复杂过程。
  • 缺点,被动,无法主动干预视频加载,只可被动捕获视频资源。
  • 缺点,有一定门槛,依赖 chrome 浏览器开发者模式,无法实现全自动化,有一定使用门槛。

使用示例链接

功能说明

  • 【已捕获 0 个片段】

    • 显示程序已捕获的视频片段数。
  • 【下载已捕获片段】

    • 可以强制下载已经捕获的片段,无需等待整个视频全部捕获完成。
  • 【十倍速捕获】

    • 由于视频捕获是依赖视频加载进度的。
    • 点击该按钮,可以十倍速播放,加速视频加载,加速视频捕获。
  • 当视频全部加载完成,将触发自动下载。

    • 若无触发,可手动点击「下载已捕获片段」按钮,对捕获到的视频进行下载。

使用方式

示例实验链接

  • 复制工具代码

    • 可以直接复制本文中的核心源码
    • 也可以点开示例实验链接,点击按钮,快速复制工具代码。

  • 打开目前页面的控制台

  • ctrl + f ,输入 <iframe,判断是否存在 iframe 内嵌页面。若存在 iframe,请看完本说明,再继续查看下一节「iframe 解决方案」。若无,则下一步

  • 打开代码调试面板

  • 在调试面板中,找到当前页面的代码

    • 注意文件的寻找方法,需根据 URL 中的路径层级寻找。
    • 点击下方按钮,对代码进行排版。

  • 搜索,找到第一个 <script 标签,并设置多个断点

    • 搜索,如果第一个 <script 标签是一个链接。

    • 则找到对应文件,设置断点。

  • 刷新页面,出现如下状态,则证明断点设置成功

    • 若页面白屏,为正常现象,按照步骤继续执行即可。

  • 在 console 栏,粘贴工具代码,回车

  • 回到 source 栏,点击按钮,恢复运行

  • 若页面出现这几个按钮,则证明注入成功,工具运行成功

  • 正常观看视频,等待视频捕获

    • 可点击「十倍速捕获」,接口视频播放速度,加快视频捕获速度。
  • 若页面出现如下弹窗,即捕获完成,视频自动下载(也可以点击「下载已捕获片段」,手动下载)

  • 视频下载完成,得到「音频」文件,「视频」文件

    • 可使用专属播放器,进行播放。
    • 也可以使用其他工具,进行合并。

iframe 解决方案

示例实验链接

  • 找到 iframe 标签,复制 src 中的 url,新建页面打开该 url。

    • 如果该新建页面能正常播放视频,则在该新建页面,使用上述「使用说明」即可。

  • 如果新建页面没有正常播放页面,则回到原页面,换一种方式实现。
  • 回到原页面,找到 iframe 内嵌页面的源码。

    • 同样搜索 <script,但这一次,要找带 src 的 script 标签

  • 找到该 src 对应的文件,并打断点

  • 刷新页面,并在源文件中,插入代码

    • 注意,打断点和插入代码是在不同的栏,打断点的栏中,有「:format」标识。插入代码的栏,没有该标识。

  • 粘贴代码,ctrl + s 进行保存

  • 恢复执行(操作方式,查看上一节「使用说明」)

  • 完成代码插入,捕获视频

特别说明

  • 在代码操作过程中,页面白屏是正常的,按照步骤继续执行即可。
  • 如果不行,安装使用说明,多试几遍就可以了。可能是视频广告导致。
  • 注意 Chrome 的多文件下载询问,如果拒绝过,需要重新打开。
  • 视频捕获,分为「视频」文件与「音频」文件,「视频」文件是纯视频,没声音的。需要搭配「音频」文件播放。点击这里,使用专属播放器。

专属播放器

  • 由于采集工具是单独对「视频」和「音频」分开采集的。
  • 使用普通播放器可能无法正常播放。
  • 可利用本工具同时加载「视频」和「音频」同步播放。
  • 本工具还附有倍速播放功能。

window 系统,音视频合成方法

  • 可使用「小丸工具箱」完成
  • 具体的方式,笔者没有实践过,有经验的朋友欢迎在评论区留言使用教程。万分感谢。
  • 特别感谢㍿⃣ 介绍的「小丸工具箱」解决方案

mac 系统,音视频合成方法

  • 安装 ffmpeg 视频编辑库
  • 先把音频「audio_mp4」进行转码

    • 命令行执行 ffmpeg -i "***-audio_mp4;codecs=***.mp4" -acodec copy "audio.aac"
  • 原始视频「video_mp4」和上一步得到的 aac 「audio.aac」组装到一起

    • 命令行执行 ffmpeg -i "***-video_mp4;codecs=***.mp4" -i "audio.aac" -c copy -shortest "result.mp4"
  • 得到的「result.mp4」就是音视频合成成功的视频
  • 特别感谢journey-ad 介绍的 ffmpeg 合成教程。

原理

  • 主流视频媒体播放技术,均使用到 MES 技术
  • MES 技术播放流程一般如下:

    • 创建 video 播放器标签。
    • 拉取视频片段。
    • 解密视频片段(如果对视频进行了加密操作)
    • 解析视频片段,分为「视频轨」「音频轨」。
    • 将每个片段的「视频轨」「音频轨」,"喂给" video 标签进行播放。
    • 当已加载的视频片段快要播完时,重复第二个步骤,拉取新的视频片段,进行投喂。

  • 本工具的核心逻辑

    • 覆写视频片段的"投喂"操作。
    • 插入自定义代码,收集"投喂"的「视频」「音频」资源,进行下载。

 核心源码

(function () {

  let _sourceBufferList = []
  let $btnDownload = document.createElement('div')
  let $downloadNum = document.createElement('div')
  let $tenRate = document.createElement('div') // 十倍速播放

  // 十倍速播放
  function _tenRatePlay () {
    let $domList = document.getElementsByTagName('video')
    for (let i = 0, length = $domList.length; i < length; i++) {
      const $dom = $domList[i]
      $dom.playbackRate = 10
    }
  }

  // 下载捕获到的资源
  function _download () {
    _sourceBufferList.forEach((target) => {
      const mime = target.mime.split(';')[0]
      const type = mime.split('/')[1]
      const fileBlob = new Blob(target.bufferList, { type: mime }) // 创建一个Blob对象,并设置文件的 MIME 类型
      const a = document.createElement('a')
      a.download = `${document.title}.${type}`
      a.href = URL.createObjectURL(fileBlob)
      a.style.display = 'none'
      document.body.appendChild(a)
      a.click()
      a.remove()
    })
  }

  // 监听资源全部录取成功
  let _endOfStream = window.MediaSource.prototype.endOfStream
  window.MediaSource.prototype.endOfStream = function () {
    alert('资源全部捕获成功,即将下载!')
    _download()
    _endOfStream.call(this)
  }

  // 捕获资源
  let _addSourceBuffer = window.MediaSource.prototype.addSourceBuffer
  window.MediaSource.prototype.addSourceBuffer = function (mime) {
    console.log(mime)
    let sourceBuffer = _addSourceBuffer.call(this, mime)
    let _append = sourceBuffer.appendBuffer
    let bufferList = []
    _sourceBufferList.push({
      mime,
      bufferList,
    })
    sourceBuffer.appendBuffer = function (buffer) {
      $downloadNum.innerHTML = `已捕获 ${_sourceBufferList[0].bufferList.length} 个片段`
      bufferList.push(buffer)
      _append.call(this, buffer)
    }
    return sourceBuffer
  }

  // 添加操作的 dom
  function _appendDom () {
    const baseStyle = `
      position: fixed;
      top: 50px;
      right: 50px;
      height: 40px;
      padding: 0 20px;
      z-index: 9999;
      color: white;
      cursor: pointer;
      font-size: 16px;
      font-weight: bold;
      line-height: 40px;
      text-align: center;
      border-radius: 4px;
      background-color: #3498db;
      box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.3);
    `
    $tenRate.innerHTML = '十倍速捕获'
    $downloadNum.innerHTML = '已捕获 0 个片段'
    $btnDownload.innerHTML = '下载已捕获片段'
    $tenRate.style = baseStyle + `top: 150px;`
    $btnDownload.style = baseStyle + `top: 100px;`
    $downloadNum.style = baseStyle
    $btnDownload.addEventListener('click', _download)
    $tenRate.addEventListener('click', _tenRatePlay)
    document.getElementsByTagName('html')[0].insertBefore($tenRate, document.getElementsByTagName('head')[0]);
    document.getElementsByTagName('html')[0].insertBefore($downloadNum, document.getElementsByTagName('head')[0]);
    document.getElementsByTagName('html')[0].insertBefore($btnDownload, document.getElementsByTagName('head')[0]);
  }

  _appendDom()
})()

项目源码

声明

  • 本项目仅用于学习,交流,切勿用于侵权行为。

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ACL综合实验

拓扑结构&#xff1a; 要求 1、PC1可以Telnet R1&#xff0c;但是不能pingR1 2、PC1可以ping R2&#xff0c;但是不能Telnet R2 3、PC2的所有要求与PC1相反 使用的设备&#xff1a;4台路由器、1台交换机 解决网络拓扑&#xff1a; 1、确定广播域的个数 2、分配网段 3、配置…

【2023 · CANN训练营第一季】:AscendCL应用开发深入讲解 基础知识介绍

昇腾&#xff08;Ascend&#xff09;CANN&#xff08;Compute Architecture for Neural Networks&#xff09;是华为推出的一款面向AI处理器的软件开发工具包&#xff0c;用于支持各种AI应用的开发和部署。它的深度神经网络应用开发流程可以分为以下几个主要步骤 AscendCL应用…

TS WIKI 个人知识库软件

TS WIKI 个人知识库软件(VER: 0.1) TS WIKI 目标是做一个可以本地化部署&#xff0c;小型的&#xff0c;适合个人或小型团队的知识管理软件。 T(iny) S(mall) WIKI 软件界面 TS WIKI 功能说明 1、简化的软件依赖和安装 依赖的软件最简化。软件只使用 SQLITE 数据库&#xf…

【Java闭关修炼】SpringMVC-HttpMeaasgeConverter

【Java闭关修炼】SpringMVC-HttpMeaasgeConverter概述RequestBodyRequestEntity使用原生servlet响应浏览器ResponseBody概述 浏览器发送到服务器&#xff0c;将请求报文转换为java对象 服务器响应浏览器&#xff0c;将java对象转换成响应报文 RequestBody 将请求体中的请求报…

Flink系列-6、Flink DataSet的Transformation

版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。 大数据系列文章目录 官方网址&#xff1a;https://flink.apache.org/ 学习资料&#xff1a;https://flink-learning.org.cn/ 目录Flink 算子Ma…

C生万物 | 火眼辨析指针数组与数组指针

本文我们来讲讲C语言中的易混淆的指针数组与数组指针✒ 文章目录 一、指针数组1、概念明细2、数组地址偏移量与指针偏移量3、指针变量与数组名的置换【✔】4、实例讲解① 指针数组存放地址② 指针数组存放数组 二、数组指针1、数组指针的定义2、&数组名VS数组名3、数组指针…

VL822- GEN2 10Gbps简述及运用(USB3.1 HUB芯片)

VL822是一颗USB3.1 GEN2&#xff08;10Gbps&#xff09;的HUB芯片&#xff0c;有三种封装分别是QFN88(10x10x0.85 mm);QFN76&#xff08;9x9x0.85 mm &#xff09;;QFN56(7x7x0.85 mm)。这三种封装在USB数据协议上都是一样&#xff0c;但各个封装都有自己的实际应用特点。 VL8…

ODrive运放电路的分析和替代方案

SimpleFOC、ODrive和VESC教程链接汇总&#xff1a;请点击   一、电流采样范围的计算 这是一个典型的Lowside电流采样运放电路&#xff0c;下图&#xff1a; 实际运用中会增加阻容做滤波处理。&#xff08;SP1-SN1&#xff09;就是电流在R5采样电阻上产生的压降&#xff0c…

模型融合和预测结果融合

模型融合和预测结果融合 文章目录模型融合和预测结果融合1. 模型融合提升技术1. Bagging 方法和随机森林2. Boosting 方法2. 预测结果融合策略1. Voting2. 软投票代码示例&#xff1a;3. Averaging 和 Ranking4. Blending5. Stacking3. 其他提升方法1. 模型融合提升技术 模型融…

一个Java线程的线生(线生 vs 人生)

java线程的使用 1. Java多线程概述 下面我们看下Java的多线程 1.1 java天生就是多线程的 一个Java程序从main()方法开始执行&#xff0c;然后按照既定的代码逻辑执行&#xff0c;看似没有其他线程参与&#xff0c;但实际上Java程序天生就是多线程程序&#xff0c;因为执行main…

设计模式 -- 建造者模式

前言 月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂) 央是一片海洋,海乃百川,代表着一块海绵(吸纳万物) 泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出) 月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容 希望大家一起坚持这个过程,也同…

WPF教程(四)--Dispatcher

一、Dispatcher介绍 微软在WPF引入了Dispatcher&#xff0c;那么这个Dispatcher的主要作用是什么呢&#xff1f; 不管是WinForm应用程序还是WPF应用程序&#xff0c;实际上都是一个进程&#xff0c;一个进程可以包含多个线程&#xff0c;其中有一个是主线程&#xff0c;其余的是…

Embodied AI 具身智能

大模型的时代的到来&#xff0c;现在的大模型的参数几乎是几何级数的上升。 谷歌和柏林工业大学的团队重磅推出了史上最大视觉语言模型——PaLM-E&#xff1a;An Embodied Multimodal Language Model。通才大模型PaLM-E&#xff0c;什么是通才模型&#xff0c;就是多任务统一学…

NeRF必读:NeuS--三维重建的milestone以及脑补的作者脑回路

前言 NeRF从2020年发展至今&#xff0c;仅仅三年时间&#xff0c;而Follow的工作已呈井喷之势&#xff0c;相信在不久的将来&#xff0c;NeRF会一举重塑三维重建这个业界&#xff0c;甚至重建我们的四维世界&#xff08;开头先吹一波&#xff09;。NeRF的发展时间虽短&#xf…

C++入门(前篇)

&#x1f525;&#x1f525;本章重内容 C入门 1.命名空间2. C输入&输出3. 缺省参数 简单的说一下C语言的出现是为了弥补C语言的不足 由于要补充的东西太多&#xff0c;所以就在C语言的基础上又出了C 所以我认为学习C的前提是你得懂C语言 C中可以使用C的大部分语法 可以这样…

Autowired注解与Resource注解的区别

两者的用法 其实这两个注解的作用都一样,都是在做bean的注入,在使用过程中,两个注解有时候可以替换使用 两者的共同点 Resource注解和Autowired注解都可以用作bean的注入.在接口只有一个实现类的时候,两个注解可以互相替换,效果相同. 两者的不同点 Resource注解是Java自身的…

技术分享 | OceanBase 手滑误删了数据文件怎么办

作者&#xff1a;张乾 外星人2号&#xff0c;现兼任六位喵星人的资深铲屎官。 本文来源&#xff1a;原创投稿 *爱可生开源社区出品&#xff0c;原创内容未经授权不得随意使用&#xff0c;转载请联系小编并注明来源。 手滑误删了数据文件&#xff0c;并且没有可替换的节点时&…

代码随想录第19天 | 235. 二叉搜索树的最近公共祖先 701.二叉搜索树中的插入操作 450.删除二叉搜索树中的节点

235. 二叉搜索树的最近公共祖先 var lowestCommonAncestor function(root, p, q) {// 使用递归的方法// 1. 使用给定的递归函数lowestCommonAncestor// 2. 确定递归终止条件if(root null) {return root;}if(root.val > p.val && root.val > q.val) {// 向左子…

set、map容器

一、set 1. set基本概念 简介: 所有元素都会在插入时自动被排序 本质: set/multiset属于关联式容器&#xff0c;底层结构是用二叉树实现。 set和multiset区别: set不允许容器中有重复的元素 multiset允许容器中有重复的元素 2. set构造和赋值 构造: set<T> st; …

安装WMware16、centos7记录

将一台闲置电脑安装虚拟机&#xff0c;计划给个8G内存&#xff0c;80G硬盘&#xff0c;打算安装WMware16&#xff0c;对系统要求是win10 一、将win7升级到win10 1.1、正版的win10安装U盘制作教程 https://www.bilibili.com/video/BV1AW411G7Lq/?vd_sourcecaf04463d06774efd…