Closed ganyariya closed 5 years ago
ここで、複数のlinksをPromise.allで待っている際に、上記のエラーが発生すると、永遠に時間が経っても、要求が帰ってこないため、ここで止まってしまいます。
Promise.all
は指定した処理の中のどれか1つでも失敗するとcatch
の方に流れてしまうので、要求が返ってこないというより、どこかにすっ飛んで行ってしまっているのではないかと思います。
以下のようにtry
~catch
で囲めばおそらく処理は継続できると思います。
try {
await Promise.all(links.map(scrape)));
console.log("linksすべてのスクレピングが終わるまでここは実行されない");
} catch (e) {
// エラー処理
}
ただ、これだといくつか指定したスクレイピングの内、1つでも失敗したものがあると他の成功したスクレイピング結果を取得できません。
そこで、Promise.all
ではなくPromise.allSettled
を使用してみてはどうでしょうか。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled https://blog.jxck.io/entries/2019-08-20/promise-allsettled-any.html#allsettled
なお、エラーログを見るとElectron環境で実行しているようですが、ElectronのベースとなっているChromiumのJavaScriptエンジンがPromise.allSettled
を実装しているかどうか分かりません(たぶん対応していると思いますが)。
もし、対応していない場合でもnpmモジュールのpromise.allSettledをインストールすれば使用できます。
以下のスクリプトを実行してok
と共にresult
に各スクレイピング結果が入っているのを確認できました。
const allSettled = require('promise.allsettled');
const client = require('cheerio-httpcli');
(async () => {
// タイムアウトするまで時間がかかるようならここで調整(ミリ秒)
client.set('timeout', 10000);
try {
const result = await allSettled([
client.fetch('https://www.yahoo.co.jp/'), // 成功
client.fetch('http://localhost:5000/'), // 自前で立てたダミーサーバー(タイムアウトさせる)
client.fetch('https://www.yahoo.co.jo/') // 存在しないドメイン
]);
console.log('ok', result);
} catch (e) {
console.log('error', e);
}
console.log('done');
})();
というような形で目的は達成できるかと思いますがどうでしょうか。
ありがとうございます! Promise.allSettledを追加し、 client.set(timeout)(指定時間建ったら、TLEとしてスクレイピング用フェッチをやめる) 処理を追加することで動かすことが出来ました、ありがとうございます!
背景
現在スクレピングを非同期で行っており、可能であれば 複数のURLを同時にスクレイピングー>全部終わるまで待つー>全部終わったらまた複数のURLを同時にスクレピング の繰り返しを行いたいと考えています。
つまり、最初
link1
,link2
,link3
のURLたちをスクレピングするなら これら3つの結果が帰ってくるまで待ち、全部終わったらまた別のlink4
,link5
,link6
のようにしたいと考えています。上記の実装のために links = [
link1
,link2
,link3
]のような配列を作りのようにして、非同期処理を行いながら、linksのすべての非同期なスクレピングが終わるまで待てるようになりました。
発生している問題
ここで問題が発生していて、 これら複数のlinksすべてが終わるまでスクレピングを待つ際に 以下のようなエラーが一部のリンクで発生します。
このサイト自体にはブラウザからはアクセスできるため、海外からのスクレピングのようなアクセスを遮断しているか、もしくは、なにかスクレピング時に要求が多すぎて実行されない? ようなエラーが起きていると考えています。
ここで、複数のlinksをPromise.allで待っている際に、上記のエラーが発生すると、永遠に時間が経っても、要求が帰ってこないため、ここで止まってしまいます。
httpcheerio側で、このように長時間返信待ちに強制的に通信を止めるパラメータや手段はありますでしょうか?