Comment scraper les sites web générés par JavaScript
De nombreux sites modernes envoient un document HTML presque vide et construisent le contenu dans le navigateur grâce à JavaScript. Si votre scraper récupère la page et ne trouve ni produits, ni prix, ni texte d'article, le contenu existe, mais il arrive plus tard. Ce guide montre comment identifier le type de page que vous avez, comment trouver une voie plus rapide qu'un navigateur lorsqu'elle existe, et comment scraper les pages rendues avec Playwright en Python. Il se termine par une note sur ce qu'il faut faire lorsqu'une page rendue affiche un captcha.
Étape 1 : vérifier si le contenu est dans le HTML
Ouvrez la page avec view-source: dans votre navigateur, ou récupérez-la avec une requête HTTP simple, puis cherchez dans le code source un texte que vous voyez à l'écran. Trois cas sont courants :
- Le texte est présent. La page est rendue côté serveur. Un client HTTP simple et un analyseur HTML suffisent, et vous devez les utiliser, car ils sont plus rapides et plus simples.
- Le texte est absent, mais un bloc JSON est présent. De nombreux sites intègrent leur état dans une balise script, comme
__NEXT_DATA__. Analysez directement ce JSON. - Le texte est absent et il n'y a pas de bloc JSON. La page charge son contenu avec des requêtes supplémentaires. Regardez l'onglet Réseau des outils de développement, filtré sur Fetch/XHR, pendant le chargement de la page.
Étape 2 : appeler le point d'accès JSON s'il existe
Lorsqu'une page récupère ses données depuis un point d'accès, l'appeler directement est généralement la meilleure option. Il est plus léger, plus rapide et plus stable que la page rendue. Copiez l'URL de la requête, vérifiez les en-têtes que le site exige, et essayez-la depuis un script. Ne faites cela que lorsque les conditions d'utilisation du site le permettent, et respectez les limites de débit ou l'authentification attendues. Un point d'accès non documenté peut changer sans préavis ; écrivez donc votre analyseur pour qu'il échoue bruyamment lorsque la forme de la réponse change.
Étape 3 : rendre la page lorsque c'est nécessaire
Si le contenu nécessite vraiment le navigateur, pilotez un navigateur headless. Playwright est un bon choix pour Python. L'exemple ci-dessous ouvre une liste de produits, attend que le contenu apparaisse, et lit le texte de chaque carte :
from playwright.sync_api import sync_playwright
URL = "https://example.com/products" # une page que vous avez le droit de scraper
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(URL, wait_until="domcontentloaded", timeout=60_000)
# Attendre l'élément qui prouve que les données sont arrivées.
page.wait_for_selector(".product-card", timeout=30_000)
titles = page.locator(".product-card h2").all_inner_texts()
browser.close()
for title in titles:
print(title)
Attendre un sélecteur précis est bien plus fiable qu'un sleep fixe. Une pause fixe est trop courte un mauvais jour, ou fait perdre du temps un bon jour. Choisissez l'élément qui n'apparaît qu'une fois les données chargées.
Étape 4 : gérer le défilement infini et la pagination
Certaines pages chargent davantage d'éléments au fur et à mesure du défilement. Descendez jusqu'en bas, attendez que le nombre d'éléments augmente, et arrêtez-vous lorsqu'il n'augmente plus. Les pages à pagination numérotée sont plus simples : trouvez le lien vers la page suivante, suivez-le, et arrêtez-vous à la dernière page. Fixez toujours un nombre maximal de pages ou de défilements, afin qu'un bogue ne fasse pas tourner votre crawler indéfiniment.
def scroll_until_done(page, selector: str, max_rounds: int = 20) -> int:
previous = -1
for _ in range(max_rounds):
count = page.locator(selector).count()
if count == previous:
break
previous = count
page.mouse.wheel(0, 4000)
page.wait_for_timeout(1500) # laisser au lot suivant le temps de se charger
return previous
Étape 5 : garder le navigateur économique
Le rendu coûte cher. Bloquez les images, polices et médias dont vous n'avez pas besoin, et réutilisez un seul navigateur pour de nombreuses pages au lieu d'en lancer un nouveau à chaque fois. Fermez les pages et les contextes lorsque vous avez fini, pour que la mémoire ne grimpe pas au fil d'une longue exécution.
def block_heavy_assets(route):
if route.request.resource_type in ("image", "font", "media"):
route.abort()
else:
route.continue_()
page.route("**/*", block_heavy_assets)
Étape 6 : lorsqu'une page rendue affiche un captcha
Il arrive que la page rendue présente un captcha avant d'afficher le moindre contenu. Si ce captcha est PopularCaptcha, le type de captcha disponible chez Scarnox, vous lisez la sitekey dans la page, demandez un jeton, et placez le jeton dans le champ de formulaire attendu par le site. Le guide Python PopularCaptcha détaille cette étape. Les autres widgets ne sont pas encore disponibles ; consultez donc les types de captcha expliqués avant de bâtir un projet autour de l'un d'eux.
Faites attention au navigateur lui-même. Un navigateur headless qui paraît clairement automatisé peut déclencher davantage de vérifications, et non moins. Lisez la détection des navigateurs headless pour les signaux à surveiller, et privilégiez des chargements de page plus lents et moins nombreux.
Scraper de manière responsable
- Vérifiez le
robots.txtet les conditions d'utilisation du site avant de rendre ses pages ou d'appeler ses points d'accès. - Gardez des limites de débit basses, et mettez les résultats en cache pour ne récupérer chaque page qu'une fois.
- Ne scrapez pas de données personnelles sans base légale.
- Si un site restreint l'accès, arrêtez-vous. N'essayez pas de contourner la restriction.
Prochaines étapes
- Scraper sans se faire bloquer
- Détection des navigateurs headless
- Scraper des sites protégés par Cloudflare
- Résoudre les captchas avec Playwright et Puppeteer
Commencez avec un crédit d'essai gratuit, sans carte bancaire : créez un compte et testez le flux PopularCaptcha sur une page qui vous appartient. Pour les tarifs actuels, consultez la page tarifs.