Le web scraping avec Playwright est devenu le choix par défaut pour quiconque a besoin d'extraire des données de pages qui ne s'assemblent qu'après l'exécution du JavaScript. Développé par Microsoft, Playwright pilote un vrai navigateur, attend le contenu comme le ferait une personne et expose une API cohérente sur Chromium, Firefox et WebKit. Cette combinaison le rend bien moins fragile que les anciens outils d'automatisation sur lesquels la plupart des scrapers ont démarré.
Ce guide est un tutoriel pratique sur le web scraping avec Playwright en Python, avec une courte note Node là où l'API diffère. Vous installerez Playwright et ses navigateurs, lancerez Chromium en mode headless, naviguerez vers une page, attendrez le bon sélecteur, extrairez du texte et des attributs, gérerez une interaction « charger plus » et la pagination, prendrez une capture d'écran et capturerez une réponse réseau JSON. Nous concluons avec la réalité opérationnelle honnête : Playwright est toujours bloqué à grande échelle, et là où un service de rendu et de rotation géré mérite sa place.
Pourquoi Playwright plutôt que les anciens outils d'automatisation
Si vous avez écrit des scrapers avec Selenium ou Puppeteer brut, la première chose que vous remarquez dans Playwright est que les appels sleep() fragiles disparaissent. Quelques décisions de conception en sont responsables.
- Auto-attente. Avant que Playwright clique, remplisse ou lise un élément, il attend que cet élément soit attaché, visible, stable et actionnable. Vous arrêtez de saupoudrer des délais arbitraires dans votre code, et les scrapers qui en résultent sont nettement plus fiables sur les pages lentes ou animées.
- Trois moteurs de navigateur, une seule API. Le même script s'exécute contre Chromium, Firefox ou WebKit. Lorsqu'un site se comporte différemment dans un moteur, vous changez avec une modification d'un seul mot au lieu de réécrire toute la configuration de votre driver.
- Sélecteurs robustes. Au-delà de CSS et XPath, Playwright fournit des locators et des sélecteurs de texte qui se résolvent paresseusement et requêtent à nouveau le DOM au moment de l'action, de sorte qu'ils survivent aux re-rendus qui briseraient un handle d'élément mis en cache.
- Asynchrone par conception. L'API est construite autour des I/O asynchrones, ce qui rend naturel d'exécuter de nombreuses pages en parallèle dans un seul processus de navigateur lorsque vous montez en charge.
Pour un contexte sur pourquoi un vrai navigateur est parfois inévitable, consultez les navigateurs headless pour le web scraping. Si vous avez une pile Selenium existante et souhaitez une comparaison côte à côte, le scraping de contenu dynamique avec Selenium et BeautifulSoup couvre cette voie.
Prérequis
Vous avez besoin de trois choses avant d'écrire du code, et aucune ne prend longtemps.
Python 3.8 ou version ultérieure. Confirmez votre version avec python --version. Playwright dispose également d'un binding Node.js de première classe si vous préférez JavaScript ; les concepts de ce guide se correspondent un à un, et un court exemple Node apparaît plus loin.
Confort avec les sélecteurs. Vous devez être capable d'ouvrir les outils de développement de votre navigateur, d'inspecter un élément et de lire un sélecteur CSS. L'extraction est principalement un exercice de sélecteur une fois que la page a été rendue.
Une cible que vous êtes autorisé à scraper. Utilisez un site dont les conditions le permettent, limitez-vous aux données publiques et respectez robots.txt et des limites de débit raisonnables. Les techniques ici sont générales ; la responsabilité de l'endroit où vous les pointez est la vôtre.
Installer Playwright et ses navigateurs
Créez un environnement virtuel pour que les dépendances restent isolées, installez le package Playwright, puis exécutez son installateur pour télécharger les binaires du navigateur. Cette deuxième étape est celle que les gens oublient ; le package pip seul ne regroupe pas les navigateurs.
python -m venv pw_env source pw_env/bin/activate pip install playwright playwright install chromium
Sur Windows, activez l'environnement avec pw_env\Scripts\activate au lieu de la ligne source. La commande playwright install chromium télécharge une version de Chromium épinglée ; passez aucun argument pour récupérer les trois moteurs. Si vous voyez une erreur à propos d'un exécutable manquant, cela signifie presque toujours que cette étape d'installation a été sautée.
Lancer un navigateur et ouvrir une page
Commencez par le script utile le plus simple : lancer Chromium en mode headless, ouvrir une page, naviguer vers une URL et lire le titre. L'API synchrone garde le premier exemple lisible ; nous passerons à l'asynchrone quand cela compte pour l'échelle.
from playwright.sync_api import sync_playwright def main(): with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page() page.goto("https://quotes.toscrape.com/js/") print(page.title()) browser.close() if __name__ == "__main__": main()
Quelques notes sur les choix ici. headless=True s'exécute sans fenêtre visible, ce que vous voulez pour les jobs non surveillés ; passez-le à False pendant le développement pour voir le navigateur travailler. L'URL choisie est une page de démonstration délibérément rendue par JavaScript : les citations n'apparaissent qu'après l'exécution d'un script, ce qui est exactement le cas où une simple requête HTTP retourne un conteneur vide et où Playwright excelle.
Pour tout ce qui va au-delà d'une utilisation ponctuelle, créez un contexte de navigateur avec browser.new_context() avant new_page(). Un contexte est une session isolée avec ses propres cookies, son stockage et son user agent, vous pouvez donc exécuter plusieurs pages indépendantes sans que leur état ne se mélange. Appeler new_page() directement, comme ci-dessus, utilise un contexte par défaut, ce qui convient pour une seule page.
Attendre un sélecteur, puis extraire texte et attributs
C'est le cœur du web scraping avec Playwright. Au lieu de deviner combien de temps la page a besoin, vous attendez l'élément spécifique qui signale que les données sont présentes, puis vous le lisez. Les locators de Playwright font l'auto-attente, donc un seul appel attend et sélectionne à la fois.
from playwright.sync_api import sync_playwright def scrape_quotes(url): with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page() page.goto(url) page.wait_for_selector("div.quote") results = [] for quote in page.query_selector_all("div.quote"): text = quote.query_selector("span.text").inner_text() author = quote.query_selector("small.author").inner_text() link = quote.query_selector("a").get_attribute("href") results.append({"text": text, "author": author, "link": link}) browser.close() return results
La ligne qui compte le plus est page.wait_for_selector("div.quote"). Elle bloque jusqu'à ce qu'au moins un élément de citation existe dans le DOM, ce qui signifie que le JavaScript s'est exécuté et que les données sont là. Après cela, query_selector_all retourne chaque élément correspondant, et inner_text() et get_attribute() extraient respectivement le texte et les attributs. La lecture du href de l'ancre montre le cas des attributs ; la lecture de la citation et de l'auteur montre le cas du texte. Pas de sleeps fixes nulle part.
Gérer les clics « charger plus » et la pagination
Les cibles réelles montrent rarement tout en même temps. Deux modèles couvrent la plupart d'entre elles : un bouton « charger plus » qui ajoute du contenu en place, et une pagination numérotée ou « suivant » qui change la page. Playwright gère les deux car il peut cliquer puis attendre le résultat.
Pour un bouton « charger plus » en place, cliquez dessus en boucle jusqu'à ce qu'il disparaisse, en attendant après chaque clic que le nouveau contenu se stabilise.
def load_all(page): while True: button = page.query_selector("button.load-more") if not button or not button.is_visible(): break button.click() page.wait_for_load_state("networkidle")
Pour la pagination classique, suivez le lien « suivant » jusqu'à ce qu'il disparaisse, en scrapant chaque page au fur et à mesure. Parce que les locators requêtent à nouveau le DOM à chaque appel, vous n'avez pas à vous inquiéter des handles périmés après la navigation.
def scrape_all_pages(page, url): page.goto(url) rows = [] while True: page.wait_for_selector("div.quote") for q in page.query_selector_all("div.quote span.text"): rows.append(q.inner_text()) next_link = page.query_selector("li.next a") if not next_link: break next_link.click() return rows
Notez wait_for_load_state("networkidle") dans le premier extrait : il attend qu'il n'y ait plus de requêtes réseau en cours pendant une courte fenêtre, un bon signal que le contenu chargé paresseusement est arrivé. Utilisez-le après des actions qui déclenchent des récupérations en arrière-plan.
Prendre une capture d'écran
Les captures d'écran sont utiles pour déboguer un scraper qui retourne des résultats vides et pour archiver l'apparence d'une page au moment de la capture. Playwright capture la fenêtre visible par défaut, ou la page entière défilable avec un seul indicateur.
page.screenshot(path="page.png", full_page=True)
Lorsqu'une exécution revient sans données, une capture d'écran pleine page prise juste avant l'extraction vous dit généralement pourquoi en quelques secondes : un mur de cookies, un CAPTCHA ou une page de blocage là où votre contenu devrait être.
Capturer les réponses réseau et JSON
Souvent, les données les plus propres ne se trouvent pas dans le HTML du tout mais dans une API JSON que la page appelle en arrière-plan. Plutôt que d'analyser le balisage rendu, vous pouvez écouter les réponses réseau et récupérer ce JSON directement. C'est plus rapide et bien moins fragile que de scraper le DOM, car la forme de l'API change moins souvent que la mise en page.
captured = [] def on_response(response): if "/api/" in response.url and response.ok: try: captured.append(response.json()) except Exception: pass page.on("response", on_response) page.goto("https://example.com/listings") page.wait_for_load_state("networkidle")
Le hook page.on("response", ...) se déclenche pour chaque réponse réseau. Filtrer par fragment d'URL isole les appels qui vous intéressent, et response.json() analyse le corps pour vous. Ouvrez d'abord l'onglet Réseau dans les outils de développement pour trouver quel endpoint transporte les données, puis faites-le correspondre ici. Si un site est riche en appels XHR de ce type, consultez comment scraper des pages JavaScript avec Python pour plus d'informations sur l'approche API-first.
Le même script en Node.js
Si votre stack est JavaScript, le binding Node reflète presque exactement celui de Python. Les noms de méthodes correspondent, tout est basé sur des promesses et vous installez les navigateurs de la même façon avec npx playwright install chromium.
const { chromium } = require("playwright"); (async () => { const browser = await chromium.launch({ headless: true }); const page = await browser.newPage(); await page.goto("https://quotes.toscrape.com/js/"); await page.waitForSelector("div.quote"); const texts = await page.$$eval("div.quote span.text", els => els.map(e => e.textContent)); console.log(texts); await browser.close(); })();
Le wait_for_selector Python devient waitForSelector, et $$eval exécute une fonction dans la page pour extraire de nombreux éléments à la fois. Choisissez le langage que votre équipe maintient déjà ; la logique de scraping est identique.
La réalité du furtivité : Playwright est toujours bloqué
Voici la partie que la plupart des tutoriels sautent. Piloter un vrai navigateur résout le rendu, mais cela ne vous rend pas invisible. Les systèmes anti-bot modernes regardent bien plus loin que le fait que JavaScript s'exécute. Ils créent une empreinte du navigateur, inspectent les signatures TLS et HTTP/2, évaluent les signaux comportementaux et limitent le débit par IP. Une exécution headless Playwright vanille laisse des traces, et à tout volume réel le problème le plus important est votre IP : une poignée d'adresses datacenter martelant le même hôte est rapidement signalée.
Vous pouvez vous battre contre cela. Les gens ajoutent des plugins de furtivité, randomisent les user agents et les viewports, ralentissent les requêtes et câblent un pool de proxies. Chacun aide, et chacun est une charge de maintenance. Faire tourner une flotte de navigateurs headless est en soi une charge opérationnelle : ils sont gourmands en mémoire, ils plantent, ils ont besoin d'une version de navigateur épinglée et les paralléliser sur plusieurs machines est un vrai travail d'infrastructure. Faire tout cela et maintenir en plus un pool de proxies rotatifs en bonne santé est, franchement, l'essentiel du travail.
Pour le playbook plus approfondi sur le fait de rester non bloqué, consultez comment scraper des sites web sans être bloqué.
Lorsque Playwright commence à subir des blocages à grande échelle, la Crawling API prend en charge la partie difficile. Elle rend la page dans un vrai navigateur et route la requête via des IPs résidentielles rotatives côté serveur, puis vous remet du HTML fini ou des données analysées en un seul appel, vous évitant ainsi d'exploiter une flotte headless et un pool de proxies vous-même. Vous pouvez toujours garder Playwright localement pour les flux interactifs qui nécessitent vraiment un driver.
Là où l'API gérée convient, et là où Playwright gagne encore
Ce n'est pas Playwright contre une API gérée ; c'est de savoir quel outil convient à quel job. Choisissez la Crawling API lorsque votre goulot d'étranglement est les blocages, les CAPTCHAs ou la réputation des IPs, lorsque vous crawlez de nombreuses pages et ne voulez pas exploiter l'infrastructure de navigateur et de proxies, ou lorsque vous avez simplement besoin de HTML rendu en retour de manière fiable et en volume. Parce que le rendu et la rotation se produisent côté serveur, vous faites une simple requête et analysez le résultat, sans flotte à surveiller.
Gardez Playwright localement lorsque la tâche est réellement interactive : formulaires multi-étapes, flux authentifiés derrière un login que vous contrôlez, glisser-déposer, téléchargements de fichiers ou tout ce qui nécessite de scripter une séquence précise d'actions utilisateur et d'observer le résultat. Les deux se composent bien. De nombreuses équipes prototypent et gèrent les flux riches en interactions avec Playwright, puis acheminent leur trafic de récupération à fort volume via l'API gérée une fois que les blocages deviennent le facteur limitant. Si vous souhaitez la rotation des IPs comme endpoint drop-in tout en gardant votre propre navigateur, le Smart AI Proxy vous donne une rotation résidentielle derrière une interface proxy standard.
Points clés
- Playwright corrige la fragilité. L'auto-attente, trois moteurs de navigateur derrière une seule API, des locators paresseux et l'asynchrone le rendent plus fiable que les anciens drivers pour les pages rendues.
-
Attendez, puis extrayez. Utilisez
wait_for_selectorpour confirmer que les données ont été rendues, puis lisez le texte avecinner_text()et les attributs avecget_attribute(). -
Cliquez et paginez nativement. Bouclez un bouton « charger plus » jusqu'à ce qu'il disparaisse, ou suivez un lien « suivant », en attendant sur
networkidleaprès les actions qui récupèrent. -
Récupérez le JSON quand vous pouvez. Écouter sur
page.on("response", ...)pour un appel d'API en arrière-plan est plus rapide et bien moins fragile que d'analyser le DOM. - Le rendu n'est pas la furtivité. Playwright est toujours pris en empreinte digitale et bloqué par IP à grande échelle ; une API de rendu et rotation gérée supprime la flotte et les frais généraux de proxies, tandis que Playwright reste idéal pour les flux interactifs locaux.
Foire aux questions
Playwright est-il bien adapté au web scraping ?
Oui. Playwright pilote un vrai navigateur, donc il gère les pages rendues par JavaScript qu'une simple requête HTTP ne peut pas traiter. Son auto-attente élimine la plupart des problèmes de timing qui affectent les anciens outils, il supporte Chromium, Firefox et WebKit via une seule API et ses locators paresseux survivent aux re-rendus. Pour les cibles interactives ou rendues côté client, c'est l'une des options les plus solides disponibles.
Devrais-je utiliser Playwright avec Python ou Node.js ?
Les deux fonctionnent ; l'API est presque identique dans les deux. Les noms de méthodes ne diffèrent que par la casse (wait_for_selector en Python devient waitForSelector en Node), et les deux installent les navigateurs avec une seule commande. Choisissez le langage que votre équipe maintient déjà pour que le scraper s'intègre au reste de votre stack.
Comment attendre que le contenu se charge dans Playwright ?
Attendez l'élément spécifique qui signale que les données sont présentes avec page.wait_for_selector("your.selector"), qui bloque jusqu'à ce que cet élément existe. Pour les récupérations en arrière-plan déclenchées par un clic, utilisez page.wait_for_load_state("networkidle") pour attendre que l'activité réseau se calme. Évitez les sleeps fixes ; l'auto-attente de Playwright et ces attentes explicites sont plus fiables.
Peut-on être bloqué lors du scraping avec Playwright ?
Oui. Faire tourner un vrai navigateur résout le rendu mais pas la détection. Les systèmes anti-bot prennent l'empreinte du navigateur, inspectent les signatures réseau et limitent le débit par IP, de sorte que les exécutions headless vanille sont signalées et les IPs datacenter sont bloquées en volume. Ralentir, randomiser les empreintes et faire tourner les IPs résidentielles aident tous ; une Crawling API gérée regroupe le rendu et la rotation pour que vous n'ayez pas à maintenir cette pile vous-même.
Comment capturer des données API ou JSON avec Playwright ?
Attachez un handler avec page.on("response", ...), filtrez les réponses par fragment d'URL pour trouver l'endpoint qui transporte les données et appelez response.json() dessus. Utilisez d'abord l'onglet Réseau dans les outils de développement de votre navigateur pour identifier le bon appel. Lire le JSON sous-jacent est plus rapide et bien moins fragile que d'analyser le HTML rendu.
Quand devrais-je utiliser une Crawling API plutôt que Playwright ?
Passez à la Crawling API lorsque les blocages, les CAPTCHAs ou la réputation des IPs deviennent votre goulot d'étranglement, ou lorsque vous crawlez de nombreuses pages et ne voulez pas exécuter l'infrastructure de navigateur et de proxies. Elle rend et fait tourner les IPs côté serveur et retourne du HTML fini en un seul appel. Gardez Playwright pour les flux locaux réellement interactifs comme les formulaires multi-étapes authentifiés, et acheminez le trafic de récupération à fort volume via l'API.
Crawlez n'importe quel site à grande échelle, sans combattre l'infrastructure.
Crawlbase gère les proxies, les empreintes et les CAPTCHA afin que votre équipe livre des pipelines de données au lieu de maintenir la plomberie de crawl. 1 000 requêtes gratuites, sans carte requise.

