サイトのクロールに今まで使っているのがnode.jsのrequest。非同期処理の書き方がなれないのでsync-requestを使ったり。sync-requestは同期処理っぽくかけるのでかんたんにリクエスト処理がかける。ただ、連続処理をするとメモリを大量に使って止まる。なので、requestをasync awitを使って同期処理っぽくかいている。
最近になってnode-fetchがいいという意見を見たいので試しにnode-fetchを使ってみて詰まったところを書いておく。
npmでnode-fetchをインストールして、下のnode-fetchのサンプルコードを貼り付けて実行したらエラー。awaitがなんたらのえらー。
const fetch = require('node-fetch');
const response = await fetch('https://github.com/');
const body = await response.text();
console.log(body);
非同期処理のために、関数化すると動いた。ついでにトライキャッチエラーも追加した。
(async () => {
try {
const response = await fetch('https://github.com/');
const json = await response.json();
console.log(json);
} catch (error) {
console.log(error);
}
})();
タイムアウト処理
requestのときはoptionにタイムアウト処理を入れれば、タイムアウトが実行できた。node-fetchではAbortController()を使うようである。ただ、node.jsのv15以降に追加された、AbortController()を使ってみたが動かなかった。どうやら、npmのabort-controllerを使うようだ。入れてもだめだった。
abort-controllerを使うにはnode.jsのバージョンが6, 8, 9, 10, 11, 12, 13.である必要があるみたい。もう少しわかりやすいところにかいていてくれれば、悩まずにすんだのだが。英語のエラー文面は流し読みしてしまう傾向がある。
Supported releases of Node.js are the latest release of 6, 8, 9, 10, 11, 12, 13.
サンプルコードはこれ。
Request cancellation with AbortSignal
You may cancel requests with AbortController. A suggested implementation is abort-controller.An example of timing out a request after 150ms could be achieved as the following:
const fetch = require('node-fetch');
const AbortController = require('abort-controller');const controller = new AbortController();
const timeout = setTimeout(() => {
controller.abort();
}, 150);try {
const response = await fetch('https://example.com', {signal: controller.signal});
const data = await response.json();
} catch (error) {
if (error instanceof fetch.AbortError) {
console.log('request was aborted');
}
} finally {
clearTimeout(timeout);
}
オプションにタイムアウトを追加すると、タイムアウトエラーに持っていけるようだ。
var options = {
timeout: 1500
};
fetch('https://github.com/',options);
node-fetchで abort-controllerを利用せずにタイムアウトすると、いつまで立っても処理が終わらないようだ。
process.exit(0); で無理やり終わらせるのも手かな。
また、エラーで止まった場合にretryをどのように書くかというのも考えもの。
で、エラーを出さなかったらループを抜けるとかいた。
loop2: for (let step = 0; step < 5; step++) {
try {
await requestPromise(options);
break loop2;
} catch (error) {
console.log(error);
}
}