Nodejsを使用してステーションBのビデオをワンクリックでダウンロードする方法

ワンクリックでステーションBからビデオをダウンロードする方法

ステーションBのビデオを簡単にダウンロードするために、Nodejsで小さなツールを作成ibiliし、最初はこのライブラリを使用してダウンロードしましたが、ダウンロードディレクトリをカスタマイズできないという問題のため、変更するのは不便でした。 、だから私はホイールを作りました。

倉庫の住所、ウェルカムスター。

特徴

  • URLに基​​づいて個々の作品をダウンロードする
  • UPマスターのホームページURLに従って全作品をダウンロード
  • ビデオまたはオーディオをダウンロードするオプション

環境要件

このツールを使用するには、Nodeとnpmが必要です。お持ちでない場合は、公式Webサイトにアクセスしてダウンロードしてインストールできます。

使用する

インストール:

npm i bilibili-save-nodejs
复制代码

コマンドラインツールの使用

bili-download
复制代码

コマンドラインメニューに基づいて、ダウンロードする内容と方法を選択します

私的財の巻き込み:ワンクリックスターチェイス、Jiu Sanのすべてのビデオをダウンロード:

bili-download -d
复制代码

Node.jsAPIの使用

関数名 効果
download ダウンロード
downloadByVedioPath ビデオのURLに基​​づいて単一の作品をダウンロードする
downloadByHomePath UPホームページに従ってすべての作品をダウンロード

APIパラメータ

注:3つの関数のパラメーターは、オブジェクトの形式です。

ダウンロード

パラメータ名 必要ですか 範囲 意味
downloadRange はい ['byAuthor','byVedio'] 著者のホームページのURLまたは仕事のURLによると
downloadType はい ['mp4','mp3'] ビデオまたはオーディオをダウンロードする
downloadPath はい 無し 法務URLまたはUPホームページURL
downloadFolder いいえ 無し ストレージディレクトリへのフルパス。デフォルト値がデフォルトで使用されます

ディレクトリのデフォルト:

  • ビデオ:ルートディレクトリの下の/videoフォルダ内
  • オーディオ:ルートディレクトリの下の/audioフォルダ内

デモ:

const { download } = require("bilibili-download-nodejs");
download({
  downloadRange: "byAuthor",
  downloadType: "mp4",
  downloadPath: "https://space.bilibili.com/313580179",
})
  .then(() => console.log("下载成功"))
  .catch((e) => console.log("下载出错"));
复制代码

downloadByVedioPath & downloadByHomePath

参数名 是否必须 取值范围 含义
type ['mp4','mp3'] 下载视频音频
url 合法的作品 URL
folder 存储目录的完整路径

demo:

const { downloadByVedioPath, downloadByHomePath } = require("./download.js");
const path = require("path");

// 下载单个作品的视频
downloadByVedioPath({
  url: "https://www.bilibili.com/video/BV1AL4y1L7cg",
  type: "mp4",
  folder: path.join(__dirname, "/foo"),
})
  .then(() => console.log("下载成功"))
  .catch((e) => console.log("下载出错"));

// 下载UP主所有作品的音频
downloadByHomePath({
  url: "https://space.bilibili.com/313580179",
  type: "mp3",
  folder: path.join(__dirname, "/bar"),
})
  .then(() => console.log("下载成功"))
  .catch((e) => console.log("下载出错"));
复制代码

原理介绍

介绍完用法,简单介绍本项目的原理。

根据视频 URL 下载视频

根据 URL 获取 bvid

bvid 是现在 b 站视频的唯一标识,也是后续操作的必备参数。但为了方便使用,直接复制作品的 URL 更好理解和操作。

其实 bvid 就存在于 URL 之中,只需要做简单的字符串操作:

const urlList = url.split("/");
const bvid = urlList[urlList.length - 1].split("?")[0];
复制代码

根据 bvid 获取 cid 数组与作品标题

对于多 p 视频,仅通过 bvid 无法确定请求的是哪一 p 视频,此时 cid 起到了唯一标识视频的作用。通过浏览器抓包分析接口,可知获取 cid 的方法为:

const getCidByBvid = async (bvid) => {
  const res = await axios.get("https://api.bilibili.com/x/web-interface/view", {
    params: {
      bvid,
    },
  });
  return res.data.data.pages.map((item) => item.cid);
};
复制代码

该接口用于查询作品信息,因此获取作品标题的方法为:

const getTitleByBvid = async (bvid) => {
  const res = await axios.get("https://api.bilibili.com/x/web-interface/view", {
    params: {
      bvid,
    },
  });
  return res.data.data.title;
};
复制代码

根据 bvid 获取视频下载地址数组

  1. 首先,根据 bvid 获取 cid 数组
  2. 对于每个 cid,与 bvid 一起唯一标识了视频,进行请求
  3. 根据下载类型的不同(视频或音频),传入参数会不同。

参数含义:

  • fnval设为 16 时,音视频将会分离,此时可以达到只下载音频的目的
  • qn参数标识清晰度,对照如下
清晰度 字段取值
4K 120
1080p+ 112
1080p 80
720p 64
480p 32
360p 16

完整实现代码为:

const getDownloadPathById = async (bvid, type) => {
  const cidList = await getCidByBvid(bvid);
  const result = [];
  for (const cid of cidList) {
    const params = {
      bvid,
      cid,
      qn: 112,
    };
    if (type === "mp3") {
      params.fnval = 16;
    }
    const res = await axios.get("https://api.bilibili.com/x/player/playurl", {
      params,
    });
    result.push(
      type === "mp3"
        ? res.data.data.dash.audio[0].baseUrl
        : res.data.data.durl[0].url
    );
  }
  return result;
};
复制代码

根据下载地址下载资源

getDownloadPathById返回的是下载地址,但直接在浏览器打开会报错,这是因为 request header 必须带有 referer 字段。

通过抓包可知, referer 字段取值就是视频地址,因此:

const getRefererByBvid = (bvid) => `https://www.bilibili.com/video/${bvid}`;
复制代码

下载资源的思路是:

  • 检查目标文件是否存在,若存在不重复下载
  • 根据 bvid 获取 referer 字段
  • 请求资源
  • 写入文件

完整实现:

const downloadResource = async ({ url, referer, folder, title, type }) => {
  const target = path.join(folder, `${title}.${type}`);
  if (fs.existsSync(target)) {
    console.log(`视频 ${title} 已存在`);
    return Promise.resolve();
  }
  const res = await axios.get(url, {
    headers: {
      referer,
    },
    responseType: "stream",
  });
  console.log(`开始下载:${title}.${type}`);
  const writer = fs.createWriteStream(target);
  res.data.pipe(writer);
  return new Promise((resolve, reject) => {
    writer.on("finish", resolve);
    writer.on("error", reject);
  });
};
复制代码

UPホームページのURLに従ってビデオをダウンロードする

UPホームページのURLから中途半端に

midは、各Bステーションユーザーの一意の識別子です。また、理解と使用の便宜のために、公開されたインターフェイスはUPホームページのURLを使用し、文字列処理を実行してmidを取得します。

const getMidByUrl = (url) => {
  const reg = /space.bilibili.com\/(?<mid>\d+)/;
  return url.match(reg).groups?.mid;
};
复制代码

アップメインミッドに従ってビデオホームページアドレスを取得します

パケットキャプチャによると、ホームページ情報を取得するには3つのパラメータが必要です。

  • mid:アカウントID
  • ps:ページあたりの動画数
  • pn:現在のページ番号

1ページあたりのデフォルト数である30を使用すると、ホームページを取得する操作は次のように記述できます。

const getHomeUrl = (mid, currentPage) =>
  `https://api.bilibili.com/x/space/arc/search?mid=${mid}&ps=30&pn=${currentPage}`;
复制代码

返されたデータはパケットをキャプチャすることによって分析され、返された結果はdata.list.vlistbvidを取得できるビデオ情報であり、その後のダウンロードプロセスは上記と同じです。

参照する

おすすめ

転載: juejin.im/post/7087973085097230349