Une plateforme low-code alliant la simplicité du no-code à la puissance du full-code 🚀
Commencez gratuitement
Optimisation des stratégies d'attente dans Puppeteer : Guide complet des méthodes d'attente
20 mars 2025
9
min lire

Optimisation des stratégies d'attente dans Puppeteer : Guide complet des méthodes d'attente

Georges Miloradovitch
Chercheur, rédacteur et intervieweur de cas d'utilisation
Table des matières

Aux prises avec Marionnettiste Les scripts expirent ou échouent ? Voici comment résoudre ce problème.

Marionnettiste, un Node.js bibliothèque pour le contrôle Chrome, est puissant pour l'automatisation web. Cependant, le contenu dynamique et les pages pilotées par API peuvent compliquer le timing. Des stratégies d'attente appropriées garantissent le fonctionnement fiable et efficace de vos scripts.

Principaux plats à emporter:

  • waitForSelector(): Attend que des éléments apparaissent (par exemple, des boutons ou des formulaires).
  • waitForNavigation(): Gère les transitions de page et assure le chargement complet des pages.
  • waitForNetworkIdle():Idéal pour les pages riches en API, attend que toutes les requêtes réseau soient terminées.
  • Conditions personnalisées: Utilisation waitForFunction() pour des scénarios complexes comme du contenu dynamique ou des animations.

Astuces rapides:

  • Ajustez les délais d'attente à l'aide de page.setDefaultTimeout() pour gérer les pages à chargement lent.
  • 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 ces stratégies pour rendre vos scripts Puppeteer plus rapides, plus fiables et mieux adaptés aux applications Web modernes.

Comment attendre / dormir pendant N secondes dans marionnettiste?

marionnettiste

Comment le marionnettiste gère l'attente

Lorsque vous utilisez Puppeteer pour l'automatisation, il est essentiel de comprendre comment il gère l'attente pour créer des scripts fiables. Puppeteer inclut des paramètres de délai d'attente par défaut pour éviter que les scripts ne se bloquent indéfiniment, mais ces paramètres peuvent nécessiter un ajustement ou des stratégies personnalisées pour les scénarios 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. Cela garantit que vos scripts ne se bloquent pas indéfiniment en cas de problème ou de durée excessive.

Vous pouvez modifier ces valeurs par défaut avec page.setDefaultTimeout(timeout)Par exemple, si le chargement de fonctionnalités complexes par votre application prend plus de temps, augmenter le délai d'expiration peut éviter que votre script ne s'arrête trop tôt. Bien que pratiques, ces paramètres par défaut ne sont pas toujours adaptés au comportement des applications dynamiques.

Défis liés aux paramètres par défaut

Les applications web modernes reposent souvent sur le chargement dynamique du 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 gérer ce problème :

  • networkidle0: Attend qu'il n'y ait plus de connexions réseau pendant 500 ms.
  • networkidle2: Attend qu'il n'y ait plus de 2 connexions réseau pendant 500 ms.

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

  • Chargement du contenu via JavaScript une fois le DOM prêt
  • Mise à jour des éléments en réponse aux appels d'API
  • Chargement de contenu supplémentaire par défilement infini
  • Applications monopage mettant à jour dynamiquement les vues

Pour relever ces défis, essayez d’utiliser un try-catch Bloc pour gérer les erreurs de dépassement de délai. Cela permet à votre script d'éviter les échecs soudains et d'appliquer des stratégies de secours si nécessaire. Au lieu de vous fier à des délais fixes, envisagez de créer des conditions d'attente basées sur l'état réel de la page. 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 des éléments, la navigation dans les pages et l'activité réseau. Ces méthodes permettent de gérer efficacement les interactions, notamment dans les environnements web dynamiques.

En utilisant waitForSelector()

Le waitForSelector() La méthode suspend l'exécution jusqu'à l'apparition d'un élément spécifique sur la page. Ceci est particulièrement utile pour le contenu chargé dynamiquement dans les applications monopage (SPA).

Voici comment vous pouvez 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.

En utilisant waitForNavigation()

Le waitForNavigation() La méthode est conçue pour gérer les transitions entre les pages. Elle attend que la page soit complètement chargée 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 avec des options :

Option Description Idéal pour
waitUntil: 'load' Attend que l'événement de chargement de la page se déclenche Pages statiques
waitUntil: 'domcontentloaded' Attend que le DOM soit entièrement chargé Interactions rapides
waitUntil: 'networkidle0' Attend qu'aucune demande réseau ne soit active Applications complexes

Cette flexibilité garantit une gestion fluide de la navigation pour différents scénarios.

En utilisant waitForNetworkIdle()

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

// 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 pour compléter la demande ou networkidle2 dans les cas où les connexions en arrière-plan peuvent rester actives.

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

sbb-itb-23997f1

Techniques d'attente complexes

Parfois, les méthodes d'attente de base ne suffisent pas. Pour les scénarios plus complexes, des techniques avancées sont la solution.

Conditions d'attente personnalisées

Lorsque les sélecteurs standards ne suffisent pas, vous pouvez utiliser waitForFunction() pour définir des conditions d'attente personnalisées en fonction de l'état de la page ou 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 scénarios 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, il est souvent nécessaire d'attendre plusieurs conditions simultanément. Promise.all() peut aider à les gérer efficacement.

Exemple de soumission 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 :

Parfois, il est nécessaire de procéder 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')
  ]);
};

Scénarios 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 puissants, capables de gérer des applications Web complexes avec des opérations asynchrones et du contenu dynamique.

Rendre les méthodes d'attente plus rapides

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

Vitesse vs stabilité

Un facteur clé pour optimiser les méthodes d'attente est de comprendre le fonctionnement de votre page. Il est essentiel d'adapter les temps 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 des chargements de page complets, utilisez 'networkidle0', et pour le contenu dynamique, utilisez 'networkidle2'Cela équilibre la vitesse et la fiabilité.

« Bien qu'attendre une période déterminée soit une mauvaise pratique, dans le monde réel, il est difficile de trouver une solution qui fonctionne bien dans tous les cas. » – Dmytro Krasun

Une autre façon d'améliorer les performances consiste à désactiver les ressources non essentielles. Cependant, pour une efficacité encore plus grande, envisagez des solutions basées sur l'IA.

Logique d'attente alimentée par l'IA

L'IA peut propulser l'optimisation de l'attente à un niveau supérieur en analysant le comportement des pages et en ajustant les conditions de manière dynamique. Des outils comme Laténode utiliser 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 les scénarios plus complexes, l'attente parallèle avec des délais d'attente optimisés peut changer la donne :

// 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 à diverses conditions de réseau et à différents temps de chargement de pages, garantissant à la fois 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'attente après avoir optimisé les méthodes d'attente.

Gestion des délais d'attente

Des erreurs de délai d'attente se produisent lorsqu'une page met plus de temps à charger que prévu. Par défaut, Puppeteer définit un délai d'attente de 30 secondes, ce qui peut être insuffisant pour les connexions Internet lentes ou les pages chargées.

Voici comment vous pouvez 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 scénarios plus complexes, essayez les délais d'expiration incrémentiels. Cette approche permet de relancer l'opération à 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...`);
    }
  }
};

Recherche d'erreurs d'attente

Pour corriger les erreurs d'attente, utilisez des techniques de surveillance systématique. 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 courantes et leurs solutions :

Type d'erreur Causes Solution
Délai d'expiration de la navigation Chargement de page important Augmenter le délai d'attente à 60000 XNUMX ms
Élément introuvable Contenu dynamique Utilisez waitForFunction avec un observateur de mutation
Délai d'inactivité du réseau Appels API multiples Utilisez l'option networkidle2 stratégie
Échec de l'interaction État de l'élément Ajouter des vérifications pour l'interactivité des éléments

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'attente, garantissant que vos scripts gèrent différents scénarios avec élégance.

Conclusion

Trouver le juste équilibre entre rapidité et stabilité est essentiel pour utiliser des stratégies d'attente dans Puppeteer. Choisir la bonne méthode d'attente garantit le bon déroulement de vos interactions web automatisées et la fiabilité de vos résultats.

Voici un aperçu rapide des stratégies d’attente courantes et du moment où les utiliser :

Stratégie d'attente Meilleur cas d'utilisation Avantage clé
waitForSelector() Éléments d'interface utilisateur dynamiques Confirme que l'élément est présent avant utilisation
waitForNavigation() Transitions de pages Maintient votre script synchronisé avec les changements de page
waitForNetworkIdle() Pages riches en API Confirme que toutes les demandes réseau sont terminées
Conditions d'attente personnalisées Scénarios complexes Offre un contrôle précis du timing

Pour un contenu dynamique, combinant waitForSelector() L'utilisation de conditions d'attente personnalisées est souvent plus efficace que les délais d'attente par défaut. Cette approche vous offre un meilleur 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, améliorant ainsi la rapidité et la fiabilité. De plus, la définition de délais d'attente avec page.setDefaultTimeout() peut aider à éviter les échecs de script tout en gardant votre automatisation efficace.

À lire également

Blogs connexes

Cas d'utilisation

Soutenu par