ワンクリックでステーション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 获取视频下载地址数组
- 首先,根据 bvid 获取 cid 数组
- 对于每个 cid,与 bvid 一起唯一标识了视频,进行请求
- 根据下载类型的不同(视频或音频),传入参数会不同。
参数含义:
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.vlist
bvidを取得できるビデオ情報であり、その後のダウンロードプロセスは上記と同じです。