Qu'est-ce que Puppeteer et pourquoi est-ce important pour le web scraping ?
En général, le web scraping désigne le processus d'automatisation de l'extraction de données à partir de divers serveurs. Autrefois, un simple client HTTP aurait suffi pour effectuer cette tâche. De nos jours, cependant, les sites web s'appuient de plus en plus sur JavaScript. Or, les clients HTTP traditionnels sont incapables de rendre les fichiers JavaScript. C'est là que Puppeteer entre en jeu.
Puppeteer est une bibliothèque Node.js qui vous permet de contrôler un navigateur Chrome ou Chromium sans interface graphique via le protocole DevTools. En résumé, elle fournit une API de haut niveau pour automatiser Chrome.
En matière de web scraping, Puppeteer est utile pour extraire des données de sites web qui nécessitent le rendu de JavaScript. De plus, il peut également être utilisé pour interagir avec des pages web de manière similaire à un humain. Par exemple, cliquer sur des boutons ou, notre sujet du jour, remplir des formulaires. Cela le rend idéal pour extraire des données de sites web qui utilisent des techniques anti-scraping.
Mise en place d'un projet Puppeteer simple
Je pense qu’il vaut mieux prendre son temps pour mieux comprendre le processus dans son ensemble. Avant d’aborder la manière de soumettre un formulaire avec Puppeteer, parlons d’abord de Puppeteer en général. Dans cette section, je vais vous montrer comment configurer un projet Node, installer Puppeteer et l’utiliser pour extraire des données. Commençons donc par créer un nouveau dossier et ouvrons-le dans l'IDE de votre choix. Je préfère Visual Studio Code, mais n'hésitez pas à utiliser celui qui vous convient le mieux.
Le saviez-vous ?
- Vous pouvez créer un nouveau dossier « par programmation » depuis votre terminal en tapant la commande `mkdir`.
- Vous pouvez utiliser la commande `npm init -y` pour configurer un projet Node et accepter les valeurs par défaut
- Vous pouvez créer un nouveau fichier avec la commande `touch`.
- Et vous pouvez également ouvrir VSCode avec la commande `code .`.
Si vous le souhaitez, vous pouvez combiner ces quatre commandes et lancer un projet en quelques secondes comme ceci :
~ » mkdir scraper && cd scraper && npm init -y && code .
Dans votre IDE, ouvrez un nouveau terminal (Terminal > Nouveau terminal) et installons Puppeteer. Tapez `npm i puppeteer --save` dans votre terminal. Par ailleurs, je préfère utiliser les modules JS plutôt que CommonJS. Découvrez les différences entre les deux ici. Si vous souhaitez également utiliser les modules, ouvrez `package.json` et ajoutez `"type": "module"` à l'objet JSON.
Maintenant que tout est prêt, nous pouvons commencer à ajouter du code. Créez un nouveau fichier `index.js` et ouvrez-le dans l'IDE. Pas besoin de le faire depuis le terminal cette fois-ci, mais à titre indicatif, vous pourriez utiliser la commande `touch`. Ajoutons maintenant le code :
import puppeteer, { executablePath } from 'puppeteer'
const scraper = async (url) => {
const browser = await puppeteer.launch({
headless: false,
executablePath: executablePath(),
})
const page = await browser.newPage()
await page.goto(url)
const html = await page.content()
await browser.close()
return html
}
Et voyons ce que nous faisons :
- Nous importons Puppeteer et `executablePath` dans notre projet
- Nous définissons une nouvelle fonction qui prend un paramètre `url`
- Nous lançons un nouveau navigateur à l'aide de `puppeteer.launch` a. Nous précisons que nous voulons qu'il s'exécute en mode head-first b. Nous utilisons `executablePath` pour obtenir le chemin d'accès à Chrome
- Nous ouvrons une nouvelle page et naviguons vers l'`url`
- Nous enregistrons `page.content()` dans une constante
- Nous fermons l'instance du navigateur
- Et enfin, nous renvoyons le code `html` de la page que nous venons de scraper
Jusqu'ici, rien de compliqué. C'est le strict minimum pour implémenter un scraper web avec Node JS et Puppeteer. Si vous souhaitez exécuter le code, il suffit de passer une cible à la fonction `scraper` et d'enregistrer sa valeur de retour :
console.log(await scraper('https://webscrapingapi.com/'))
Mais n'oubliez pas que notre objectif est d'extraire des données lors de l'envoi d'un formulaire. Cela signifie que nous devons trouver un moyen d'envoyer le formulaire avec Puppeteer. Heureusement, je l'ai déjà fait et je sais que ce n'est pas difficile. Voyons donc comment vous pouvez vous y prendre vous aussi.
Comment envoyer des formulaires avec Puppeteer
Considérez Puppeteer comme un moyen d’imiter le comportement humain sur un site web donné. Comment nous, les humains, soumettons-nous des formulaires ? Eh bien, nous identifions le formulaire, le remplissons et cliquons généralement sur un bouton. C'est la même logique qui est utilisée pour soumettre des formulaires avec Puppeteer. La seule différence réside dans la manière dont nous effectuons ces actions. En effet, les humains s'appuient sur leurs sens. Comme Puppeteer est un logiciel, nous allons le faire par programmation, en utilisant les méthodes intégrées de Puppeteer, comme ceci :
#1 : Soumettre des formulaires simples avec Puppeteer
Tout d’abord, nous devons « visualiser » notre formulaire. Sur un site web, tous les éléments sont regroupés dans un bloc HTML et chaque élément possède un identifiant. Les identifiants sont généralement constitués des attributs CSS de l’élément. Cependant, vous pouvez rencontrer des sites web qui ne disposent pas de tels sélecteurs. Dans ce cas, vous pouvez utiliser des xPaths, par exemple. Mais c’est un sujet pour une autre discussion. Concentrons-nous sur l’identification des éléments dans Puppeteer à l’aide du CSS.
Pour vous donner un peu de contexte, imaginons que nous souhaitions automatiser la connexion sur Stack Overflow. La cible est donc https://stackoverflow.com/users/login. Ouvrez votre navigateur, rendez-vous sur la page de connexion et ouvrez les Outils de développement. Vous pouvez cliquer avec le bouton droit sur la page et sélectionner « Inspecter ». Vous devriez voir quelque chose comme ceci :
À gauche, vous trouverez une interface graphique. À droite, la structure HTML. Si vous regardez attentivement à droite, vous verrez notre formulaire. Il se compose principalement de deux champs de saisie et d’un bouton. Ce sont les trois éléments que nous ciblons. Et comme vous pouvez le constater, ces trois éléments possèdent un `id` servant d’identifiant CSS. Traduisons maintenant ce que nous avons appris jusqu’ici en code :
import puppeteer, { executablePath } from 'puppeteer'
const scraper = async (target) => {
const browser = await puppeteer.launch({
headless: false,
executablePath: executablePath(),
})
const page = await browser.newPage()
await page.goto(target.url,{waitUntil: 'networkidle0'})
await page.type(target.username.selector, target.username.value)
await page.type(target.password.selector, target.password.value)
await page.click(target.buttonSelector)
const html = await page.content()
await browser.close()
return html
}
Afin de garantir la fonctionnalité et la réutilisabilité du code, j’ai choisi de remplacer le paramètre de ma fonction par un objet. Cet objet comprend l’URL ciblée, les sélecteurs et les valeurs des champs de saisie, ainsi que le sélecteur du bouton de soumission. Ainsi, pour exécuter le code, il suffit de créer un nouvel objet `TARGET` contenant vos données, puis de le transmettre à votre fonction `scraper` :
const TARGET = {
url: 'https://stackoverflow.com/users/login',
username: {
selector: 'input[id=email]',
value: '<YOUR_USERNAME>'
},
password: {
selector: 'input[id=password]',
value: '<YOUR_PASSWORD>'
},
buttonSelector: 'button[id=submit-button]'
}
console.log(await scraper(TARGET))#2 : Télécharger des fichiers avec Puppeteer
Parfois, l'automatisation Web nous oblige à télécharger des fichiers, plutôt que de simplement soumettre des formulaires. Si vous êtes confronté à une telle tâche et que vous devez joindre des fichiers avant de soumettre le formulaire avec Puppeteer, vous devrez utiliser la méthode `uploadFile` de Puppeteer. Pour simplifier les choses, je vous suggère de créer une nouvelle fonction pour cette action :
const upload = async (target) => {
const browser = await puppeteer.launch({
headless: false,
executablePath: executablePath(),
})
const page = await browser.newPage()
await page.goto(target.url,{waitUntil: 'networkidle0'})
const upload = await page.$(target.form.file)
await upload.uploadFile(target.file);
await page.click(target.form.submit)
await browser.close()
}
Remarquez que cette fois-ci, j'utilise `page.$` pour identifier d'abord l'élément. Ce n'est qu'ensuite que j'appelle la méthode `uploadFile`, qui ne fonctionne qu'avec les types `ElementHandle`. En ce qui concerne les paramètres, tout comme précédemment, j'utilise un objet pour transmettre toutes les données en une seule fois à ma fonction. Si vous souhaitez tester le script, ajoutez simplement le code suivant et exécutez `node index.js` dans votre terminal :
const TARGET = {
url: 'https://ps.uci.edu/~franklin/doc/file_upload.html',
form: {
file: 'input[type=file]',
submit: 'input[type=submit]'
} ,
file: './package.json'
}
upload(TARGET)Conclusions
Pour résumer, je dirais qu’il est assez facile de soumettre le formulaire avec Puppeteer. De plus, je trouve que, comparé à ses alternatives, Puppeteer gère parfaitement cette action. En gros, tout ce que l’utilisateur a à faire, c’est d’identifier correctement les éléments.
Je tiens toutefois à préciser qu’un scraper en situation réelle nécessite bien plus pour être efficace. La plupart du temps, si vous « abusez » d’un serveur en soumettant trop de formulaires en peu de temps, vous risquez fort d’être bloqué. C’est pourquoi, si vous souhaitez automatiser le processus de soumission de formulaires, je vous recommande d’utiliser un service de scraping professionnel. Chez Web Scraping API, nous proposons la possibilité d'envoyer des requêtes POST et PUT. Vous pouvez en savoir plus à ce sujet dans notre documentation.




