Retour au blog
Guides
Mihnea-Octavian Manolache25 avril 20238 min de lecture

Comment créer un scraper et télécharger un fichier avec Puppeteer

Comment créer un scraper et télécharger un fichier avec Puppeteer

Pourquoi télécharger des fichiers avec Puppeteer ?

Les cas d'utilisation d'un scraper de fichiers sont nombreux, et StackOverflow regorge de développeurs à la recherche de réponses sur la manière de télécharger des fichiers avec Puppeteer. Il faut comprendre que les fichiers comprennent des images, des PDF, des documents Excel ou Word, et bien d'autres encore. Vous comprenez pourquoi tous ces éléments peuvent fournir des informations très importantes à certaines personnes.

Par exemple, certaines entreprises du secteur du dropshipping s'appuient sur des images extraites de sources externes, telles que les places de marché. Un autre bon exemple d'utilisation d'un scraper de téléchargement de fichiers concerne les entreprises qui surveillent des documents officiels. Ou même de petits projets. J'ai moi-même un script qui télécharge des factures depuis le site web d'un partenaire.

En ce qui concerne l'utilisation de Puppeteer pour télécharger des fichiers, je constate que la plupart des gens le choisissent principalement pour deux raisons :

  • Il est conçu pour Node JS, et Node JS est l'un des langages de programmation les plus populaires, tant pour le front-end que pour le back-end.
  • Il ouvre un véritable navigateur et certains sites web s'appuient sur JavaScript pour afficher leur contenu. Cela signifie que vous ne pourriez pas télécharger les fichiers à l'aide d'un client HTTP classique, incapable d'exécuter les fichiers JavaScript.

Comment Puppeteer gère le téléchargement de fichiers

Pour comprendre comment télécharger des fichiers avec Puppeteer, il faut également savoir comment Chrome s'y prend. En effet, à la base, Puppeteer est une bibliothèque qui « contrôle » Chrome via le protocole Chrome DevTools (CDP).

Dans Chrome, les fichiers peuvent être téléchargés :

  • Manuellement, par exemple en cliquant sur un bouton
  • Par programmation, via le domaine de la page depuis le CDP.

Il existe également une troisième technique utilisée dans le web scraping. Elle intègre en effet un nouvel acteur : un client HTTP. De cette manière, le web scraper recueille les `hrefs` des fichiers, puis un client HTTP est utilisé pour télécharger les fichiers. Chaque option a ses cas d'utilisation particuliers ; nous allons donc explorer ces deux méthodes.

Télécharger des fichiers dans Puppeteer d'un simple clic

Si, par chance, le site web dont vous souhaitez extraire des fichiers utilise des boutons, il vous suffit de simuler l'événement de clic dans Puppeteer. La mise en œuvre d'un téléchargeur de fichiers est assez simple dans ce scénario. Puppeteer documente même la méthode Page.click() et vous trouverez plus d'informations ici.

Comme il s'agit d'un comportement « semblable à celui d'un humain », voici ce que nous devons faire :

  • Ouvrir le navigateur
  • Accéder à la page Web ciblée
  • Localiser l'élément bouton (à l'aide de son sélecteur CSS ou de son xPath, par exemple)
  • Cliquer sur le bouton

Il n'y a que quatre étapes simples à mettre en œuvre dans notre script. Cependant, avant de nous lancer dans le codage, sachez que, tout comme votre navigateur habituel, l'instance Chrome contrôlée par Puppeteer enregistrera le fichier téléchargé dans le dossier de téléchargement par défaut, qui est :

  • \Users\<username>\Downloads pour Windows
  • /Users/<username>/Downloads pour Mac
  • /home/<nom d'utilisateur>/Téléchargements pour Linux

Gardant cela à l'esprit, commençons à coder. Imaginons que nous soyons des astrophysiciens et que nous ayons besoin de collecter des données auprès de la NASA, que nous traiterons plus tard. Pour l'instant, concentrons-nous sur le téléchargement des fichiers .doc.

#1 : Identifier les éléments « cliquables »

Nous allons nous rendre sur le domaine de la NASA ici et inspecter les éléments de la page. Notre objectif est d’identifier les éléments « cliquables ». Pour trouver ces éléments, ouvrez les Outils de développement (Commande + Option + I / Ctrl + Maj + I dans Chrome) :

NASA documents listing page with browser devtools highlighting a download link element

#2 : Codage du projet

import puppeteer from "puppeteer"

(async () => {

   const browser = await puppeteer.launch({ headless: false })

   const page = await browser.newPage()

   await page.goto('https://www.nasa.gov/centers/dryden/research/civuav/civ_uav_doc-n-ref.html',

       { waitUntil: 'networkidle0' })

   const tr_elements = await page.$x('html/body/div[1]/div[3]/div[2]/div[2]/div[5]/div[1]/table[2]/tbody/tr')

   for (let i = 2; i<=tr_elements.length; i ++) {

       const text = await tr_elements[i].evaluate(el => el.textContent)

       if (text.toLocaleLowerCase().includes('doc')) {

           try {

               await page.click(`#backtoTop > div.box_710_cap > div.box_710.box_white.box_710_white > div.white_article_wrap_detail.text_adjust_me > div.default_style_wrap.prejs_body_adjust_detail > table:nth-child(6) > tbody > tr:nth-child(${i}) > td:nth-child(3) > a`)

           }catch {}

       }

   }

   await browser.close()

})()

Voici ce que nous allons faire :

  • Lancer Puppeteer et accéder au site web ciblé
  • Sélectionner tous les éléments `tr` qui contiennent l'attribut `href` sur lequel nous voulons cliquer plus tard
  • Parcourir les éléments `tr` et a. Vérifier si le texte à l'intérieur de l'élément contient le mot « doc » b. Si c'est le cas, nous construisons le sélecteur et cliquons sur l'élément
  • Fermer le navigateur

Et c'est tout. Télécharger des fichiers avec Puppeteer ne peut pas être plus simple.

Télécharger des fichiers dans Puppeteer avec CDP

Je sais que le dossier de téléchargement par défaut ne pose pas de gros problème pour les petits projets. En revanche, pour les projets plus importants, vous souhaiterez certainement organiser les fichiers téléchargés avec Puppeteer dans différents répertoires. C’est là que CDP entre en jeu. Pour atteindre cet objectif, nous conserverons le code actuel et nous nous contenterons de le compléter.

La première chose qui vient à l'esprit est de résoudre le chemin d'accès au répertoire actuel. Heureusement, nous pouvons utiliser le module intégré node:path. Il suffit d'importer le module `path` dans notre projet et d'utiliser la méthode `resolve`, comme vous le verrez dans un instant.

Le deuxième aspect consiste à définir le chemin d'accès dans notre navigateur à l'aide de CDP. Comme je l'ai dit précédemment, nous utiliserons la méthode `.setDownloadBehavior` de Page Domain. Voici à quoi ressemble notre code mis à jour avec ces deux ajouts :

import puppeteer from "puppeteer"

import path from 'path'

(async () => {

   const browser = await puppeteer.launch({ headless: false })

   const page = await browser.newPage()

   const client = await page.target().createCDPSession()

   await client.send('Page.setDownloadBehavior', {

       behavior: 'allow',

       downloadPath: path.resolve('./documents')

   });

   await page.goto('https://www.nasa.gov/centers/dryden/research/civuav/civ_uav_doc-n-ref.html',

       { waitUntil: 'networkidle0' })

   const tr_elements = await page.$x('html/body/div[1]/div[3]/div[2]/div[2]/div[5]/div[1]/table[2]/tbody/tr')

   for (let i = 1; i<=tr_elements.length; i ++) {

       const text = await tr_elements[i].evaluate(el => el.textContent)

       if (text.toLocaleLowerCase().includes('doc')) {

           try {

               await page.click(`#backtoTop > div.box_710_cap > div.box_710.box_white.box_710_white > div.white_article_wrap_detail.text_adjust_me > div.default_style_wrap.prejs_body_adjust_detail > table:nth-child(6) > tbody > tr:nth-child(${i}) > td:nth-child(3) > a`)

           } catch {}

       }

   }

   await browser.close()

})()

Voici ce que nous faisons avec le code ajouté :

  • Nous créons une nouvelle session CDPSession pour « communiquer en langage brut du protocole Chrome Devtools »
  • Nous émettons l'événement `Page.setDownloadBehavior` où a. `behavior` est défini sur `allow` pour autoriser les téléchargements b. `downloadPath` est construit avec `node:path` pour pointer vers le dossier où nous allons stocker nos fichiers

Et c'est tout ce que vous avez à faire si vous souhaitez modifier le répertoire dans lequel enregistrer les fichiers avec Puppeteer. De plus, nous avons également atteint notre objectif de créer un scraper web permettant de télécharger des fichiers.

Télécharger un fichier avec Puppeteer et Axios

La troisième option dont nous avons parlé consiste à collecter les liens vers les sites ciblés et à utiliser un client HTTP pour les télécharger. Personnellement, je préfère Axios, mais il existe également d’autres alternatives en matière de scraping web. Donc, pour les besoins de ce tutoriel, je vais utiliser Axios et partir du principe que nous créons un scraper pour les images de voitures mises aux enchères.

#1 : Collecter les liens vers nos fichiers

const get_links = async (url) => {

   const hrefs = []

   const browser = await puppeteer.launch({ headless: false })

   const page = await browser.newPage()

   await page.goto(url, { waitUntil: 'networkidle0' })

   const images = await page.$$('img')

   for (let i = 1; i<=images.length; i ++) {

       try {

          hrefs.push(await images[i].evaluate(img => img.src))

      } catch {}

   }

   await browser.close()

   return hrefs

}

Je suis sûr que vous maîtrisez désormais la syntaxe de Puppeteer. Contrairement aux scripts ci-dessus, ce que nous faisons maintenant consiste à évaluer les éléments `img`, à extraire leur URL source, à l'ajouter à un tableau et à renvoyer ce tableau. Cette fonction n'a rien de compliqué.

#2 : Enregistrer les fichiers avec axios

const download_file = async (url, save) => {

   const writer = fs.createWriteStream(path.resolve(save))

   const response = await axios({

       url,

       method: 'GET',

       responseType: 'stream'

   })

   response.data.pipe(writer)

   return new Promise((resolve, reject) => {

       writer.on('finish', resolve)

       writer.on('error', reject)

   })

}

Cette fonction est un peu plus complexe, car elle introduit deux nouveaux paquets : `fs` et `axios`. La première méthode du paquet `fs` est assez explicite. Elle permet de créer un flux inscriptible. Vous pouvez en savoir plus à ce sujet ici.

Ensuite, nous utilisons axios pour « puiser » dans l’URL du serveur, et nous indiquons à axios que la réponse sera de type « stream ». Enfin, puisque nous travaillons avec un flux, nous allons utiliser `pipe()` pour écrire la réponse dans notre flux.

Une fois cette configuration en place, il ne reste plus qu’à combiner les deux fonctions pour obtenir un programme exécutable. Pour ce faire, ajoutez simplement les lignes de code suivantes :

let i = 1

const images = await get_links('https://www.iaai.com/Search?url=PYcXt9jdv4oni5BL61aYUXWpqGQOeAohPK3E0n6DCLs%3d')

images.forEach(async (img) => {

   await download_file(img, `./images/${i}.svg`)

   i += 1

})

Conclusions

La documentation de Puppeteer n’est peut-être pas très claire concernant le téléchargement de fichiers. Malgré cela, nous avons découvert aujourd’hui plusieurs façons de le mettre en œuvre. Mais notez que le scraping de fichiers avec Puppeteer n’est pas vraiment une tâche facile. En effet, Puppeteer lance un navigateur sans interface graphique, et ceux-ci sont généralement bloqués très rapidement.

Si vous recherchez un moyen discret de télécharger des fichiers par programmation, vous pouvez vous tourner vers un service de web scraping. Chez Web Scraping API, nous avons consacré beaucoup de temps et d'efforts à masquer nos empreintes afin de ne pas être détectés. Et cela se traduit par des résultats concrets dans notre taux de réussite. Télécharger des fichiers à l'aide de Web Scraping API peut être aussi simple que d'envoyer une requête curl, et nous nous occupons du reste.

Cela étant dit, j’espère sincèrement que l’article d’aujourd’hui vous a aidé dans votre apprentissage. De plus, j’espère que nous avons atteint nos deux objectifs initiaux. À partir de maintenant, vous devriez être en mesure de créer vos propres outils et de télécharger des fichiers avec Puppeteer.

À propos de l'auteur
Mihnea-Octavian Manolache, Développeur Full Stack @ WebScrapingAPI
Mihnea-Octavian ManolacheDéveloppeur Full Stack

Mihnea-Octavian Manolache est ingénieur Full Stack et DevOps chez WebScrapingAPI, où il développe des fonctionnalités pour les produits et assure la maintenance de l'infrastructure qui garantit le bon fonctionnement de la plateforme.

Commencez à créer

Prêt à faire évoluer votre système de collecte de données ?

Rejoignez plus de 2 000 entreprises qui utilisent WebScrapingAPI pour extraire des données Web à l'échelle de l'entreprise, sans aucun coût d'infrastructure.