Laden der Puppenspieler-Warteseite nach dem Absenden des Formulars

76

Ich sende ein Formular mit dem folgenden Code und möchte, dass Puppeteer das Laden der Seite nach dem Senden des Formulars wartet.

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'});

Wie kann ich mit dem Puppenspieler auf das Laden der Seite warten?

Redochka
quelle

Antworten:

77

Sie können asynchron auf die Navigation warten, um eine nullUmleitung zu vermeiden .

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

Dies hilft Ihnen, wenn der page.click bereits eine Navigation auslöst.

Md. Abu Taher
quelle
4
networkidlesollte jetzt auf networkidle2 github.com/GoogleChrome/puppeteer/blob/master/docs/… eingestellt werden
Ryannjohnson
@ryannjohnson Ich sehe nirgendwo in den Dokumenten, in denen erwähnt wird, dass networkidle2 notwendig ist. Vielleicht haben sich die Dokumente seit Ihrem Kommentar geändert?
Hylle
Mein Kommentar war mit networkidle und er half mir mit networkidle2. Es ist nicht notwendig, auf networkidle0 oder networkidle2 zu warten.
Md. Abu Taher
48
await page.waitForNavigation();
Redochka
quelle
5
Was ist der Unterschied zwischen diesem und await Promise.all([page.click..., page.waitForNavigation...]);?
Nathan Goings
32

Gemäß der offiziellen Dokumentation sollten Sie Folgendes verwenden:

page.waitForNavigation (Optionen)

  • options< Objekt > Navigationsparameter mit folgenden Eigenschaften:
    • timeout< Nummer > Maximale Navigationszeit in Millisekunden, standardmäßig 30 Sekunden, 0Zeitüberschreitung zum Deaktivieren. Der Standardwert kann mithilfe der page.setDefaultNavigationTimeout- Methode (Timeout) geändert werden .
    • waitUntil< string | Array < string >> Wenn die Navigation als erfolgreich angesehen werden soll, wird standardmäßig Folgendes verwendet load. Bei einer Reihe von Ereigniszeichenfolgen wird die Navigation als erfolgreich angesehen, nachdem alle Ereignisse ausgelöst wurden. Ereignisse können sein:
      • load- Betrachten Sie die Navigation als beendet, wenn das loadEreignis ausgelöst wird.
      • domcontentloaded - Betrachten Sie die Navigation als beendet, wenn die DOMContentLoadedEreignis ausgelöst wird.
      • networkidle0 - Betrachten Sie die Navigation als beendet, wenn mindestens mindestens 0 Netzwerkverbindungen bestehen 500 ms .
      • networkidle2- Betrachten Sie die Navigation als beendet, wenn für mindestens 500ms nicht mehr als 2 Netzwerkverbindungen bestehen .
  • Rückgabe: < Versprechen <[? Antwort] >> Versprechen, das in die Antwort der Hauptressource aufgelöst wird. Bei mehreren Weiterleitungen wird die Navigation mit der Antwort der letzten Weiterleitung aufgelöst. Wenn Sie aufgrund der Verwendung der Verlaufs-API zu einem anderen Anker oder einer anderen Navigation navigieren, wird die Navigation mit aufgelöst null.

Lesbarkeit:

Sie können page.waitForNavigation()warten, bis eine Seite navigiert ist:

await page.waitForNavigation();

Performance:

Da dies page.waitForNavigation()jedoch eine Abkürzung für ist page.mainFrame().waitForNavigation(), können wir Folgendes für eine geringfügige Leistungssteigerung verwenden:

await page._frameManager._mainFrame.waitForNavigation();
Grant Miller
quelle
1
Ich versuche zu warten, bis ein Bild in einem Popover geladen ist. Ist es möglich, nur 10 Sekunden zu pausieren? Keiner dieser Werte funktioniert für mich.
Chovy
8
Der Leistungshinweis ist eine vorzeitige Optimierung und hat keine praktischen Auswirkungen auf die realen Leistungen. Außerdem ist es wahrscheinlicher, dass es nach einem Upgrade des Puppenspielers kaputt geht, da es die interne API verwendet
Soufiane Ghzal
8

Ich weiß, dass es etwas spät ist, dies zu beantworten. Dies kann hilfreich sein für diejenigen, die während der Ausführung von waitForNavigation unter die Ausnahme geraten .

(Knoten: 14531) UnhandledPromiseRejectionWarning: TimeoutError: Navigation Timeout überschritten: 30000 ms überschritten bei Promise.then (/home/user/nodejs/node_modules/puppeteer/lib/LifecycleWatcher.js:142:21) um - ASYNC - um - Frame. (/home/user/nodejs/node_modules/puppeteer/lib/helper.js:111:15) auf Page.waitForNavigation (/home/user/nodejs/node_modules/puppeteer/lib/Page.js:649:49) auf Seite . (/home/user/nodejs/node_modules/puppeteer/lib/helper.js:112:23) unter /home/user/nodejs/user/puppeteer/example7.js:14:12 unter

Der richtige Code, der für mich funktioniert hat, ist wie folgt.

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

Wenn Sie zu einer neuen Seite gehen, sollte der Code ähnlich sein

await page.goto('here goes url', {waitUntil: 'domcontentloaded'});
Austin
quelle
1
Vielen Dank. Es ist wirklich hilfreich. Ich kann nicht einmal die richtige Syntax auf der offiziellen Website finden.
Mark
8

Manchmal führt sogar die Verwendung zu await page.waitForNavigation()einemError: Execution context was destroyed, most likely because of a navigation.

In meinem Fall lag es daran, dass die Seite mehrmals umgeleitet wurde. Die API gibt an, dass die Standardoption waitUntillautetLoad Ich muss bei jeder Umleitung (dreimal) auf die Navigation warten.

In meinem Fall hat es gut funktioniert, nur eine einzige Instanz von page.waitForNavigationmit der waitUntilOption zu verwenden networkidle2:

await button.click();

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

Schließlich schlägt die API vor, a Promise.Allzu verwenden, um eine Rennbedingung zu verhindern. Ich habe das nicht gebraucht, aber der Vollständigkeit halber angegeben :

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

Wenn alles andere fehlschlägt, können Sie es page.waitForSelectorwie empfohlen für ein Puppenspieler-Github-Problem verwenden - oder in meinem Fall:page.waitForXPath()

Nathan geht
quelle
Ich hatte eine Weiterleitung, die so lange dauerte, dass sie nur networkidle0richtig funktionierte.
Nathan Goings
5

Ich schlage vor, page.to in einen Wrapper zu verpacken und auf alles zu warten, was geladen wurde

Das ist mein Wrapper

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)
    }
}

Jetzt können Sie dies mit verwenden

await loadUrl(page, "https://www.google.com")
Andrea Bisello
quelle
Wird das Warten nicht networkidle0durch das Warten ersetzt networkidle2?
Rinogo
2
await Promise.all([
      page.click(selectors.submit),
      page.waitForNavigation({ waitUntil: 'networkidle0' }),
]);

Dies ist die erste Priorität, die verwendet werden muss, da darauf gewartet wird, dass das gesamte Netzwerk abgeschlossen ist, und davon ausgegangen wird, dass dies erfolgt, wenn Sie 500 ms lang nicht mehr als 0 Netzwerkanrufe haben.

Sie können auch verwenden

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

oder Sie können verwenden

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

Diese Funktion kann auch an verschiedenen Stellen verwendet werden, da sie nur dann fortgesetzt werden kann, wenn alle Anrufe erfolgreich sind, dh wenn der gesamte Antwortstatus in Ordnung ist, dh (200-299).

Denish S.
quelle
waitUntil: 'load'. Nur Kleinbuchstaben sind gültig. ref: github.com/puppeteer/puppeteer/blob/master/docs/…
Thanwa Ch.
0

Ich bin auf ein Szenario gestoßen, in dem es den klassischen POST-303-GET gab und an dem ein input[type=submit]beteiligt war. Es scheint, dass in diesem Fall clickdie Schaltfläche erst nach dem Senden und Umleiten des zugehörigen Formulars aufgelöst wird. Daher bestand die Lösung darin, das zu entfernen waitForNavigation, da es nach der Umleitung ausgeführt wurde und somit eine Zeitüberschreitung aufwies.

Tomáš Hübelbauer
quelle
0

Das hat bei mir funktioniert:

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

Aus irgendeinem Grund konnte ich nicht auf die Schaltfläche klicken (Ereignis behandelt, nicht in Form)

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

Das Problem war, dass die Seite auf der Serverseite gerendert wurde. Daher existierte die Schaltfläche nicht, wenn ich auf ein Eingabefeld warteteawait page.waitForSelector('button.button2')

Die Lösung war zu binden page.goto(URL)und page.waitForNavigation({ waitUntil: 'networkidle0' })inPromise

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

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