Le web scraping avec Puppeteer

Découvrez comment faire du web scraping avec Puppeteer sur des sites statiques et dynamiques dans ce guide détaillé.
10 min read
web scraping with puppeteer

Puppeteer is a browser testing and automation library that’s also nice for web scraping. In comparison to simpler tools like Axios and cheerio, Puppeteer enables developers to scrape dynamic content (ie content that changes based on user actions).

Cela signifie que vous pouvez l’utiliser pour extraire des données sur des applications web (applications monopages) qui chargent leur contenu en utilisant JavaScript, ce qui est exactement ce que vous allez faire ici.

Web Scraping Using Puppeteer

In this tutorial, you’ll learn how to scrape static and dynamic data (ie post titles and links from Bright Data’s Blog) with Puppeteer.

Setting Up

Before you begin the tutorial, you need to make sure that you have Node.js installed on your computer. You can download it from their official Downloads page.

Créez ensuite un nouveau répertoire pour le projet et accédez à celui-ci à l’aide des commandes suivantes :

mkdir puppeteer_tutorial 
cd puppeteer_tutorial 
npm init -y 

Ensuite, installez Puppeteer à l’aide de la commande suivante :

npm i puppeteer --save

Cette commande permet également de télécharger un navigateur dédié que la bibliothèque utilisera.

Scraping a Static Site

Comme tous les outils de web scraping, Puppeteer vous permet d’extraire le code HTML des pages web.

Voici les étapes que vous pouvez suivre pour collecter des données sur la première page de posts du blog de Bright Data avec Puppeteer :

Create an index.js file and import Puppeteer:

const puppeteer = require('puppeteer');

Insérez ensuite le code standard nécessaire pour exécuter Puppeteer :

(async () => {
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: null
  });

  const page = await browser.newPage();
  await page.goto('https://brightdata.com/blog');

  // all the web scraping will happen here  

  await browser.close();

})();

Cette fonction ouvre un navigateur, accède à la page pour y collecter des données, puis ferme le navigateur.

Il ne vous reste plus qu’à extraire les données de la page.

In Puppeteer, the easiest way to access HTML data is through the page.evaluate method. While Puppeteer has $ and $$ methods, which are wrappers useful for fetching elements, it’s simpler to just get all the data from page.evaluate.

On the Bright Data blog, all blog post data is wrapped in an <a> tag with the class of brd_post_entry. The title of the post is in an <h3> element with the class of brd_post_title. The link to the post is the href value of the brd_post_entry.

Here’s what a page.evaluate function that extracts those values looks like:

  const data = await page.evaluate( () => {

    let data = [];
    const titles = document.querySelectorAll('.brd_post_entry');

    for (const title of titles) {
      const titleText = title.querySelector('.brd_post_title').textContent;
      const titleLink = title.href;

      const article = { title: titleText, link: titleLink };
      data.push(article);
    }

    return data;

  })

Enfin, vous pouvez afficher les données sur la console :

  console.log(data);

Le script complet se présente comme suit :

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: null
  });

  const page = await browser.newPage();
  await page.goto('https://brightdata.com/blog');

  const data = await page.evaluate(() => {

    let data = [];
    const titles = document.querySelectorAll('.brd_post_entry');

    for (const title of titles) {
      const titleText = title.querySelector('.brd_post_title').textContent;
      const titleLink = title.href;

      const article = { title: titleText, link: titleLink };
      data.push(article);
    }

    return data;

  })

  console.log(data);

  await browser.close();

})();

Run it by calling node index.js in the terminal. The script should return a list of post titles and links:

[
  {
    title: 'APIs for Dummies: Learning About APIs',
    link: 'https://brightdata.com/blog/web-data/apis-for-dummies'
  },
  {
    title: 'Guide to Using cURL with Python',
    link: 'https://brightdata.com/blog/how-tos/curl-with-python'
  },
  {
    title: 'Guide to Scraping Walmart',
    link: 'https://brightdata.com/blog/how-tos/guide-to-scraping-walmart'
  },
…

Scraping Dynamic Content

Extraire un contenu statique est une tâche simple qui peut être facilement mise en œuvre avec des outils élémentaires. Heureusement, Puppeteer peut être utilisé pour effectuer toutes sortes d’actions – clic, saisie, défilement, etc. Vous pouvez utiliser toutes ces fonctionnalités pour interagir avec des pages dynamiques et simuler les actions d’un utilisateur.

Une tâche courante de scraping Web pouvant être effectuée avec une telle bibliothèque consiste à rechercher un certain ensemble de données sur la page. Par exemple, vous pouvez utiliser Puppeteer pour rechercher tous les posts de Bright Data qui parlent de Puppeteer.

Voici comment vous pouvez faire :

Step 1: Accept Cookies

Si vous visitez le blog de Bright Data, vous verrez parfois apparaître une bannière de cookies :

To deal with that, you need to click on the Accept all button with the following code:

  await page.waitForSelector('#brd_cookies_bar_accept', {timeout: 5000})
    .then(element => element.click())
    .catch(error => console.log(error));

The first line of the code waits for an item with the #brd_cookies_bar_accept to appear for 5 seconds. The second line clicks on that element. The third line makes sure that the script doesn’t crash if the cookie bar doesn’t appear.

Notez que pour implémenter une attente avec Puppeteer, vous devez fournir une condition dont vous voulez attendre la réalisation, et non en définissant un temps d’attente donné pour l’exécution de l’action considérée. Le premier type d’attente est appelé attente implicite, et le second type d’attente est appelé attente explicite.

L’attente explicite est fortement découragée dans Puppeteer, car cela entraîne des problèmes d’exécution. Si vous fournissez un temps d’attente explicite, il sera immanquablement trop long (ce qui est inefficace) ou trop court (ce qui signifie que votre script ne s’exécutera pas correctement).

Step 2: Search for Posts

Par la suite, le script doit faire en sorte de cliquer sur l’icône de recherche. Saisissez « Puppeteer » et appuyez de nouveau sur l’icône de recherche pour lancer une recherche :

Cela peut être réalisé avec le code suivant :


await page.click('.search_icon');

  await page.waitForSelector('.search_container.active');
  const search_form = await page.waitForSelector('#blog_search');
  await search_form.type('puppeteer');

 await page.click('.search_icon');

  await new Promise(r => setTimeout(r, 2000));

This example works similarly to the cookie banner example. After clicking the button, you need to wait until the search container appears, which is why the code waits for an element that matches the CSS selector of .search_container.active.

En outre, à la fin, vous devez ajouter un arrêt de deux secondes pour le chargement des éléments. Bien que les attentes explicites soient déconseillées avec Puppeteer, nous n’avons pas de meilleure option dans le cas présent.

In most websites, if a change in the URL happens, you can use the waitForNavigation method. If a new element appears, you can use the waitForSelector method. Figuring out if some elements are refreshed is a bit more difficult and out of scope for this article.

If you want to try it on your own, this Stack Overflow answer can be of help.

Step 3: Collect the Posts

Une fois que vous avez trouvé les posts, vous pouvez utiliser le code que vous avez utilisé pour le scraping de pages statiques pour obtenir les titres des posts du blog :

  const data = await page.evaluate( () => {

    let data = [];
    const titles = document.querySelectorAll('.brd_post_entry');

    for (const title of titles) {
      const titleText = title.querySelector('.brd_post_title').textContent;
      const titleLink = title.href;

      const article = { title: titleText, link: titleLink };
      data.push(article);
    }

    return data;

  })

  console.log(data);

Voici le code complet du script :

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: null
  });

  const page = await browser.newPage();
  await page.goto('https://brightdata.com/blog');

  const cookie_bar_accept = await page.waitForSelector('#brd_cookies_bar_accept');
  await cookie_bar_accept.click();
  await new Promise(r => setTimeout(r, 500));

  await page.click('.search_icon');

  await page.waitForSelector('.search_container.active');
  const search_form = await page.waitForSelector('#blog_search');
  await search_form.type('puppeteer');

  await page.click('.search_icon');

  await new Promise(r => setTimeout(r, 2000));

  const data = await page.evaluate( () => {

    let data = [];
    const titles = document.querySelectorAll('.brd_post_entry');

    for (const title of titles) {
      const titleText = title.querySelector('.brd_post_title').textContent;
      const titleLink = title.href;

      const article = { title: titleText, link: titleLink };
      data.push(article);
    }

    return data;

  })

  console.log(data);

  await browser.close();

})();

Can You Do Better?

Bien que l’écriture de scripts de web scraping avec Puppeteer soit possible, cela n’est pas idéal. Puppeteer est conçu pour l’automatisation des tests, ce qui le rend peu pratique pour le web scraping.

For example, if you want to achieve scale and efficiency in your scripts, it’s important to be able to scrape without being blocked. To do this, you can use proxies—gateways between you and the website you scrape. While Puppeteer supports the use of proxies, you need to find and contract with a proxy network on your own (learn more about Puppeteer proxy integration with Bright Data).

En outre, il n’est pas facile d’optimiser Puppeteer pour une utilisation en parallèle. Si vous voulez collecter de gros volumes de données, vous devrez travailler dur pour obtenir des performances optimales.

Ces difficultés impliquent que Puppeteer est un bon choix pour l’écriture de petits scripts en temps qu’amateur, mais qu’il vous faudra travailler pas mal de temps avant de réussir à effectuer des opérations sur de gros volumes de données.

In case you want something that’s easier to use, you can pick a web data platform like Bright Data. It enables companies to gather massive amounts of structured data from the web using easy-to-use tools, like the Scraping Browser (Puppeteer/Playwright compatible), that’s specially made for scraping.

Conclusion

Dans cet article, vous avez appris à utiliser Puppeteer pour faire du web scraping sur des pages web statiques et dynamiques.

Puppeteer peut effectuer la plupart des actions qu’un navigateur peut réaliser – clics sur des éléments, saisies de texte et exécutions de code en JavaScript. Et grâce à l’utilisation des attentes implicites, les scripts Puppeteer peuvent être écrits rapidement et facilement.

Mais il peut également y avoir quelques difficultés – Puppeteer n’est pas l’outil le plus efficace pour le web scraping et sa documentation est complexe pour les novices. Il est également difficile de faire du web scraping sur de gros volumes de données à l’aide de Puppeteer si vous n’êtes pas déjà un spécialiste.

Tired of scraping data yourself? Get precollected or custom datasets.