Ляльковий чекає завантаження сторінки після подання форми


81

Я подаю форму, використовуючи наступний код, і я хочу, щоб Лялечник чекав завантаження сторінки після подання форми.

await page.click("button[type=submit]");

//how to wait until the new page loads before taking screenshot?
// i don't want this:
// await page.waitFor(1*1000);  //← unwanted workaround
await page.screenshot({path: 'example.png'});

Як дочекатися завантаження сторінки ляльководом?

Відповіді:


82

Ви можете чекати навігації асинхронно, щоб уникнути nullперенаправлення,

await Promise.all([
      page.click("button[type=submit]"),
      page.waitForNavigation({ waitUntil: 'networkidle0' }),
]);

Це допоможе вам, якщо сторінка click вже викликає навігацію.


4
networkidleтепер слід встановити networkidle2 github.com/GoogleChrome/puppeteer/blob/master/docs/…
ryannjohnson

@ryannjohnson Я не бачу ніде в документах, де він згадує, необхідний networkidle2? Можливо, документи змінились після вашого коментаря?
Hylle

Мій коментар стосувався networkidle, і він допомагав мені з networkidle2. Не потрібно чекати networkidle0 або networkidle2.
Md. Abu Taher


33

Відповідно до офіційної документації , ви повинні використовувати:

page.waitForNavigation (варіанти)

  • options< Об'єкт > Параметри навігації, які можуть мати такі властивості:
    • timeout< число > Максимальний час навігації в мілісекундах, за замовчуванням 30 секунд, пропустіть, 0щоб вимкнути тайм-аут. Значення за замовчуванням можна змінити за допомогою методу page.setDefaultNavigationTimeout (timeout) .
    • waitUntil< рядок | Масив < рядок >> Коли вважати навігацію успішною, за замовчуванням load. Враховуючи масив рядків подій, навігація вважається успішною після запуску всіх подій. Події можуть бути:
      • load- вважати навігацію закінченою під час loadзапуску події.
      • domcontentloaded- вважати навігацію закінченою під час DOMContentLoadedзапуску події.
      • networkidle0- вважати навігацію закінченою, якщо не менше 0 мережевих з’єднань протягом принаймні 500мс.
      • networkidle2- вважати навігацію закінченою, якщо не менше 2 мережевих з’єднань протягом принаймні 500мс.
  • повертає: < Обіцянка <[? Відповідь] >> Обіцянка, яка переходить до відповіді основного ресурсу. У разі кількох переадресацій навігація буде вирішена з відповіддю останнього переадресації. У разі переходу до іншого якоря або навігації через використання API історії, навігація вирішить за допомогою null.

Читаність:

Ви можете використовувати page.waitForNavigation()для очікування сторінки для навігації:

await page.waitForNavigation();

Продуктивність:

Але оскільки page.waitForNavigation()це ярлик для page.mainFrame().waitForNavigation(), ми можемо використовувати наступне для незначного підвищення продуктивності:

await page._frameManager._mainFrame.waitForNavigation();

1
Я намагаюся дочекатися завантаження зображення в поповері. Чи можна просто зробити паузу на 10 секунд? Жодне з цих цінностей не працює для мене.
чови

8
Підказка щодо продуктивності - це передчасна оптимізація, і вона не матиме практичних результатів щодо реальних виступів. Плюс, це більше шансів зламатися після оновлення ляльковода, оскільки він використовує внутрішній API
Soufiane Ghzal

11

Іноді навіть використання await page.waitForNavigation()все одно призводить доError: Execution context was destroyed, most likely because of a navigation.

У моєму випадку це було тому, що сторінка переспрямовувала кілька разів. API говорить за замовчуванням waitUntilопція Load-Цей потрібно мені чекати навігації кожен редирект (3 рази).

Використання лише одного екземпляра page.waitForNavigationз waitUntilпараметром networkidle2добре працювало в моєму випадку:

await button.click();

await page.waitForNavigation({waitUntil: 'networkidle2'});

Нарешті, API пропонує використовувати a Promise.Allдля запобігання перегоновим умовам. Мені це не потрібно, але надайте це для повноти :

await Promise.all([button.click(), page.waitForNavigation({waitUntil:'networkidle2'})])

Якщо все інше не вдається, ви можете використовувати, page.waitForSelectorяк рекомендовано, у випуску Puppeteer github - або в моєму випадку,page.waitForXPath()


У мене було переспрямування, яке тривало так довго, що networkidle0працювало лише належним чином.
Nathan Goings,

8

Я знаю, що пізно відповісти на це. Це може бути корисно для тих, хто потрапляє нижче винятку під час роботи waitForNavigation .

(вузол: 14531) UnhandledPromiseRejectionWarning: TimeoutError: Перевищено час очікування навігації: перевищено 30000ms на Promise.then (/home/user/nodejs/node_modules/puppeteer/lib/LifecycleWatcher.js:142:21) на - ASYNC - у Frame. (/home/user/nodejs/node_modules/puppeteer/lib/helper.js:111:15) на Page.waitForNavigation (/home/user/nodejs/node_modules/puppeteer/lib/Page.js:649:49) на сторінці . (/home/user/nodejs/node_modules/puppeteer/lib/helper.js:112:23) на /home/user/nodejs/user/puppeteer/example7.js:14:12 о

Правильний код, який працював для мене, поданий нижче.

await page.click('button[id=start]', {waitUntil: 'domcontentloaded'});

Подібним чином, якщо ви переходите на нову сторінку, код повинен бути таким

await page.goto('here goes url', {waitUntil: 'domcontentloaded'});

1
Дякую. Це дуже корисно. Я навіть не можу знайти правильний синтаксис на офіційному веб-сайті.
Позначте

5

я пропоную загортати page.to в обгортку і чекати, поки все завантажиться

це моя обгортка

loadUrl: async function (page, url) {
    try {
        await page.goto(url, {
            timeout: 20000,
            waitUntil: ['load', 'domcontentloaded', 'networkidle0', 'networkidle2']
        })
    } catch (error) {
        throw new Error("url " + url + " url not loaded -> " + error)
    }
}

тепер ви можете використовувати це з

await loadUrl(page, "https://www.google.com")

Хіба не чекання networkidle0замінено чеканням networkidle2?
rinogo

3
await Promise.all([
      page.click(selectors.submit),
      page.waitForNavigation({ waitUntil: 'networkidle0' }),
]);

Це буде першим пріоритетом для використання, оскільки він чекає завершення роботи всієї мережі, і припускає, що це зроблено, коли у вас не більше 0 мережевих дзвінків протягом 500 мс.

Ви також можете використовувати

await page.waitForNavigation({ waitUntil: 'Load' })

або ж ви можете використовувати

await page.waitForResponse(response => response.ok())

цю функцію також можна використовувати в різних місцях, оскільки вона дозволяє продовжувати далі лише тоді, коли всі дзвінки мають успіх, тобто, коли всі відповіді в порядку, тобто (200-299)


waitUntil: 'load'. Дійсний лише малий регістр. посилання: github.com/puppeteer/puppeteer/blob/master/docs/…
Thanwa Ch.

1

Це спрацювало для мене:

await Promise.all([
    page.goto(URL),
    page.waitForNavigation({ waitUntil: 'networkidle0' }),
]);
console.log('page loaded')

З якоїсь причини я не зміг натиснути кнопку (обробляв подію, не у формі)

<button onclick="someFunction();" class="button button2">Submit</button>

Проблема полягала в тому, що сторінка відображалася на стороні сервера. Таким чином, кнопка не існувала кожного разу, коли я чекав поля введенняawait page.waitForSelector('button.button2')

Розчин для зв'язування page.goto(URL)і page.waitForNavigation({ waitUntil: 'networkidle0' })вPromise

await Promise.all([
    page.goto(URL),
    page.waitForNavigation({ waitUntil: 'networkidle0' }),
]);
console.log('page loaded')

await page.waitForSelector('button.button2')
console.log('button is here');

0

Я зіткнувся зі сценарієм, коли був класичний POST-303-GET і input[type=submit]був задіяний. Здається, що в цьому випадку clickкнопка кнопки не вирішиться до подання та перенаправлення асоційованої форми, тому рішення було видалити waitForNavigation, оскільки вона була виконана після переспрямування, і, отже, закінчився час очікування.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.