puppeteerで(node:6939) UnhandledPromiseRejectionWarning: TimeoutError: waiting for selector “{略}” failed: timeout 30000ms exceeded

要約

elementが見つからない場合に固まってしまうのを防ぐためには

1.elementの指定自体が間違っていないかどうか見直す
2.elementの固まり単位で 「try catch」でくくる。
3.タイムアウトを設定する。
※waitForを固定で入れるのは悪手

puppeteerは超絶便利です。
しかし不満もある。
非同期で動くのはnodeの仕様なのでしょうがない。
puppeteer recorderで吐いたソースをそのまま使うとelementが見つからないときにコケてしまう。
変更があっても良いように、DOMを指定するんじゃなくてid指定で要素を指定するべきという意見もおありでしょう。
しかし、あえてやってるんだと思うけど某yahooとかヤ○オクとかホント困る。
嫌がらせとしか思えない。

selectとかcheckboxとかを動かすときにオカルティックな動きをすることもある。
そういうときは、何回か選択をし直すとか、指定をした後に待ちを入れるとかする。

await page.waitFor(1000 * 0.5);

でもソース的に非常に気持ちが悪いし、何より速度が低下する。

なので解決策としては地道にtry catchでくくるしか無いという結論に達しました。

try {
    await page.waitForSelector('#shippings > .Shipment__body > .Shipment__timing > .Radio > .Radio__icon--off', { timeout: 1000 });
    await page.click('#shippings > .Shipment__body > .Shipment__timing > .Radio > .Radio__icon--off', { timeout: 1000 });
} catch (e) {
    message = 'error:1';
    console.log(message);
    browser.close();
    continue;
}

そうそう、エラーになったときも自動で再起動させるため、npmモジュールの「forever」を使わせてもらってます。便利。

最後に宣伝。
RPAや定形作業の自動化を検討されている方はぜひお問い合わせください!

追記
あまりに落ちまくる場合は、要素の指定自体がおかしい場合もある。
自動生成したソースを元に変数を混ぜ込むときには注意。

 

Leave a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です