Comment construire un scraper et télécharger un fichier avec Puppeteer
Mihnea-Octavian Manolache le 25 avril 2023

Si vous êtes un adepte du web scraping et que vous utilisez Node JS, alors vous avez très certainement entendu parler de Puppeteer. Et vous avez certainement rencontré une tâche qui vous a demandé de télécharger un fichier avec Puppeteer. Il s'agit en effet d'une tâche récurrente dans la communauté du scraping. Mais elle n'est pas bien documentée dans la documentation de Puppeteer.
Heureusement, nous allons nous en occuper ensemble. Dans cet article, nous allons parler des téléchargements de fichiers dans Puppeteer. Il y a deux objectifs que je veux que nous abordions aujourd'hui :
- Avoir une bonne compréhension de la façon dont Puppeteer gère les téléchargements
- Créer un scraper de téléchargement de fichiers fonctionnel en utilisant node et Puppeteer
À la fin de cet article, vous aurez acquis les compétences théoriques et pratiques dont un développeur a besoin pour construire un scraper de fichiers. Si ce projet vous semble aussi excitant qu'il me semble l'être, allons-y !
Pourquoi télécharger un fichier avec Puppeteer ?
Il existe de nombreux cas d'utilisation pour un scraper de fichiers et StackOverflow est rempli de développeurs qui cherchent des réponses sur la façon de télécharger des fichiers avec puppeteer. Nous devons comprendre que les fichiers comprennent les images, les PDF, les documents Excel ou Word, et bien d'autres choses encore. Vous pouvez comprendre pourquoi tous ces éléments peuvent fournir des informations très importantes à quelqu'un.
Par exemple, certaines entreprises du secteur du dropshipping s'appuient sur des images récupérées à partir de sources externes, telles que des places de marché. Un autre bon exemple de cas d'utilisation d'un scraper de téléchargement de fichiers est celui des entreprises qui surveillent les documents officiels. Ou même les petits projets. J'ai moi-même un script qui télécharge des factures depuis le site web d'un partenaire.
Lorsqu'il s'agit d'utiliser Puppeteer pour télécharger des fichiers, je constate que la plupart des gens le choisissent pour deux raisons principales :
- 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 rendre le contenu. Cela signifie que vous ne pourriez pas télécharger les fichiers à l'aide d'un client HTTP ordinaire qui n'est pas en mesure de rendre les fichiers JavaScript.
Comment Puppeteer gère le téléchargement de fichiers
Pour comprendre comment télécharger des fichiers avec Puppeteer, nous devons savoir comment Chrome le fait aussi. En effet, Puppeteer est une bibliothèque qui "contrôle" Chrome par l'intermédiaire du protocole Chrome DevTools (CDP).
Dans Chrome, les fichiers peuvent être téléchargés :
- Manuellement, en cliquant sur un bouton par exemple
- de manière programmatique, par l'intermédiaire du domaine de page de la CDP.
Il existe également une troisième technique utilisée dans le cadre du web scraping. Elle intègre un nouvel acteur : un client HTTP. De cette façon, le scrapeur web rassemble les `hrefs` des fichiers et un client HTTP est ensuite utilisé pour télécharger les fichiers. Chaque option a ses propres cas d'utilisation et nous allons donc explorer les deux méthodes.
Télécharger des fichiers dans Puppeteer en cliquant sur un bouton
Dans le cas où le site web sur lequel vous souhaitez récupérer 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 pouvez trouver plus d'informations ici.
Puisqu'il s'agit d'un comportement "humain", ce qu'il faut faire, c'est.. :
- Ouvrir le navigateur
- Naviguer vers la page web ciblée
- Localiser l'élément bouton (par son sélecteur CSS ou xPath par exemple)
- Cliquez sur le bouton
Il n'y a que quatre étapes simples à mettre en œuvre dans notre script. Cependant, avant de nous plonger dans le codage, laissez-moi vous dire que tout comme votre navigateur quotidien, l'instance de 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 for Windows
- /Users/<username>/Downloads for Mac
- /home/<username>/Downloads for Linux
En gardant cela à l'esprit, commençons à coder. Nous supposerons que nous sommes des astrophysiciens et que nous devons recueillir des données 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 naviguer vers le domaine de la NASA et inspecter les éléments de la page. Notre objectif est d'identifier les éléments "cliquables". Pour trouver ces éléments, ouvrez Developer Tools (Commande + Option + I / Contrôle + Shift + I dans Chrome) :

#2 : Coder le 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()
})()
Ce que nous faisons ici, c'est
- Lancez Puppeteer et naviguez vers notre site web ciblé
- Sélectionner tous les éléments `tr`, qui contiennent le `href` que nous voulons cliquer plus tard
- Interroger 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. Le téléchargement de fichiers avec Puppeteer peut être aussi simple que possible.
Télécharger des fichiers dans Puppeteer avec CDP
Je sais que le dossier de téléchargement par défaut n'est pas un gros problème pour les petits projets. Pour les projets plus importants, en revanche, vous voudrez certainement organiser les fichiers téléchargés avec Puppeteer dans différents répertoires. C'est là que la CDP entre en jeu. Pour atteindre cet objectif, nous conserverons le code actuel et ne ferons que l'enrichir.
La première chose à laquelle on peut penser est de résoudre le chemin vers le répertoire courant. Heureusement, nous pouvons utiliser le module node:path intégré. Tout ce que nous avons à faire est 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 dans notre navigateur à l'aide de la CDP. Comme je l'ai déjà dit, nous allons utiliser la méthode `.setDownloadBehavior` du Page Domain. Voici à quoi ressemble notre code mis à jour avec les 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 CDPS pour "parler du protocole Chrome Devtools".
- Nous émettons l'événement `Page.setDownloadBehavior` où
a. `behavior` est réglé sur `allow` downloads
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 voulez changer le répertoire dans lequel vous enregistrez vos fichiers avec Puppeteer. De plus, nous avons également atteint notre objectif de construire un scraper web de téléchargement de fichiers.
Télécharger le fichier avec Puppeteer et Axios
La troisième option dont nous avons discuté consiste à rassembler 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 d'autres solutions pour le web scraping. Pour les besoins de ce tutoriel, je vais donc utiliser axios et supposer que nous construisons un scraper pour des images de voitures vendues 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 êtes déjà familier avec la syntaxe de Puppeteer. Contrairement aux scripts ci-dessus, ce que nous faisons maintenant est d'évaluer les éléments `img`, d'extraire leur url source, de l'ajouter à un tableau, et de retourner le tableau. Rien d'extraordinaire dans cette fonction.
#2 : Sauvegarder des 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. Ce qu'elle fait est de créer un flux inscriptible. Vous pouvez lire plus d'informations à ce sujet ici.
Ensuite, nous utilisons axios pour accéder à 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 établie, il ne reste plus qu'à combiner les deux fonctions en un programme exécutable. Pour ce faire, il suffit d'ajouter 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 pas toujours claire en ce qui concerne le téléchargement de fichiers. Malgré cela, nous avons découvert aujourd'hui plusieurs façons de l'implémenter. Mais notez que le scraping de fichiers avec Puppeteer n'est pas vraiment une tâche facile. En effet, Puppeteer lance un navigateur sans tête et ceux-ci sont généralement bloqués très rapidement.
Si vous cherchez 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 investi beaucoup de temps et d'efforts pour dissimuler nos empreintes digitales afin de ne pas être détectés. Notre taux de réussite en témoigne. Le téléchargement de fichiers à l'aide de Web Scraping API peut être aussi simple que l'envoi d'une requête curl, et nous nous occupons du reste.
Ceci étant dit, j'espère vraiment que l'article d'aujourd'hui vous a aidé dans votre processus d'apprentissage. De plus, j'espère que nous avons atteint nos deux objectifs initiaux. A partir de maintenant, vous devriez être capable de construire vos propres outils et de télécharger des fichiers avec Puppeteer.
Nouvelles et mises à jour
Restez au courant des derniers guides et nouvelles sur le web scraping en vous inscrivant à notre lettre d'information.
We care about the protection of your data. Read our <l>Privacy Policy</l>.Privacy Policy.

Articles connexes

Apprenez à récupérer des sites web dynamiques en JavaScript à l'aide de Scrapy et de Splash. De l'installation à l'écriture d'un spider, en passant par la gestion de la pagination et des réponses Splash, ce guide complet propose des instructions pas à pas pour les débutants comme pour les experts.


Apprenez quel est le meilleur navigateur pour contourner les systèmes de détection de Cloudflare lorsque vous faites du web scraping avec Selenium.


Découvrez comment extraire et organiser efficacement des données pour le web scraping et l'analyse de données grâce à l'analyse de données, aux bibliothèques d'analyse HTML et aux métadonnées schema.org.
