Latenode

Puppeteer Wait for Network Idle : guide complet des méthodes d’attente

Découvrez des stratégies d’attente efficaces dans Puppeteer pour améliorer la fiabilité et la rapidité de vos scripts d’automatisation web.

8 min de lecture
Illustration des stratégies d’attente réseau et d’éléments dans Puppeteer

Vous avez du mal avec des scripts Puppeteer qui expirent ou échouent ? Voici comment y remédier.

Puppeteer, une bibliothèque Node.js permettant de contrôler Chrome, est un outil puissant pour l’automatisation web. Mais le contenu dynamique et les pages pilotées par API peuvent compliquer la gestion du timing. Des stratégies d’attente adaptées garantissent la fiabilité et l’efficacité de vos scripts.

Points clés :

  • waitForSelector() : attend que des éléments apparaissent (par exemple, des boutons ou des formulaires).
  • waitForNavigation() : gère les transitions entre pages et garantit le chargement complet des pages.
  • waitForNetworkIdle() : idéal pour les pages riches en API, attend la fin de toutes les requêtes réseau.
  • Conditions personnalisées : utilisez waitForFunction() pour des cas complexes tels que le contenu dynamique ou les animations.

Conseils rapides :

  • Ajustez les délais d’expiration avec page.setDefaultTimeout() afin de gérer les pages qui se chargent lentement.
  • Combinez plusieurs méthodes d’attente avec Promise.all() pour une meilleure fiabilité.
  • Déboguez les erreurs d’attente en surveillant les requêtes réseau ou en vérifiant la visibilité des éléments.

Commencez par appliquer ces stratégies pour rendre vos scripts Puppeteer plus rapides, plus fiables et mieux adaptés aux applications web modernes.

Comment attendre / mettre en pause pendant N secondes dans puppeteer ?

Comment Puppeteer gère l’attente

Lorsque vous utilisez Puppeteer pour l’automatisation, comprendre sa gestion de l’attente est essentiel pour créer des scripts fiables. Puppeteer inclut des paramètres de délai d’expiration par défaut pour éviter que les scripts ne restent bloqués indéfiniment, mais ces paramètres peuvent devoir être ajustés ou complétés par des stratégies personnalisées dans les cas plus complexes.

Paramètres de délai d’expiration intégrés

Puppeteer définit des délais d’expiration par défaut pour gérer des tâches telles que la navigation, la sélection d’éléments, les requêtes réseau, les requêtes XPath et les fonctions personnalisées. Ainsi, vos scripts ne restent pas bloqués indéfiniment si un problème survient ou si une opération prend trop de temps [2].

Vous pouvez modifier ces valeurs par défaut avec page.setDefaultTimeout(timeout) [2]. Par exemple, si votre application met plus de temps à charger des fonctionnalités complexes, augmenter le délai peut empêcher votre script de s’arrêter trop tôt. Bien que pratiques, ces paramètres par défaut ne correspondent pas toujours au comportement des applications dynamiques.

Limites des paramètres par défaut

Les applications web modernes reposent souvent sur le chargement dynamique de contenu, ce qui peut rendre les mécanismes d’attente par défaut de Puppeteer insuffisants. Puppeteer propose deux conditions d’inactivité réseau pour vous aider à gérer cette situation :

  • networkidle0 : attend l’absence de connexions réseau pendant 500 ms [1].
  • networkidle2 : attend qu’il n’y ait pas plus de 2 connexions réseau pendant 500 ms [1].

Cependant, ces conditions ne correspondent pas toujours au fonctionnement des applications web. Les problèmes courants incluent :

  • Du contenu chargé via JavaScript une fois le DOM prêt
  • Des éléments mis à jour en réponse à des appels API
  • Le défilement infini qui charge du contenu supplémentaire
  • Les applications monopages qui mettent dynamiquement à jour les vues

Pour relever ces défis, essayez d’utiliser un bloc try-catch afin de gérer les erreurs de délai d’expiration [2]. Cela permet à votre script d’éviter les échecs brusques et d’appliquer des stratégies de repli si nécessaire. Au lieu de dépendre de délais fixes, envisagez de créer des conditions d’attente basées sur l’état réel de la page [3]. Cette approche est plus flexible et mieux adaptée aux environnements dynamiques.

Principales méthodes d’attente dans Puppeteer

Puppeteer propose trois méthodes clés pour gérer la détection d’éléments, la navigation entre pages et l’activité réseau. Elles permettent de gérer efficacement les interactions, en particulier dans les environnements web dynamiques.

Utiliser waitForSelector()

La méthode waitForSelector() suspend l’exécution jusqu’à ce qu’un élément spécifique apparaisse sur la page. Elle est particulièrement utile pour le contenu chargé dynamiquement dans les applications monopages (SPA).

Voici comment l’utiliser :

// Wait for an element to appear
await page.waitForSelector('.button-class');

// Wait for the element to be visible
await page.waitForSelector('.button-class', { visible: true });

// Set a custom timeout
await page.waitForSelector('.button-class', { timeout: 5000 });

Cette méthode garantit que votre script interagit avec les éléments uniquement lorsqu’ils sont prêts.

Utiliser waitForNavigation()

La méthode waitForNavigation() est conçue pour gérer les transitions entre pages. Elle attend le chargement complet de la page après des événements tels qu’un clic sur un lien ou l’envoi d’un formulaire.

await Promise.all([
  page.waitForNavigation(),
  page.click('.navigation-link')
]);

Vous pouvez personnaliser son comportement à l’aide d’options :

OptionDescriptionIdéal pour
waitUntil: 'load'Attend le déclenchement de l’événement de chargement de la pagePages statiques
waitUntil: 'domcontentloaded'Attend le chargement complet du DOMInteractions rapides
waitUntil: 'networkidle0'Attend qu’aucune requête réseau ne soit activeApplications complexes

Cette flexibilité garantit une gestion fluide de la navigation selon les différents cas d’usage.

Utiliser waitForNetworkIdle()

L’option waitForNetworkIdle() est idéale pour surveiller l’activité réseau. Elle attend que le réseau soit complètement ou presque inactif.

// Wait for all network requests to finish
await page.goto(url, { waitUntil: 'networkidle0' });

// Allow up to 2 active connections (e.g., WebSockets)
await page.goto(url, { waitUntil: 'networkidle2' });

Par exemple :

try {
  await page.waitForNavigation({ waitUntil: 'networkidle0', timeout: 30000 });
  await page.waitForSelector('.dynamic-content', { visible: true });
} catch (error) {
  console.error('Loading timeout occurred');
}

Utilisez networkidle0 lorsque toutes les requêtes doivent être terminées, ou networkidle2 lorsque des connexions en arrière-plan peuvent rester actives.

Ces méthodes sont essentielles pour créer des scripts d’automatisation web fiables, en garantissant des interactions cohérentes et efficaces avec les pages web.

sbb-itb-23997f1

Techniques d’attente complexes

Parfois, les méthodes d’attente de base ne suffisent pas. Pour des situations plus complexes, les techniques avancées sont indispensables.

Conditions d’attente personnalisées

Lorsque les sélecteurs standards ne suffisent pas, vous pouvez utiliser waitForFunction() afin de définir des conditions d’attente personnalisées basées sur l’état de la page ou sur des expressions JavaScript.

// Wait for a specific number of elements to load
await page.waitForFunction(() => {
  return document.querySelectorAll('.product-card').length > 5;
});

// Wait for dynamic content and validate its state
await page.waitForFunction(
  (expectedText) => {
    const element = document.querySelector('.status');
    return element && element.innerText.includes(expectedText);
  },
  {},
  'Ready'
);

Vous pouvez également combiner plusieurs conditions pour des situations plus complexes :

await page.waitForFunction(() => {
  const isLoaded = document.readyState === 'complete';
  const hasContent = document.querySelector('.content')?.innerHTML.length > 0;
  const noSpinner = !document.querySelector('.loading-spinner');
  return isLoaded && hasContent && noSpinner;
});

Allons maintenant plus loin en gérant plusieurs conditions simultanément.

Plusieurs méthodes d’attente

Pour les applications complexes, vous devez souvent attendre plusieurs conditions en même temps. L’utilisation de Promise.all() peut vous aider à les gérer efficacement.

Exemple d’envoi de formulaire dynamique :

// Handle form submission with multiple conditions
const submitForm = async () => {
  await Promise.all([
    page.waitForNavigation({ waitUntil: 'networkidle0' }),
    page.waitForFunction(() => !document.querySelector('.processing')),
    page.click('#submit-button')
  ]);
};

Gestion des conditions de course :

Il est parfois nécessaire de continuer dès que la première condition est remplie. Pour cela, vous pouvez utiliser Promise.race() :

// Wait for either a success or error message
const waitForResponse = async () => {
  await Promise.race([
    page.waitForSelector('.success-message'),
    page.waitForSelector('.error-message')
  ]);
};

Situations de chargement complexes :

Voici un exemple de gestion du chargement de contenu dynamique avec plusieurs conditions :

const loadDynamicContent = async () => {
  await page.click('.load-more');
  await Promise.all([
    page.waitForFunction(() => {
      return window.scrollY + window.innerHeight >= document.documentElement.scrollHeight;
    }),
    page.waitForSelector('.new-items', { visible: true }),
    page.waitForFunction(() => {
      return document.querySelectorAll('.item').length > 10;
    })
  ]);
};

Ces techniques vous aident à créer des scripts d’automatisation plus robustes, capables de gérer des applications web complexes avec des opérations asynchrones et du contenu dynamique.

Accélérer les méthodes d’attente

L’amélioration des méthodes d’attente peut considérablement augmenter la vitesse et la fiabilité des scripts d’automatisation. En combinant des techniques manuelles plus intelligentes avec des stratégies pilotées par l’IA, vous pouvez accélérer l’exécution sans sacrifier la stabilité.

Vitesse ou stabilité

Un facteur clé de l’optimisation des méthodes d’attente est la compréhension du chargement de votre page. Il est essentiel d’adapter les délais d’attente au comportement réel de la page.

// Set a default timeout for all operations
page.setDefaultTimeout(30000);

// Use efficient wait conditions
const waitForContent = async () => {
  try {
    await page.waitForSelector('.content', {
      visible: true,
      timeout: 5000 // Shorter timeout for specific elements
    });
  } catch (error) {
    console.error('Content load timeout');
    throw error;
  }
};

Pour les chargements complets de pages, utilisez 'networkidle0', et pour le contenu dynamique, utilisez 'networkidle2'. Cela équilibre la vitesse et la fiabilité.

« Attendre une durée fixe est une mauvaise pratique, mais dans le monde réel, il est difficile de trouver une solution qui fonctionne bien dans tous les cas. » — Dmytro Krasun [4]

Une autre façon d’améliorer les performances consiste à désactiver les ressources non essentielles. Toutefois, pour une efficacité encore plus grande, envisagez des solutions alimentées par l’IA.

Logique d’attente alimentée par l’IA

L’IA peut faire passer l’optimisation des attentes au niveau supérieur en analysant le comportement des pages et en ajustant dynamiquement les conditions. Des outils comme Latenode utilisent l’IA pour affiner les stratégies d’attente.

// AI-enhanced wait logic example
const smartWait = async () => {
  await page.waitForFunction(() => {
    const contentReady = document.querySelector('.content')?.offsetHeight > 0;
    const apiLoaded = window._apiData && Object.keys(window._apiData).length > 0;
    const animationsComplete = !document.querySelector('.loading-animation');

    return contentReady && apiLoaded && animationsComplete;
  }, {
    timeout: 15000,
    polling: 'mutation' // Optimized polling strategy
  });
};

Pour des situations plus complexes, l’attente parallèle avec des délais optimisés peut faire toute la différence :

// Parallel waiting with timeout optimization
const optimizedLoad = async () => {
  const timeoutPromise = new Promise((_, reject) => 
    setTimeout(() => reject(new Error('Operation timed out')), 10000)
  );

  try {
    await Promise.race([
      Promise.all([
        page.waitForSelector('.content'),
        page.waitForFunction(() => window.dataLoaded === true),
        page.waitForNetworkIdle({
          idleTime: 500,
          timeout: 8000
        })
      ]),
      timeoutPromise
    ]);
  } catch (error) {
    console.error('Loading failed:', error.message);
    throw error;
  }
};

Ces méthodes aident vos scripts à s’adapter à différentes conditions réseau et durées de chargement des pages, tout en garantissant vitesse et fiabilité.

Résoudre les problèmes d’attente

Pour garantir le bon fonctionnement de vos scripts d’automatisation, il est important de traiter les erreurs de délai d’expiration après avoir optimisé les méthodes d’attente.

Gérer les délais d’expiration

Les erreurs de délai d’expiration surviennent lorsqu’une page met plus de temps que prévu à se charger. Par défaut, Puppeteer définit un délai de 30 secondes, ce qui peut ne pas suffire avec des connexions internet lentes ou des pages lourdes.

Voici comment ajuster les paramètres de délai d’expiration :

// Set a global timeout for all operations
await page.setDefaultTimeout(60000); // 60 seconds

// Set a specific timeout for navigation
await page.setDefaultNavigationTimeout(60000); // 60 seconds

try {
  await page.waitForSelector('.dynamic-content', {
    visible: true,
    timeout: 10000 // 10 seconds
  });
} catch (error) {
  console.error('Element wait timeout:', error.message);
  // Consider adding a fallback strategy here
}

Pour les situations plus complexes, essayez les délais d’expiration progressifs. Cette approche réessaie l’opération avec des intervalles de temps croissants :

const waitWithRetry = async (selector, maxAttempts = 3) => {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      await page.waitForSelector(selector, {
        timeout: 5000 * attempt // Increase timeout with each attempt
      });
      return true;
    } catch (error) {
      if (attempt === maxAttempts) throw error;
      console.warn(`Attempt ${attempt} failed, retrying...`);
    }
  }
};

Identifier les erreurs d’attente

Pour déboguer les erreurs d’attente, utilisez des techniques de surveillance systématiques. Par exemple :

// Monitor network requests for potential timing issues
await page.setRequestInterception(true);
page.on('request', request => {
  console.log(`${request.method()} ${request.url()}`);
  request.continue();
});

// Check if an element is visible on the page
const elementVisibilityCheck = async (selector) => {
  const isVisible = await page.evaluate((sel) => {
    const element = document.querySelector(sel);
    if (!element) return false;

    const style = window.getComputedStyle(element);
    return style.display !== 'none' && 
           style.visibility !== 'hidden' && 
           style.opacity !== '0';
  }, selector);

  return isVisible;
};

Erreurs d’attente fréquentes et leurs solutions :

Type d’erreurCauseSolution
Délai d’expiration de navigationChargement de page lourdAugmenter le délai à 60000 ms
Élément introuvableContenu dynamiqueUtiliser waitForFunction avec un observateur de mutations
Délai d’expiration d’inactivité réseauPlusieurs appels APIUtiliser la stratégie networkidle2
Échec de l’interactionÉtat de l’élémentAjouter des vérifications de l’interactivité de l’élément

Voici un exemple robuste pour gérer efficacement les erreurs d’attente :

const robustWait = async (page, selector) => {
  try {
    const element = await page.waitForSelector(selector, {
      visible: true,
      timeout: 15000 // 15 seconds
    });

    // Ensure the element is interactive
    await page.waitForFunction(
      (sel) => {
        const el = document.querySelector(sel);
        return el && !el.disabled && el.getBoundingClientRect().height > 0;
      },
      { timeout: 5000 }, // Additional check timeout
      selector
    );

    return element;
  } catch (error) {
    console.error(`Wait error: ${error.message}`);
    throw new Error(`Element ${selector} isn't ready`);
  }
};

Ces stratégies peuvent vous aider à résoudre et à déboguer efficacement les problèmes de délai d’expiration, afin que vos scripts gèrent correctement des situations variées.

Conclusion

Trouver le bon équilibre entre vitesse et stabilité est essentiel lors de l’utilisation des stratégies d’attente dans Puppeteer. Le choix de la bonne méthode d’attente garantit le bon déroulement de vos interactions web automatisées et des résultats fiables.

Voici un aperçu rapide des stratégies d’attente courantes et de leurs cas d’usage :

Stratégie d’attenteMeilleur cas d’usageAvantage clé
waitForSelector()Éléments d’interface dynamiquesConfirme la présence de l’élément avant son utilisation
waitForNavigation()Transitions entre pagesMaintient votre script synchronisé avec les changements de page
waitForNetworkIdle()Pages riches en APIConfirme que toutes les requêtes réseau sont terminées
Conditions d’attente personnaliséesSituations complexesOffre un contrôle précis du timing

Pour le contenu dynamique, combiner waitForSelector() avec des conditions d’attente personnalisées fonctionne souvent mieux que de s’en tenir aux délais d’expiration par défaut. Cette approche vous donne davantage de contrôle et réduit les risques d’erreurs.

L’utilisation d’outils comme Latenode peut simplifier la mise en place de stratégies d’attente efficaces, en vous aidant à améliorer à la fois la vitesse et la fiabilité. En outre, définir des délais d’expiration avec page.setDefaultTimeout() peut aider à éviter les échecs de scripts tout en maintenant l’efficacité de votre automatisation.

References

FAQ

Frequently Asked Questions

Utilisez-le sur des applications riches en API ou des applications monopages, lorsque le contenu se charge après que le DOM est prêt. networkidle0 attend qu’aucune connexion ne reste active pendant 500 ms ; networkidle2 autorise jusqu’à deux connexions actives pour les pages utilisant des sockets en arrière-plan.

Cela vous a aidé ? Partagez-le →

Écrit par

Vasiliy Datsenko

Responsable du support client

Vasiliy Datsenko est responsable du support client chez Latenode et un rédacteur en automatisation axé sur les produits. Son travail relie les conversations clients, la recherche sur l'automatisation des flux de travail, les cas d'utilisation de l'IA et la formation pratique sur les produits pour les équipes cherchant à automatiser des processus métier réels.

Profil de l'auteur →

Vérifié par

Oleg Zankov

PDG de Latenode, expert en no-code

Avec une philosophie ancrée dans l'innovation, la résolution de problèmes et l'expérience utilisateur, je me consacre à donner aux équipes les moyens de créer des intégrations sur mesure et d'automatiser les workflows avec facilité et efficacité. Fort d'une riche expérience en développement commercial, entrepreneurship technologique et développement logiciel, j'ai reconnu le besoin d'une solution d'intégration plus accessible, évolutive et adaptable. Ainsi est né Latenode.com. Grâce à notre plateforme, les entreprises peuvent exploiter la puissance de la technologie sans nécessiter de compétences approfondies en codage. Passionné par la création d'un avenir où la technologie nous sert, et non l'inverse, ma mission est de simplifier les processus complexes. Je crois en la démocratisation de la technologie et en dotant les équipes des outils nécessaires pour innover, croître et réussir dans un monde de plus en plus numérique.

Profil de l'auteur →

Continuer la lecture