node.jsでダウンローダーを作りたかったのですが...
Q&A
Closed
解決したいこと
ひとつ、ひとつの関数の実行は可能なのに、まとめて実行するとエラーが出てしまいます。
解決方法をご教授いただけますと幸いです。
作りたいもの(仕様)
- node.js(v16.3.0)を活用してダウンローダーを作ろうとしています。
- ダウンロード対象のファイルのURLを記載したリストをテキストファイル
.txt
で作成します(以下、ダウンロードリストDL_url_list.txt
) - ダウンロードリストは、URLを1行ずつ、改行で記載していく仕様とします
ダウンロードリスト
https://i.picsum.photos/id/866/200/300.jpg?hmac=rcadCENKh4rD6MAp6V_ma-AyWv641M4iiOpe1RyFHeI
https://i.picsum.photos/id/107/200/300.jpg?grayscale&hmac=rlcVQxKrk3gxxjGVf4l4N-jX85wldhSIGczV9ZfeAL0
https://i.picsum.photos/id/237/200/300.jpg?hmac=TmmQSbShHz9CdQm0NkEjx1Dyh_Y984R9LpNrpvH2D_U
- 実行ファイルは
app.js
です - 実行ファイルとダウンロードリストは、同じ階層にあります
-
app.js
を実行すると、同階層に任意のディレクトリが作成されます(DL_dir
)、それ以下のディレクトリ構造は、URLの構造に従うものとします。
URLが「https://i.picsum.photos/id/866/200/300.jpg」の場合
【ローカル構造】
app.js
DL_url_list.txt
DL_dir
└ id
└ 866
└ 200
└ 300.jpg
実行ファイル
// モジュールの読み込み
const https = require("https");
const fs = require("fs");
const url = require("url");
const path = require("path");
// 設定1:ダウンロードするURLのリスト(.txt)を指定
const UrlList = fs.readFileSync("./DL_url_list.txt", "utf-8").toString().split("\n");
// 設定2:ローカルのダウンロード先のディレクトリを指定
const DLBaseDir = "./DL_dir";
// ローカルのダウンロード先のディレクトリを作成
const createDir = (DirName) => {
fs.mkdir(DirName, { recursive: true }, (err) => {
if (err) console.log(err);
});
console.log("created - " + DirName);
};
// ダウンロードを実行
const fileDL = (Url, LocalPath) => {
const output = fs.createWriteStream(LocalPath);
https.get(Url, function (response) {
response.pipe(output);
response.on("end", function () {
output.close();
console.log("finished - " + Url);
});
});
};
// 以下、実行部
function download(target) {
const TargetUrl = new URL(target);
const PathName = TargetUrl.pathname;
const DirName = DLBaseDir + path.dirname(PathName);
const LocalPath = DLBaseDir + PathName;
createDir(DirName);
fileDL(TargetUrl.href, LocalPath);
}
// ダウンロードリストに対して繰り返し実行
UrlList.forEach((target) => {
download(target);
});
発生している問題・エラー
- 上記の実行ファイルを、そのまま実行すると、エラーが出力されます
- 「created - ***」と表示されていますが、実際はディレクトリは作成されていません
$ node -v
v16.3.0
$ node app.js
created - ./DL_dir/id/866/200
created - ./DL_dir/id/107/200
created - ./DL_dir/id/237/200
node:events:371
throw er; // Unhandled 'error' event
^
Error: ENOENT: no such file or directory, open './DL_dir/id/866/200/300.jpg'
Emitted 'error' event on WriteStream instance at:
at emitErrorNT (node:internal/streams/destroy:193:8)
at emitErrorCloseNT (node:internal/streams/destroy:158:3)
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: './DL_dir/id/866/200/300.jpg'
}
検証したこと
1)ダウンロード部の一時的除外
- ダウンロードの実行部
fileDL(TargetUrl.href, LocalPath);
をコメントアウトして実行しました - すると、問題なくディレクトリの作成が実行されました
// 以下、実行部
function download(target) {
const TargetUrl = new URL(target);
const PathName = TargetUrl.pathname;
const DirName = DLBaseDir + path.dirname(PathName);
const LocalPath = DLBaseDir + PathName;
createDir(DirName);
// fileDL(TargetUrl.href, LocalPath); // ← コメントアウト
}
2)ディレクトリ作成後の再実行
- ディレクトリが作成された状態で、上記のコメントアウトを元へ戻し、再実行しました
- すると、ダウンロードまで問題なく実行されました
検証からの推測
- 「ディレクトリの作成
createDir
」と「ダウンロードの実施fileDL
」の関数個々としては、実行できている -
カレントディレクトリに、ダウンロード先のディレクトリ
./DL_dir
が存在しない場合で、createDir
とfileDL
を一度に実行することでエラーが出力されることから、createDir
とfileDL
を実行するタイミングの問題なのか...と思いましたが、解決に至っていません。
お力添えいただけますと幸いです。よろしくお願いいたします。
また「こういう作り方の方がいいよ」というアドバイスなどもいただけると、大変うれしいです。