Passer au contenu

Comment prendre des captures d'écran avec Puppeteer pour un scraping Web efficace

Puppeteer est une bibliothèque Node.js qui fournit une API puissante pour contrôler Chrome et Chromium sans tête via le protocole DevTools. L'une de ses fonctionnalités les plus utiles est la possibilité de capturer par programme des captures d'écran de pages et d'éléments Web.

Pour les scrapers Web, la possibilité de prendre des captures d'écran avec Puppeteer ouvre une variété de cas d'utilisation précieux :

  • Débogage visuel des problèmes de scraping et des échecs de tests.
  • Capturer les états des pages dynamiques et des SPA.
  • Surveillance des régressions visuelles et des modifications de l'interface utilisateur.
  • Création de tutoriels et de documentation avec des captures d'écran pour le contexte.
  • Générer des ressources d'image à partir de pages Web.

Dans ce guide complet, nous explorerons comment exploiter les captures d'écran de Puppeteer pour améliorer vos flux de travail de scraping Web.

L'essor de Puppeteer pour le Web Scraping

Puppeteer a été publié pour la première fois en 2017 et a été rapidement adopté par la communauté du web scraping. Voici quelques statistiques qui mettent en évidence sa popularité :

  • Plus de 52,000 XNUMX étoiles sur Github, ce qui en fait l'un des meilleurs projets JS.
  • Plus de 3 millions de téléchargements hebdomadaires sur NPM.
  • Croissance de 490 % d'une année sur l'autre des recherches Google pour Marionnettiste en 2022.

Alors, qu'est-ce qui distingue Puppeteer en matière de web scraping ?

Contrôle du navigateur sans tête

Puppeteer offre un contrôle total sur un navigateur sans tête via le protocole Chrome DevTools. Cela permet de répliquer les interactions des utilisateurs pour l'automatisation et la suppression du contenu dynamique.

Léger et rapide

Être uniquement sans tête signifie que Puppeteer ignore tout le rendu de l'interface utilisateur qui fait du Chromium un poids lourd. Cela se traduit par des performances rapides pour le scraping à grande échelle.

Développement actif

Soutenu par l'équipe Chrome de Google, Puppeteer bénéficie de mises à jour fréquentes et de nouvelles fonctionnalités adaptées aux cas d'utilisation d'automatisation et de scraping.

Plus simple que le sélénium

Puppeteer se concentre uniquement sur le contrôle de Chromium alors que Selenium prend en charge plusieurs navigateurs. L'API est beaucoup plus propre et idiomatique, ce qui la rend facile à utiliser.

Pour ces raisons, de nombreux web scrapers passent de Selenium/WebDriver à Puppeteer pour améliorer la vitesse, la fiabilité et les capacités.

Voyons maintenant comment tirer parti des puissantes capacités de capture d'écran de Puppeteer.

Capturer des captures d'écran pleine page

Le moyen le plus simple de prendre une capture d'écran d'une page entière consiste à utiliser le page.screenshot() méthode:

// Launch browser
const browser = await puppeteer.launch();

// Open page 
const page = await browser.newPage();
await page.goto(‘https://example.com‘);

// Screenshot
await page.screenshot({
  path: ‘fullpage.png‘ 
});

Cela capture la fenêtre d'affichage actuellement visible. Pour capturer la hauteur complète de la page, définissez le fullPage Option de true:

await page.screenshot({
  path: ‘longpage.png‘,
  fullPage: true
}); 

Spécification des options d'image

Le screenshot() La méthode accepte des options pour contrôler le type, la qualité et plus :

  • type – png, jpeg ou webp. La valeur par défaut est png.
  • quality – Pour jpeg/webp, la qualité varie de 0 à 100. La valeur par défaut est 80.
  • omitBackground – Masque le fond blanc par défaut et autorise la transparence.
  • encoding – Peut sortir en base64 au lieu d’enregistrer un fichier.

Par exemple, pour enregistrer un jpeg de haute qualité :

await page.screenshot({
  path: ‘page.jpeg‘,
  type: ‘jpeg‘,
  quality: 100
});

Conseil : Utilisez webp pour une meilleure compression avec une qualité équivalente. Cependant, webp peut avoir des problèmes de compatibilité.

Gérer les grandes captures d'écran

Les captures d’écran d’une page entière peuvent facilement dépasser plusieurs mégaoctets. Par défaut, Puppeteer met les captures d'écran en mémoire tampon avant de les enregistrer, ce qui peut dépasser les limites du processus.

Pour gérer les grandes captures d'écran, passez l'option encoding: ‘base64‘ pour obtenir la chaîne base64 au lieu d'un Buffer. Enregistrez ensuite en utilisant fs.writeFile() pour éviter de mettre l'image en mémoire tampon.

Voici un exemple :

const buffer = await page.screenshot({ encoding: ‘base64‘ });

fs.writeFile(‘screenshot.png‘, buffer, ‘base64‘, err => {
  // handle error 
});

Défilement de grandes pages pour des captures de page entière

Pour capturer toute la hauteur des pages plus longues que la fenêtre d'affichage, nous devrons d'abord faire défiler la page.

Voici une approche utilisant page.evaluate():

// Scroll to bottom  
await page.evaluate(() => {
  window.scrollTo(0, document.body.scrollHeight);
});

// Screenshot full scrollable area
await page.screenshot({ path: ‘longpage.png‘, fullPage: true });

Nous pouvons également faire défiler progressivement les captures d'écran, puis les assembler en une seule grande capture d'écran. Cela évite d'avoir à mettre en mémoire tampon l'intégralité de l'image.

Alternative : Enregistrer au format PDF

Une autre option pour capturer du contenu d’une page entière : générez un PDF !

// Generates PDF and saves to disk 
await page.pdf({
  path: ‘page.pdf‘,
  printBackground: true
});

Avantages des PDF :

  • Gère le contenu de plusieurs pages immédiatement.
  • Le format vectoriel génère généralement des fichiers de plus petite taille.
  • Le formatage de l'impression reste intact.

Inconvénients:

  • Moins flexible pour le traitement programmatique.
  • Options de style limitées par rapport aux images.
  • Peut-être ne pas capturer le contenu rendu dynamiquement.

Définition de la taille de la fenêtre

Par défaut, Puppeteer utilise une fenêtre d'affichage de 800 px x 600 px. Pour obtenir des captures d'écran complètes précises sur différentes tailles d'ordinateur de bureau et de mobile, nous pouvons définir explicitement la fenêtre d'affichage :

// 1200px wide desktop 
await page.setViewport({
  width: 1200,
  height: 800  
});

// 400px wide mobile
await page.setViewport({
  width: 400,
  height: 1200 
});

Ensuite, les captures d'écran correspondront à la taille de fenêtre spécifiée.

Capturer des éléments

En plus des captures d'écran pleine page, nous pouvons capturer des captures d'écran d'éléments spécifiques en utilisant element.screenshot().

// Get reference to element
const menu = await page.$(‘.main-menu‘);

// Screenshot just that element
await menu.screenshot({path: ‘menu.png‘});

L’élément défilera avant de capturer la capture d’écran. Cela permet de capturer des images d'éléments qui pourraient être hors écran sans avoir à les faire défiler.

Quelques cas d'utilisation des captures d'écran d'éléments :

  • Capturer des captures d'écran de composants dynamiques tels que des tickers ou des animations.
  • Débogage des problèmes de mise en page en prenant des photos d'éléments individuels.
  • Obtenir des éléments d'image d'icônes et d'illustrations.

Captures d'écran des éléments hors écran

Un problème courant est que des éléments sont masqués ou déplacés lorsque vous essayez de capturer des captures d'écran lors d'interactions.

Nous pouvons tirer parti du défilement automatique des éléments element.screenshot() pour capturer de manière fiable des éléments dans n'importe quel état, même hors écran :

// Click button which hides the element 
await page.click(‘.toggle-menu‘);

// Menu is now hidden but we can still screenshot it
await menu.screenshot({path: ‘hidden-menu.png‘}); 

Cela permet une capture d'écran facile sans réinitialiser l'état de la page.

En attente du chargement du contenu dynamique

Lorsque nous travaillons avec des pages dynamiques, nous souhaitons attendre que le contenu soit rendu avant de prendre des captures d'écran pour capturer l'état souhaité.

Voici un exemple en attente de l'apparition d'un élément :

// Click button to trigger ajax call
await page.click(‘.load-content‘);

// Wait for new content to load
await page.waitForSelector(‘.loaded‘);

// Screenshot after loaded
await page.screenshot({path: ‘loaded.png‘}); 

page.waitForSelector() attend que le sélecteur existe dans le DOM avant de continuer.

Voici quelques autres attentes utiles :

  • page.waitFor() – Attendre qu'une condition donnée soit vraie.
  • page.waitForFunction() – Attendez la fin des mises à jour asynchrones du DOM.
  • page.waitUntil() – Attendez que la navigation ait lieu.

La clé consiste à choisir la bonne condition d'attente pour la mise à jour de la page que vous souhaitez capturer dans une capture d'écran.

En attente de modifications spécifiques du DOM

Pour synchroniser avec des modifications DOM plus discrètes, nous pouvons attendre la mise à jour des attributs au lieu des sélecteurs généraux :

// Wait for text content to change
await page.waitForFunction(() => {
  return document.querySelector(‘.status‘).textContent === ‘Loaded‘; 
});

// Element updated  
await page.screenshot({/*...*/});

Cette approche fonctionne bien pour attendre le chargement des données clés plutôt que pour les modifications statiques du DOM.

Gérer les applications à page unique (SPA)

Attendre les modifications du DOM peut être délicat avec les SPA JavaScript complexes qui mettent à jour l'état sans rechargement.

Quelques conseils pour les gérer :

  • Attendez que le réseau soit inactif après les interactions pour permettre aux XHR de se terminer.
  • Attendez que des composants spécifiques tels que les superpositions disparaissent au lieu des sélecteurs généraux.
  • Faites défiler jusqu'à la section nécessaire pour forcer le rendu avant de prendre une capture d'écran.
  • Utilisez des attentes incrémentielles au lieu de délais d'attente fixes.

Aucune approche unique ne fonctionne parfaitement pour tous les SPA. Vous devrez expérimenter avec l'application en question.

Faire défiler les pages avant de prendre des captures d'écran pleine page

Pour les pages qui nécessitent un défilement, nous devrons faire défiler par programme avant de prendre une capture d'écran complète avec fullPage: true.

Voici une approche fiable :

await page.evaluate(() => {
  // Scroll to bottom
  window.scrollTo(0, document.body.scrollHeight);
}); 

// Capture full scrolled screenshot  
await page.screenshot({fullPage: true});

Cela fait défiler la page jusqu'à la position de défilement maximale avant de prendre la capture d'écran.

Une alternative consiste à utiliser window.scrollBy() pour faire défiler progressivement une certaine quantité à la fois. Cela permet de prendre des captures d'écran en continu tout en faisant défiler toute la page.

Gestion des longues pages défilantes

Pour les pages extrêmement longues, le défilement sur toute la longueur en une seule fois peut toujours dépasser les limites de mémoire ou de temps.

Une bonne solution consiste à le diviser en sections, à le faire défiler petit à petit, à prendre des captures d'écran et à les assembler :

const screenshots = [];

while (hasMoreContent()) {

  await page.evaluate(scrollDown);

  screenshots.push(await page.screenshot()); 

}

// Stitch screenshots together into one tall image

Cela évite d'avoir à mettre en mémoire tampon la hauteur complète de la page.

Faire défiler horizontalement également

Pour les pages avec défilement horizontal, nous pouvons ajuster la séquence de défilement pour qu'elle défile également horizontalement :

await page.evaluate(() => {
  window.scrollTo(
    document.body.scrollWidth, 
    document.body.scrollHeight
  );
});

await page.screenshot({fullPage: true});

Cela capture la largeur et la hauteur de la page entière !

Meilleures pratiques pour des captures d'écran fiables

Voici quelques conseils clés pour prendre des captures d’écran cohérentes et fiables avec Puppeteer :

Attendez que le réseau soit inactif - Utilisation page.waitForNetworkIdle() après les interactions pour garantir que toutes les demandes asynchrones sont terminées avant de capturer l'état.

Utilisez des attentes appropriées – Choisissez des attentes conditionnelles qui se synchronisent avec l'état de la page souhaité plutôt que des délais d'attente généraux.

Définir la taille de la fenêtre - Définissez explicitement la fenêtre d'affichage pour capturer des captures d'écran précises de l'appareil.

Bouclier contre les animations/popups – Le survol d’éléments peut déclencher des changements – utilisez page.evaluate() pour éviter les effets secondaires.

Prévoyez du temps pour le rendu – Attendez quelques centaines de millisecondes après avoir fait défiler les pages pour terminer le rendu avant les captures d'écran.

Stabiliser les tests floconneux – Définissez une boucle de nouvelle tentative avec des attentes autour des étapes de capture d’écran pour gérer les flocons.

Comparez avec le bien connu – Tirez parti des outils de tests de régression visuelle pour détecter les changements involontaires.

Conclusion

J'espère que ce guide a fourni un aperçu complet de la prise de captures d'écran de pages entières et d'éléments avec Puppeteer pour vos besoins de scraping Web.

Quelques sujets clés que nous avons abordés :

  • Utilisation de page.screenshot() et element.screenshot() pour capturer des captures d'écran
  • Options de contrôle du type, de la qualité et du format de l'image
  • Faire défiler les pages et attendre du contenu dynamique
  • Définition de la taille de la fenêtre d'affichage pour les pages réactives
  • Meilleures pratiques pour des flux de travail de capture d'écran fiables

Les captures d'écran automatisées sont inestimables pour le débogage des scrapers, les tests visuels et la capture d'états dynamiques. Ajoutez-les à votre boîte à outils de web scraping avec Puppeteer !

Mots clés:

Prendre part à la conversation

Votre adresse email n'apparaitra pas. Les champs obligatoires sont marqués *