Help us understand the problem. What is going on with this article?

puppeteerでどのwaitForが失敗しているか分からず詰まった話

More than 1 year has passed since last update.

早速注意なのですが、現状暫定対応で凌いでおり個人的にしっくりしておりません。
なのでcoolな解決法がございましたら教えてください。

2018/06/13 追記
今は解消されていると思います!

暫定対応(飛ばしたい人はこちらから)

さて、困っていることはタイトルの通りだが、うだうだ文章に書くより実際にコードを載せたほうが早いと思うので下記が該当のものになる。

sample.js
const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        args: [
            '--no-sandbox',
            '--disable-setuid-sandbox',
        ]
    });
    process.on('unhandledRejection', (reason, p) => {
        console.log(reason, p);
        browser.close();
    });
    const page = await browser.newPage();
    await page.goto('https://www.google.com/');
    await page.type("#lst-ib", "puppeteer");
    await page.click('input[name="btnK"]');
    await page.waitFor('#rso > div > div > div:nth-child(1) > div > div.rc > h3 > a');
    await page.waitFor('存在しない要素', {timeout: 1});
    browser.close();
})();

で、上記を実行したときのコンソールがこちら

$ node sample01
Error: waiting failed: timeout 1ms exceeded
    at Timeout.WaitTask._timeoutTimer.setTimeout (/home/operational_work/puppeteer/node_modules/puppeteer/lib/FrameManager.js:695:58)
    at ontimeout (timers.js:475:11)
    at tryOnTimeout (timers.js:310:5)
    at Timer.listOnTimeout (timers.js:270:5) Promise {
  <rejected> Error: waiting failed: timeout 1ms exceeded
    at Timeout.WaitTask._timeoutTimer.setTimeout (/home/operational_work/puppeteer/node_modules/puppeteer/lib/FrameManager.js:695:58)
    at ontimeout (timers.js:475:11)
    at tryOnTimeout (timers.js:310:5)
    at Timer.listOnTimeout (timers.js:270:5) }

エラーログとしてはtimeoutで落ちているのかはわかったのだが、どのwaitForで落ちているのかはわからないのでそれを解決したい。

試したこと

assert入れればいいんじゃない?

早速トライ

sample.js
const puppeteer = require('puppeteer');
const assert = require('assert');

(async () => {
    const browser = await puppeteer.launch({
        args: [
            '--no-sandbox',
            '--disable-setuid-sandbox',
        ]
    });
    process.on('unhandledRejection', (reason, p) => {
        console.log(reason, p);
        browser.close();
    });
    const page = await browser.newPage();
    await page.goto('https://www.google.com/');
    await page.type("#lst-ib", "puppeteer");
    await page.click('input[name="btnK"]');
    await page.waitFor('#rso > div > div > div:nth-child(1) > div > div.rc > h3 > a');
    assert(await page.waitFor('存在しない要素', {timeout: 1}));
    browser.close();
})();

コンソール

$ node sample01
Error: waiting failed: timeout 1ms exceeded
    at Timeout.WaitTask._timeoutTimer.setTimeout (/home/operational_work/puppeteer/node_modules/puppeteer/lib/FrameManager.js:695:58)
    at ontimeout (timers.js:475:11)
    at tryOnTimeout (timers.js:310:5)
    at Timer.listOnTimeout (timers.js:270:5) Promise {
  <rejected> Error: waiting failed: timeout 1ms exceeded
    at Timeout.WaitTask._timeoutTimer.setTimeout (/home/operational_work/puppeteer/node_modules/puppeteer/lib/FrameManager.js:695:58)
    at ontimeout (timers.js:475:11)
    at tryOnTimeout (timers.js:310:5)
    at Timer.listOnTimeout (timers.js:270:5) }

ダメだ変わらん…

バックトレース仕込めばいいんじゃない?

sample.js
const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        args: [
            '--no-sandbox',
            '--disable-setuid-sandbox',
        ]
    });
    process.on('unhandledRejection', (reason, p) => {
        console.trace();
        browser.close();
    });
    const page = await browser.newPage();
    await page.goto('https://www.google.com/');
    await page.type("#lst-ib", "puppeteer");
    await page.click('input[name="btnK"]');
    await page.waitFor('#rso > div > div > div:nth-child(1) > div > div.rc > h3 > a');
    await page.waitFor('存在しない要素', {timeout: 1});
    browser.close();
})();

コンソール

$ node sample01
Trace
    at process.on (/home/operational_work/puppeteer/sample01.js:12:17)
    at emitTwo (events.js:126:13)
    at process.emit (events.js:214:7)
    at emitPendingUnhandledRejections (internal/process/promises.js:94:22)
    at runMicrotasksCallback (internal/process/next_tick.js:124:9)
    at _combinedTickCallback (internal/process/next_tick.js:131:7)
    at process._tickCallback (internal/process/next_tick.js:180:9)

あ、そうなるのね……。

暫定対応

色々ググってみたがようわからんとなり、どうしたか言うと……。

sample.js
const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        args: [
            '--no-sandbox',
            '--disable-setuid-sandbox',
        ]
    });
    process.on('unhandledRejection', (reason, p) => {
        console.log('失敗したwaitFor:' + selector);
        browser.close();
    });
    const page = await browser.newPage();
    let selector;
    const waitFor = x => {
        selector = x;
        return page.waitFor(selector, {timeout: 500});
    };
    await page.goto('https://www.google.com/');
    await page.type("#lst-ib", "puppeteer");
    await page.click('input[name="btnK"]');
    await waitFor('#rso > div > div > div:nth-child(1) > div > div.rc > h3 > a');
    await waitFor('存在しない要素');
    browser.close();
})();

waitForのラッピング関数を作って、selectorをどんどん上書いて失敗したのをログに出した。

で、コンソール

$ node sample01
失敗したwaitFor:存在しない要素

一応、目的は達成したけどなんか腑に落ちにない……。
なので、アドバイス等を募集中です。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした