Java n'est pas le premier langage auquel la plupart des gens pensent pour le scraping, mais c'est l'un des plus fiables. Si votre pipeline de données, votre couche de services ou vos traitements par lots tournent déjà sur la JVM, réaliser l'extraction en Java garde tout dans une seule base de code, un seul build et un seul processus de déploiement. L'écosystème est mature : un analyseur HTML rapide, des liaisons vers des navigateurs sans interface et un modèle de concurrence solide sont tous de premier ordre.
Ce guide est un tour pratique du web scraping avec Java. Nous couvrons la boîte à outils dont vous avez réellement besoin (Jsoup pour les pages statiques, HtmlUnit et Selenium pour celles rendues en JavaScript), parcourons un exemple Jsoup complet de bout en bout, puis abordons la partie qui fait échouer la plupart des scrapers à grande échelle : les défenses anti-bot et les blocages d'IP. L'objectif est un modèle mental solide sur lequel bâtir, pas un catalogue exhaustif.
La boîte à outils du scraping en Java
Presque tous les scrapers Java sont construits à partir de l'un de ces trois outils. Choisir le bon est surtout une question de la façon dont la page cible diffuse son contenu.
- Jsoup est le cheval de trait. Il récupère une URL via HTTP et analyse le HTML renvoyé en un document interrogeable avec un support des sélecteurs CSS qui ressemble à jQuery. Il est rapide, n'a aucun runtime externe et constitue le bon choix par défaut pour toute page dont les données sont présentes dans le HTML initial.
- HtmlUnit est un navigateur sans interface graphique pour Java. Il exécute le JavaScript et construit un DOM, ce qui lui permet d'atteindre du contenu que Jsoup ne peut pas voir. Il est plus léger qu'un vrai navigateur, mais son moteur JavaScript est en retard sur les sites modernes, si bien que les applications monopages complexes peuvent le mettre en difficulté.
- Selenium WebDriver pilote un vrai navigateur (Chrome, Firefox) depuis Java. Il rend tout ce qu'un utilisateur verrait, ce qui en fait l'option la plus capable pour un rendu côté client lourd, au prix d'être la plus lente et la plus gourmande en ressources.
La décision est plus simple que la longue liste de « types de scrapers » que l'on rencontre parfois. Les données sont-elles dans le HTML brut ? Utilisez Jsoup. N'apparaissent-elles qu'après l'exécution des scripts ? Tournez-vous vers HtmlUnit, et repliez-vous sur Selenium quand HtmlUnit ne suit plus. Tout le reste est du détail.
Ouvrez l'URL cible, affichez le code source (pas l'inspecteur, le code source brut) et cherchez une valeur que vous voulez extraire. Si elle s'y trouve, la page est rendue côté serveur et Jsoup seul suffira. Si le source est une coquille presque vide et que les données n'apparaissent que dans le DOM en direct, la page est rendue côté client et il vous faut un moteur de navigateur ou un service de rendu.
Mettre en place un projet Jsoup
Jsoup se livre sous la forme d'une unique dépendance Maven. Ajoutez-la à votre pom.xml et vous êtes prêt à récupérer et analyser.
<dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.17.2</version> </dependency>
Si vous utilisez Gradle à la place, la même coordonnée va dans votre build.gradle sous la forme implementation 'org.jsoup:jsoup:1.17.2'. Dans les deux cas, vous disposez désormais d'un récupérateur et d'un analyseur dans une seule bibliothèque.
Un exemple Jsoup propre, du début à la fin
Le schéma pour une page statique est toujours le même : se connecter à l'URL, récupérer un Document analysé, sélectionner les éléments voulus avec des sélecteurs CSS et en extraire les champs. Voici un exemple complet et exécutable qui scrape une liste d'entrées de livres et affiche un enregistrement structuré pour chacune. Remplacez l'URL et les sélecteurs par votre propre cible.
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; public class BookScraper { public static void main(String[] args) throws Exception { String url = "https://books.toscrape.com/"; Document doc = Jsoup.connect(url) .userAgent("Mozilla/5.0 (compatible; MyScraper/1.0)") .timeout(10000) .get(); Elements books = doc.select("article.product_pod"); for (Element book : books) { String title = book.selectFirst("h3 a").attr("title"); String price = book.selectFirst("p.price_color").text(); String stock = book.selectFirst("p.instock").text().trim(); System.out.printf("%s | %s | %s%n", title, price, stock); } } }
Quelques détails de cet extrait méritent leur place. L'appel à userAgent définit un identifiant raisonnable au lieu de celui par défaut de Jsoup, que de nombreux serveurs rejettent d'emblée. Le timeout empêche un hôte lent de faire traîner votre exécution indéfiniment. select renvoie chaque élément correspondant, sur lequel vous itérez ; selectFirst en renvoie un seul, ce qui est exactement ce que vous voulez pour un champ à l'intérieur d'une ligne. Lire le titre depuis l'attribut title plutôt que depuis le texte du lien évite les « ... » tronqués que le texte visible véhicule parfois.
La sortie est une ligne nette par livre : le titre, le prix et la disponibilité. À partir de là, il n'y a qu'un pas pour écrire chaque enregistrement en JSON, en CSV ou directement dans une base de données, et pour suivre les liens de pagination afin de parcourir tout le catalogue. Si votre objectif est un crawl complet sur plusieurs pages plutôt qu'une seule récupération, le tutoriel dédié sur la façon de construire un web crawler en Java pousse ce schéma plus loin, vers la mise en file d'attente et la découverte de liens.
Le code Java ci-dessus ne change presque jamais. Les sélecteurs, si. Les sites renomment les classes et restructurent le balisage sans prévenir, si bien qu'un scraper qui fonctionnait le mois dernier peut renvoyer des résultats vides aujourd'hui. Gardez vos sélecteurs à un seul endroit, échouez bruyamment quand un élément attendu est absent et réinspectez la page en direct quand l'extraction se tait. C'est de la maintenance de routine, pas le signe que l'approche est mauvaise.
Gérer les pages rendues en JavaScript
Jsoup ne voit jamais que le HTML envoyé par le serveur. Quand une page construit son contenu dans le navigateur, ce HTML initial est une coquille et Jsoup revient vide. Vous avez deux voies pour avancer.
La première est un moteur de navigateur Java. HtmlUnit exécute le JavaScript de la page sans interface et vous donne un DOM peuplé que vous pouvez interroger un peu comme Jsoup. Il est rapide et n'a aucun navigateur externe à installer, mais son moteur de script n'est pas aussi à jour qu'un vrai navigateur, si bien que les frameworks modernes peuvent s'afficher incorrectement ou lever des erreurs. Selenium WebDriver contourne cela en automatisant un vrai Chrome ou Firefox : il rend exactement ce qu'un utilisateur voit, attend les éléments et gère même les interactions comme les clics et les défilements. Le compromis, c'est le poids. Un navigateur par worker dévore mémoire et CPU, et une flotte de navigateurs représente une vraie infrastructure à faire tourner et à maintenir en bonne santé.
La seconde voie consiste à éliminer entièrement le problème du navigateur de votre côté et à laisser un service de rendu renvoyer du HTML fini. Cela garde votre code Java aussi simple que l'exemple Jsoup ci-dessus tout en obtenant des pages entièrement rendues, ce qui est exactement le sujet de la section suivante.
Le vrai obstacle : les défenses anti-bot à grande échelle
Le rendu est la moitié facile du problème. La moitié difficile apparaît dès que vous lancez plus d'une poignée de requêtes. Les sites commerciaux surveillent le trafic en forme de scraper et ripostent avec des limites de débit, des CAPTCHA et des bannissements d'IP purs et simples. Une IP de datacenter qui effectue des dizaines de requêtes identiques par minute est repérée vite, et une fois qu'une IP est bloquée, chaque requête qui en provient échoue, peu importe la propreté de votre code d'analyse.
Les solutions sont bien connues : faire tourner de nombreuses adresses IP pour qu'aucune ne déclenche une limite, privilégier les IP résidentielles qui passent pour de vrais utilisateurs, espacer vos requêtes, varier vos en-têtes et rendre les pages pour que votre trafic ressemble à un navigateur. L'ennui, c'est qu'assembler tout cela vous-même (un pool de proxys sain plus une flotte de navigateurs sans interface plus une logique de réessai) représente l'essentiel de l'ingénierie, et n'a rien à voir avec les données que vous voulez réellement. Pour le guide complet, voyez comment scraper des sites web sans se faire bloquer.
Acheminer les requêtes via la Crawling API
C'est là que reléguer les parties difficiles côté serveur garde votre Java simple. La Crawling API est un unique point d'accès HTTP : vous lui envoyez une URL cible et votre token, et elle rend la page dans un vrai navigateur derrière une IP résidentielle rotative, puis renvoie le HTML fini. Votre code reste un simple appel HTTP suivi d'une analyse Jsoup. Pas de flotte sans interface, pas de pool de proxys, pas de gestion de CAPTCHA de votre côté.
Comme il s'agit simplement d'une requête HTTP, vous pouvez l'appeler avec le HttpClient intégré de Java. Passez &javascript=true quand la cible est rendue côté client ; omettez-le pour les pages statiques afin d'économiser sur le rendu.
import java.net.URI; import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; public class CrawlingApiScraper { private static final String TOKEN = "YOUR_CRAWLBASE_JS_TOKEN"; public static void main(String[] args) throws Exception { String target = "https://www.example.com/products"; String encoded = URLEncoder.encode(target, StandardCharsets.UTF_8); String endpoint = "https://api.crawlbase.com/?token=" + TOKEN + "&javascript=true&url=" + encoded; HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(endpoint)) .GET() .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() != 200) { System.out.println("Request failed: " + response.statusCode()); return; } Document doc = Jsoup.parse(response.body()); Elements items = doc.select("div.product"); System.out.println("Parsed " + items.size() + " products"); } }
Remarquez que la moitié analyse est identique à l'exemple Jsoup nu. Le seul changement est d'où vient le HTML : au lieu que Jsoup.connect(url).get() frappe le site directement, vous récupérez via l'API et passez le corps à Jsoup.parse(). Tout ce que vous savez déjà sur les sélecteurs se reporte inchangé, tandis que le rendu, la rotation d'IP et l'évitement des blocages se produisent de l'autre côté de cet unique appel HTTP.
Le scraping à grande échelle échoue sur les blocages, pas sur l'analyse. La Crawling API rend chaque page dans un vrai navigateur derrière une IP résidentielle rotative et renvoie du HTML fini à un unique appel HTTP, si bien que votre code Java reste une récupération plus une analyse Jsoup. Ajoutez javascript=true pour les pages rendues côté client et commencez sur l'offre gratuite.
Quand utiliser un navigateur plutôt qu'un service
Acheminer via l'API n'est pas le seul choix valable. Si votre cible nécessite une véritable interaction, se connecter, cliquer à travers des flux en plusieurs étapes, remplir des formulaires, faire glisser des curseurs, alors piloter un vrai navigateur avec Selenium vous donne un contrôle qu'un seul appel HTTP ne peut pas offrir. Le compromis honnête est le coût opérationnel : vous possédez la flotte de navigateurs, l'empreinte mémoire et l'instabilité qui accompagne l'automatisation d'interfaces en direct. Pour des bases sur l'exécution de navigateurs à des fins d'extraction et là où ils sont payants, l'aperçu du bon navigateur sans interface pour le web scraping est une bonne lecture complémentaire.
Un terrain d'entente courant consiste à utiliser l'API gérée pour le gros des récupérations de pages simples, là où les blocages et le rendu sont tout le problème, et à réserver un worker Selenium pour la petite tranche de cibles qui requièrent réellement une interaction. Cela garde votre infrastructure légère sans renoncer aux cas qui nécessitent un navigateur complet.
Bonnes habitudes pour des scrapers Java en production
Quel que soit l'outil que vous retenez, quelques pratiques séparent un script qui fonctionne une fois d'un scraper qui tourne de façon fiable pendant des mois.
- Définissez un véritable user agent et un timeout. Les identifiants par défaut sont rejetés, et une requête sans borne peut bloquer un lot entier.
- Échouez bruyamment sur les champs manquants. Un null là où vous attendiez un élément est votre tout premier signal que les sélecteurs ont dérivé. Attrapez-le et journalisez l'URL.
- Cadencez et réessayez avec backoff. Espacez les requêtes, et sur une erreur transitoire attendez plus longtemps avant de réessayer plutôt que de marteler.
- Séparez la récupération de l'analyse. Une frontière nette signifie que vous pouvez passer d'une récupération Jsoup directe à la Crawling API sans toucher à votre code d'extraction.
- Persistez au fur et à mesure. Écrivez chaque enregistrement à mesure qu'il est analysé plutôt que de mettre en tampon une longue exécution en mémoire, afin qu'un crash près de la fin ne perde pas tout.
Points clés
- Jsoup est le choix par défaut. Pour toute page dont les données vivent dans le HTML brut, connectez-vous, sélectionnez avec des sélecteurs CSS et extrayez. Il est rapide et léger en dépendances.
- Les pages JavaScript nécessitent un moteur de navigateur ou un service de rendu. HtmlUnit et Selenium rendent le contenu côté client en Java ; un service de rendu renvoie du HTML fini sans que vous en exécutiez un.
- Ce sont les blocages, pas l'analyse, qui cassent les scrapers à grande échelle. Les limites de débit, les CAPTCHA et les bannissements d'IP sont le vrai obstacle, et les IP résidentielles rotatives plus une cadence maîtrisée sont la réponse.
- La Crawling API garde Java simple. Un seul appel HTTP gère le rendu et la rotation d'IP côté serveur, si bien que votre code reste une récupération plus une analyse Jsoup.
- Les sélecteurs sont la couche fragile. Attendez-vous à ce qu'ils dérivent, échouez bruyamment quand cela arrive et traitez la réinspection de la page en direct comme de la maintenance de routine.
Foire aux questions
Peut-on faire du web scraping avec Java ?
Oui. Java possède un écosystème de scraping mature : Jsoup récupère et analyse le HTML statique avec des sélecteurs CSS, HtmlUnit et Selenium gèrent les pages rendues en JavaScript, et le HttpClient intégré vous permet d'appeler des services de rendu ou de proxy. Si votre stack tourne déjà sur la JVM, scraper en Java garde l'extraction dans la même base de code que le reste de votre pipeline.
Quelle bibliothèque Java est la meilleure pour le web scraping ?
Cela dépend de la page. Jsoup est le meilleur choix par défaut pour le HTML statique rendu côté serveur, car il est rapide et simple. Pour les pages qui construisent leur contenu dans le navigateur, HtmlUnit exécute le JavaScript sans interface et Selenium WebDriver pilote un vrai navigateur pour les applications monopages les plus lourdes. La plupart des projets utilisent Jsoup pour l'analyse et n'ajoutent un moteur de navigateur ou un service de rendu que là où la page l'exige.
Quand Jsoup cesse-t-il de suffire ?
Jsoup ne voit que le HTML que le serveur renvoie, il revient donc vide sur les pages qui rendent leurs données côté client avec du JavaScript. Le test rapide consiste à afficher le code source brut de la page et à y chercher une valeur que vous voulez : si elle est absente du source mais présente dans le DOM en direct, il vous faut un moteur de navigateur comme HtmlUnit ou Selenium, ou un service de rendu qui renvoie du HTML fini que Jsoup pourra analyser.
Comment éviter de me faire bloquer lors du scraping avec Java ?
Faites tourner de nombreuses adresses IP pour qu'aucune ne déclenche une limite de débit, privilégiez les IP résidentielles qui passent pour de vrais utilisateurs, espacez vos requêtes, variez vos en-têtes et rendez les pages pour que le trafic ressemble à un navigateur. Construire cela vous-même représente l'essentiel du travail, ce qui explique pourquoi de nombreuses équipes acheminent leurs requêtes via la Crawling API, qui gère la rotation, le rendu et l'évitement des blocages côté serveur.
Java ou Python, lequel est meilleur pour le web scraping ?
Python a la plus grande communauté de scraping et une courbe d'apprentissage un peu plus douce, mais Java est pleinement capable et souvent le meilleur choix quand votre plateforme de données, vos services ou vos traitements par lots tournent déjà sur la JVM. Rester dans un seul langage et un seul build pour l'extraction comme pour le traitement en aval vaut généralement plus qu'une différence marginale de nombre de bibliothèques.
Ai-je besoin de l'option JavaScript de la Crawling API pour chaque page ?
Non. Passez javascript=true uniquement pour les pages qui rendent leur contenu côté client. Les pages statiques rendues côté serveur renvoient leurs données sans cela, et sauter le rendu sur celles-ci est plus rapide et moins coûteux. La règle la plus simple : activez-le quand une simple récupération renvoie une coquille vide, et laissez-le désactivé sinon.
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.
