Retour au blog
Guides
Mihnea-Octavian ManolacheLast updated on May 12, 202613 min read

Comment construire un scraper web avec Pyppeteer (Guide 2026)

Comment construire un scraper web avec Pyppeteer (Guide 2026)
En bref : Pyppeteer est le portage Python non officiel de Puppeteer et permet toujours de piloter un véritable navigateur Chromium à partir de asyncio. Dans ce guide, vous allez l'installer, puis écrire un scraper web moderne avec Pyppeteer en utilisant asyncio.run et try/finally, gérer les délais d'attente, les formulaires, les captures d'écran, le défilement infini, les cookies et les proxys, et découvrir quand migrer vers Playwright, Selenium ou une API de scraping hébergée.

Si vous avez dépassé requests et de BeautifulSoup parce que les données dont vous avez besoin n'apparaissent qu'après l'exécution de JavaScript, vous avez probablement déjà envisagé de créer un scraper web avec Pyppeteer. Pyppeteer est le portage Python de Puppeteer, et il vous permet de lancer une véritable instance de Chromium, d'attendre des sélecteurs, de cliquer sur des boutons et d'exécuter du code JavaScript arbitraire à l'intérieur de la page à partir de async code Python. Cela suffit pour scraper des applications à page unique, des flux à défilement infini, des interfaces de recherche et tout ce qui se cache derrière un fetch appel.

Ce guide s’adresse aux développeurs Python de niveau intermédiaire en 2026. Nous aborderons un état des lieux honnête du projet, une comparaison avec Selenium, Playwright et Node Puppeteer, les modèles asynchrones modernes (asyncio.run, try/finally, les attentes structurées), ainsi qu’un exemple complet de bout en bout qui parcourt plusieurs mots-clés sur une interface de recherche pilotée par JavaScript. À la fin, vous disposerez d’un modèle de scraper Pyppeteer fonctionnel ainsi que d’un cadre décisionnel clair pour déterminer quand Pyppeteer est l’outil approprié et quand il ne l’est pas.

Pyppeteer en 2026 : où l'utiliser et ce qui a changé

Pyppeteer est, à la base, un wrapper Python qui reflète l'API de Puppeteer : launch un navigateur, ouvrir une page, appeler waitForSelector, exécuter evaluate, répéter. Le modèle mental correspond exactement au projet Puppeteer original sur GitHub, ce qui est utile si vous avez déjà lu un tutoriel Node et que vous souhaitez rester en Python.

La mise en garde honnête pour 2026 est que Pyppeteer ne fait l'objet que d'une maintenance minimale. Les responsables indiquent dans le fichier README du projet qu'il est maintenu de manière minimale, et plusieurs fonctionnalités récentes de Puppeteer n'ont jamais été portées. Cela ne signifie pas que votre scraper cessera de fonctionner demain, mais cela signifie que vous ne devriez pas choisir Pyppeteer pour un système de production à long terme sans envisager Playwright et une API de scraping gérée comme alternatives. Nous reviendrons sur ce choix à la fin.

Pyppeteer vs Selenium, Playwright et Puppeteer

Avant de vous engager, il est utile de comparer Pyppeteer à ses alternatives les plus proches. Le tableau ci-dessous est un aide-mémoire rapide qui vous permettra de choisir l'outil adapté à votre pile plutôt que de vous contenter de la première option qui apparaît sur Google.

Outil

Langage

Modèle asynchrone

Navigateurs

Options de furtivité

Maintenance

Pyppeteer

Python

Natif asyncio

Chromium

Manuel, pas de plugin natif

Maintenance minimale

Playwright (Python)

Python

Sync + asyncio

Chromium, Firefox, WebKit

Paramètres par défaut intégrés favorisant la discrétion

Développé activement par Microsoft

Selenium

Python (et autres)

Synchronisation (asynchrone via des wrappers)

Chromium, Firefox, Edge, Safari

selenium-stealth, pilotes non détectés

Maintenu activement, mature

Puppeteer (Node)

JavaScript / TypeScript

Promesses natives

Chromium, Firefox (expérimental)

puppeteer-extra-plugin-stealth

Développé activement par l'équipe Chrome

Conseil pratique : optez pour Puppeteer sous Node si vous recherchez les fonctionnalités les plus récentes, Playwright pour les nouveaux projets Python nécessitant un scraping stable sur tous les navigateurs, Selenium lorsque vous devez prendre en charge Safari ou des flux de type IE hérités, et Pyppeteer lorsqu'un petit script Python ou une base de code existante est déjà en place asyncio. Pour une comparaison plus large, consultez nos résumés sur les bibliothèques de navigateurs headless Python et les alternatives à Puppeteer.

Configuration de Pyppeteer (corrections pour Python, Chromium et M1/M2)

Utilisez Python 3.10 ou une version plus récente et un environnement virtuel. Avec uv, l'installation se fait en une seule ligne :

uv init pyppeteer-demo && cd pyppeteer-demo
uv add pyppeteer
uv run pyppeteer-install   # downloads bundled Chromium

Si vous préférez le mode pip, remplacez par python -m venv .venv && pip install pyppeteer && pyppeteer-install. Lors de la première exécution, Pyppeteer peut télécharger une version intégrée de Chromium (environ 150 Mo au moment de la rédaction de cet article, vérifiez donc les dernières notes de mise à jour avant de l'utiliser). Pour ignorer ce téléchargement et utiliser Chromium système, définissez PYPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 et passez executablePath à launch:

# macOS:  /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
# Linux:  /usr/bin/google-chrome
# Windows: C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe
await launch(executablePath='/usr/bin/google-chrome', headless=True)

Piège sur les Mac M1/M2 : Pyppeteer peut se montrer capricieux sur arm64. Si Chromium refuse de se lancer ou plante immédiatement, relancez votre terminal sous Rosetta et l'installation se termine généralement sans problème.

Créer un scraper web minimal avec Pyppeteer : un modèle moderne

Voici un modèle de base réutilisable pour un scraper web avec Pyppeteer qui utilise asyncio.run, encapsule le navigateur dans try/finally, et transmet le code HTML rendu à BeautifulSoup. Nous allons extraire quotes.toscrape.com/js/, une page sandbox qui affiche des citations via JavaScript, de sorte que les clients HTTP simples voient une page vide <body>.

import asyncio
from bs4 import BeautifulSoup
from pyppeteer import launch

URL = 'https://quotes.toscrape.com/js/'

async def scrape() -> list[dict]:
    browser = await launch(headless=True, args=['--no-sandbox'])
    try:
        page = await browser.newPage()
        await page.goto(URL, {'waitUntil': 'networkidle2'})
        await page.waitForSelector('.quote')
        html = await page.content()
        soup = BeautifulSoup(html, 'html.parser')
        return [
            {
                'text': q.select_one('.text').get_text(strip=True),
                'author': q.select_one('.author').get_text(strip=True),
            }
            for q in soup.select('.quote')
        ]
    finally:
        await browser.close()

if __name__ == '__main__':
    for row in asyncio.run(scrape()):
        print(row)

Trois éléments sont importants ici. asyncio.run remplace l'ancien get_event_loop().run_until_complete modèle que l'on trouve encore dans les anciens tutoriels. try/finally garantit la fermeture de Chromium même si votre code lève une exception. Et waitForSelector constitue le point de synchronisation explicite, et non un sleep qui fait perdre du temps sur les pages rapides et expire sur les pages lentes.

Attendre les éléments de la bonne manière

Pyppeteer propose plusieurs méthodes d'attente, et le choix est important. waitFor() est vague et source d'erreurs car il attend que « quelque chose » se produise, tandis que waitForSelector() est explicite et ne se résout que lorsque le nœud cible existe dans le DOM. Optez pour waitForNavigation après une soumission, et utilisez waitUntil='networkidle2' lorsque la page effectue des appels en arrière-plan fetch . En dernier recours, vous pouvez appeler page.waitFor(5000) pour marquer une pause de cinq secondes, mais ne recourez à une attente de durée fixe qu’en dernier recours, car c’est la principale source de scrapers instables.

Cliquer, saisir du texte et soumettre des formulaires

Pour des interactions plus riches, combinez page.click, page.type (avec un petit delay pour un rendu plus naturel), et page.keyboard.press. Après avoir soumis un formulaire, attendez la navigation en parallèle du clic afin de ne pas manquer le changement d'URL :

await page.type('input[name="q"]', 'pyppeteer', {'delay': 80})
await asyncio.gather(
    page.waitForNavigation({'waitUntil': 'networkidle2'}),
    page.keyboard.press('Enter'),
)

Ce modèle fonctionne pour les formulaires de connexion, les barres de recherche et toute interface utilisateur où une requête POST déclenche une redirection.

Les captures d'écran et les exportations au format PDF

page.screenshot() capture la fenêtre d'affichage visible par défaut. Passez fullPage=True pour des captures de haut en bas, et appelez setViewport first si vous souhaitez une résolution spécifique. Les PDF proviennent de page.pdf() et fonctionnent mieux sur les pages avec des styles d'impression épurés :

await page.setViewport({'width': 1440, 'height': 900})
await page.screenshot({'path': 'page.png', 'fullPage': True})
await page.pdf({
    'path': 'page.pdf',
    'format': 'A4',
    'printBackground': True,
    'margin': {'top': '20mm', 'bottom': '20mm', 'left': '15mm', 'right': '15mm'},
})

Gestion du défilement infini et du chargement différé

Les pages à défilement infini n'affichent le lot suivant que lorsque vous faites défiler la fenêtre d'affichage vers le bas. Utilisez page.evaluate pour exécuter une petite boucle JS qui surveille document.body.scrollHeight et s'arrête lorsqu'il cesse de s'agrandir :

await page.evaluate('''async () => {
  await new Promise(resolve => {
    let last = 0;
    const timer = setInterval(() => {
      window.scrollBy(0, 800);
      const h = document.body.scrollHeight;
      if (h === last) { clearInterval(timer); resolve(); }
      last = h;
    }, 400);
  });
}''')

Limitez la boucle avec un nombre maximal d'itérations si le flux est véritablement infini.

Gestion des cookies, des sessions et des user agents

Pour les pages nécessitant une connexion, connectez-vous une seule fois, enregistrez les cookies et réutilisez-les lors de la prochaine exécution afin de ne pas déclencher de nouvelles demandes d'authentification :

cookies = await page.cookies()          # save somewhere safe
await page.setCookie(*saved_cookies)    # restore later
await page.setUserAgent('Mozilla/5.0 ... Chrome/124 Safari/537.36')
await page.setViewport({'width': 1366, 'height': 768})

Associez setUserAgent avec un setViewport afin que l'empreinte digitale de l'appareil reste cohérente en interne. Un agent utilisateur de bureau avec une fenêtre d'affichage de 320 pixels est un indice classique permettant de détecter les bots.

Scraper web de bout en bout avec Pyppeteer : scraper une interface de recherche pilotée par JavaScript

Rassemblons tous ces éléments. Le script ci-dessous parcourt plusieurs mots-clés, saisit chacun d'entre eux dans une barre de recherche qui affiche les résultats côté client, attend que les fiches de résultats apparaissent, extrait leurs titres avec querySelectorAllEval, puis efface le champ de saisie avant le mot-clé suivant. Remplacez l'URL et les sélecteurs pour les adapter à votre cible réelle.

import asyncio
from pyppeteer import launch

KEYWORDS = ['python', 'pyppeteer', 'asyncio']
SEARCH_URL = 'https://example.com/search'   # JS-rendered UI

async def search_one(page, keyword: str) -> list[str]:
    await page.click('input[name="q"]', {'clickCount': 3})
    await page.keyboard.press('Backspace')
    await page.type('input[name="q"]', keyword, {'delay': 60})
    await page.keyboard.press('Enter')
    await page.waitForSelector('.result-card', {'timeout': 10000})
    return await page.querySelectorAllEval(
        '.result-card h3',
        '(nodes) => nodes.map(n => n.innerText.trim())',
    )

async def main():
    browser = await launch(headless=True, args=['--no-sandbox'])
    try:
        page = await browser.newPage()
        await page.goto(SEARCH_URL, {'waitUntil': 'networkidle2'})
        results = {}
        for kw in KEYWORDS:
            results[kw] = await search_one(page, kw)
            await asyncio.sleep(2)   # be polite
        return results
    finally:
        await browser.close()

if __name__ == '__main__':
    print(asyncio.run(main()))

Ce modèle offre deux avantages. Premièrement, vous réutilisez un seul navigateur et une seule page pour tous les mots-clés, ce qui réduit les coûts d'exécution. Deuxièmement, l'utilisation explicite de waitForSelector rend le scraper résistant aux fluctuations du réseau, de sorte que le processus ne s'effondre pas dès qu'une requête prend 600 ms au lieu de 200 ms. À partir de là, l'ajout de tentatives de réessai et de concurrence avec asyncio.gather constitue une étape naturelle.

Utilisation de proxys et de rotation avec Pyppeteer

Pyppeteer gère à merveille l'automatisation du navigateur, mais ne gère pas les proxys de lui-même ; vous devez donc les configurer au lancement. Le --proxy-server indicateur Chromium accepte un seul point de terminaison, et page.authenticate ajoute les identifiants avant la première requête :

import random
from pyppeteer import launch

PROXIES = [
    'http://user:pass@proxy-a.example.com:8000',
    'http://user:pass@proxy-b.example.com:8000',
    'http://user:pass@proxy-c.example.com:8000',
]

async def launch_with_proxy():
    proxy = random.choice(PROXIES)   # naive rotation
    host = proxy.split('@')[-1]
    browser = await launch(args=[f'--proxy-server=http://{host}'])
    page = await browser.newPage()
    await page.authenticate({'username': 'user', 'password': 'pass'})
    return browser, page

Même avec un proxy propre, vous finirez par atteindre les limites de débit ; il faut donc effectuer une rotation par session ou par mot-clé. Pour un modèle plus approfondi, consultez notre guide de rotation des proxys en Python. Si la gestion des pools vous semble fastidieuse, un produit de proxys résidentiels gérés, ou une API au niveau des requêtes comme la WebScrapingAPI Scraper API, vous déchargera de ce travail.

Liste de contrôle pour la furtivité et l'hygiène des empreintes

Pyppeteer est livré sans plugin de furtivité natif, vous devez donc renforcer la sécurité du navigateur vous-même. Liste de contrôle minimale :

  • Définissez un user agent de bureau réaliste et à jour avec page.setUserAgent.
  • Associez-le à une fenêtre d'affichage plausible via page.setViewport (1366x768 ou 1440x900 sont des valeurs par défaut sûres).
  • Appliquez le navigator.webdriver indicateur dans un evaluateOnNewDocument hook afin qu'il renvoie undefined au lieu de true.
  • Veillez à la bonne gestion des cookies : effacez-les entre les sessions ou alternez les sessions lorsque vous changez d'adresse IP.
  • Faites tourner les adresses IP via des proxys résidentiels ou mobiles pour toute cible dotée de défenses anti-bots sérieuses.
  • Limitez les requêtes et humanisez le timing avec delay sur type et de petits asyncio.sleep intervalles entre les actions.

Meilleures pratiques de niveau production pour 2026

Si vous souhaitez créer un scraper web avec Pyppeteer capable de fonctionner selon un calendrier réel, appliquez ces règles :

  • Exécutez le point d'entrée avec asyncio.run(main()). Oubliez get_event_loop() et loop.run_until_complete(); la fonction moderne est plus propre et moins sujette aux bugs.
  • Enveloppez chaque navigateur dans try/finally afin que le processus Chromium soit tué même lorsque votre code lève une exception. Les navigateurs qui fuient sont la cause numéro un des runners CI bloqués.
  • Préférez waitForSelector (explicite) à waitFor (vague). Réservez les temps de pause fixes aux délais anti-bot documentés uniquement.
  • Limitez poliment le débit. Respectez robots.txt, limitez-vous aux données publiques et ajoutez de la gigue afin que les 100 requêtes n'arrivent pas en 100 millisecondes.
  • Ajoutez une journalisation structurée (une ligne JSON par page) et enregistrez l'URL, le statut, le temps de réponse et le nombre de correspondances de sélecteurs. Vous vous en féliciterez la première fois qu'un site cible modifiera son code HTML.

Quand Pyppeteer n'est pas l'outil adéquat (et quoi utiliser à la place)

Pyppeteer est idéal pour les scripts ponctuels, l'automatisation interne et les petites bases de code Python qui utilisent déjà asyncio. Il commence à montrer ses limites dès que vous avez besoin d'une couverture multi-navigateurs, de nouvelles fonctionnalités CDP, d'un mode furtif officiel ou d'une concurrence à grande échelle. Utilisez cette règle de décision approximative :

  • Restez avec Pyppeteer pour les prototypes, les scrapers de week-end et les scripts traitant moins de quelques centaines de pages par jour.
  • Passez à Playwright (Python) lorsque vous avez besoin de Firefox ou de WebKit, d’une attente automatique robuste ou d’un traçage de premier ordre.
  • Passez à Selenium si vous devez prendre en charge Safari ou vous connecter à une grille de test existante.
  • Utilisez une API de scraping hébergée lorsque vous passez plus de temps sur la rotation des proxys, les CAPTCHA et l'infrastructure headless que sur les données proprement dites.

Points clés

  • Pyppeteer est le portage Python de Puppeteer, peu maintenu ; il fonctionnera encore en 2026 pour asyncio, mais ce n’est pas le bon choix pour les systèmes de production à long terme sans plan de secours.
  • Utilisez asyncio.run, try/finallyet waitForSelector à la place de l'ancienne boucle d'événements et des waitFor modèles présentés dans des tutoriels obsolètes.
  • Un scraper web complet avec Pyppeteer prend en charge les délais d'attente, la saisie de formulaires, les captures d'écran, les PDF, le défilement infini, la réutilisation des cookies et les proxys, et pas seulement goto.
  • Il n'existe pas de plugin de furtivité natif ; l'agent utilisateur, la fenêtre d'affichage, navigator.webdriver, l'hygiène des cookies et la rotation des adresses IP relèvent de votre responsabilité.
  • Optez pour Playwright, Selenium ou une API de scraping gérée dès que votre scraper dépasse les capacités d’une seule machine, d’un seul navigateur ou d’un seul proxy.

FAQ

Pyppeteer est-il toujours maintenu et peut-il être utilisé en toute sécurité en 2026 ?

Pas vraiment. Les responsables indiquent explicitement dans le fichier README du projet sur GitHub que Pyppeteer ne fait l'objet que d'une maintenance minimale et que les nouvelles fonctionnalités de Puppeteer y sont rarement portées. Il fonctionne toujours et permet toujours de scraper, mais pour un système de production à long terme, vous devriez évaluer Playwright (Python) ou une API de scraping hébergée comme alternative développée plus activement avant de vous engager.

Quelle est la différence entre Pyppeteer et Puppeteer ?

Puppeteer est la bibliothèque Node.js officielle de l'équipe Chrome pour l'automatisation de Chromium. Pyppeteer est un portage Python non officiel qui reproduit la plupart de l'API de Puppeteer mais utilise asyncio à la place des Promises. Pyppeteer est généralement en retard sur Puppeteer en matière de nouvelles fonctionnalités, et certaines API de Puppeteer sont totalement absentes ; les écosystèmes sont donc similaires dans leur structure mais pas dans leur étendue.

Dois-je choisir Pyppeteer, Playwright ou Selenium pour un nouveau projet de scraping en Python ?

Pour un nouveau projet en 2026, optez par défaut pour Playwright en Python. Il est activement développé, prend en charge Chromium, Firefox et WebKit, et intègre une fonctionnalité d'attente automatique qui élimine une grande partie des instabilités. Choisissez Selenium si vous avez besoin de Safari ou d'une grille de test existante. Ne choisissez Pyppeteer que si vous étendez un script existant qui l'utilise déjà.

Pyppeteer peut-il contourner Cloudflare, la détection de bots ou les CAPTCHA de lui-même ?

Non. Pyppeteer est livré sans plugin de furtivité et ne dispose pas de solveur de CAPTCHA intégré. Vous pouvez réduire votre empreinte numérique manuellement en configurant un agent utilisateur réaliste, en modifiant navigator.webdriveret en alternant les adresses IP résidentielles, mais pour contourner de manière fiable les défis posés par les versions modernes de Cloudflare ou hCaptcha, il faut généralement un framework renforcé ou une API de scraping au niveau de la requête qui gère le déblocage à votre place.

Pourquoi mon script Pyppeteer plante-t-il sur les Mac M1 ou M2 ?

Le Chromium fourni est sensible à Apple Silicon. La solution la plus courante consiste à relancer votre terminal sous Rosetta et à réexécuter pyppeteer-install, ce qui permet à la version x86_64 de Chromium de s’installer et de démarrer correctement. Sinon, définissez PYPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 et pointez executablePath vers une arm64version native de Google Chrome que vous avez déjà installée.

Conclusion

Construire un scraper web avec Pyppeteer en 2026 reste un choix raisonnable lorsque vous recherchez un petit script Python compatible avec l'asynchronisme qui pilote un véritable Chromium. Vous disposez d'un modèle de départ fonctionnel, de modèles pour les délais d'attente, les formulaires, les captures d'écran, le défilement infini, les cookies et les proxys, ainsi que d'une liste de contrôle pour la discrétion et une idée claire du moment où passer à Playwright, Selenium ou une alternative gérée.

En conclusion : le statut de Pyppeteer, peu maintenu, signifie que vous devriez le considérer comme un outil tactique plutôt que comme une plateforme à long terme. Intégrez votre navigateur dans try/finally, privilégiez waitForSelector aux temps d'attente fixes, et prévoyez un budget pour une migration le jour où un site cible mettra à jour ses défenses anti-bots plus rapidement que Pyppeteer ne portera la prochaine fonctionnalité CDP.

Si la rotation des proxys, les CAPTCHA ou les mises à jour de Chromium commencent à prendre plus de temps que le scraping lui-même, confiez la couche de requêtes à l'API Scraper de WebScrapingAPI et concentrez votre code Pyppeteer sur l'analyse des données qui vous intéressent réellement.

À 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.