Retour au blog
Guides
Mihai MaximLast updated on May 12, 202614 min read

Analyse HTML en Java avec Jsoup

Analyse HTML en Java avec Jsoup
En bref : Jsoup est la bibliothèque par défaut pour l'analyse HTML en Java. Ce guide couvre l'ensemble du cycle de vie (configuration Maven, chargement d'un document, sélecteurs CSS, exploration du DOM, extraction, modification et sérialisation), ainsi qu'un projet de scraping fonctionnel, la gestion des erreurs, la pagination et les limites qui vous poussent à opter pour un navigateur sans interface graphique ou une API de scraping.

Si vous devez extraire ou réécrire du code HTML au sein d’un service JVM, plusieurs options s’offrent à vous, mais pour la plupart des cas concrets, l’analyse HTML en Java commence et se termine toujours avec Jsoup. Le web scraping consiste à extraire automatiquement des données à partir du code source HTML d’un site, et Jsoup est la bibliothèque open source qui transforme ce code source en un DOM navigable que vous pouvez interroger à l’aide de sélecteurs CSS et modifier directement.

Ce tutoriel Jsoup s'adresse aux développeurs Java de niveau intermédiaire (ingénieurs backend, ingénieurs de données, spécialistes du référencement et de l'assurance qualité, toute personne effectuant des migrations de contenu) qui souhaitent un guide pratique plutôt qu'une présentation marketing. Nous abordons la configuration de Maven, le chargement d'un Document à partir d’un String, Fileou d’une URL, la configuration de la requête HTTP, la gestion des erreurs, la traversée et la sélection d’éléments, l’extraction de texte et d’attributs, la modification de nœuds et la sérialisation du résultat en HTML propre. Un projet de scraping complet et exécutable conclut l’article, avec des notes sur la pagination et la limitation de débit.

Nous sommes également honnêtes quant à ses limites : Jsoup n'exécute pas de JavaScript, ne change pas d'adresse IP et ne contourne pas les défenses anti-bot. La section finale indique où ses capacités s'arrêtent et vers quoi se tourner ensuite.

Pourquoi Jsoup est le choix par défaut pour l'analyse HTML en Java

Lorsque les données dont vous avez besoin se trouvent sur une page web publique et que le site ne dispose pas d’API, vous écrivez un scraper. Pour l’analyse HTML en Java, Jsoup est la solution par défaut depuis des années : open source, versions régulières, documentation solide et API fluide qui s’adapte parfaitement à jQuery ou au DOM JavaScript standard. Surtout, il couvre les deux volets du workflow : lire le HTML et écrire du HTML.

Ce que Jsoup peut et ne peut pas faire en un coup d’œil

Jsoup implémente la spécification HTML5 du WHATWG, il analyse donc pratiquement n'importe quel balisage, du plus propre au plus abîmé, à la manière d'un navigateur moderne. Vous disposez d’un arbre DOM, de sélecteurs de type jQuery et de méthodes pour la lecture et l’écriture. Ce qu’il ne fait pas, c’est exécuter du JavaScript. Tout ce qui est injecté par un framework côté client après la réponse initiale (un store React, des lignes chargées paresseusement, du contenu soumis à l’hydratation) est invisible pour Jsoup. Cette limite est à l’origine de la section sur les contraintes qui suit.

Configurer Jsoup dans un projet Maven

Lancez un squelette Maven avec mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart, puis ajoutez la dépendance Jsoup à pom.xml. Au moment de la rédaction de cet article, la version actuelle est la série 1.17.x, mais vérifiez toujours la dernière version stable sur Maven Central avant de fixer une version en production :

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.17.x</version>
</dependency>

Si vous souhaitez exécuter les exemples avec mvn exec:java, enregistrez le plugin Exec Maven dans votre <plugins> . Utilisez la version indiquée comme actuelle sur la page du plugin ; les anciens tutoriels mentionnent la version 3.0.0, qui est peut-être déjà obsolète. Vous n'utilisez pas Maven ? Jsoup est fourni sous la forme d'un fichier JAR unique que vous pouvez placer dans le classpath, et les utilisateurs de Gradle peuvent déclarer implementation 'org.jsoup:jsoup:1.17.x'.

Chargement de HTML dans un document Jsoup

Le point d'entrée pour l'analyse HTML en Java avec cette bibliothèque est la Jsoup classe. Vous pouvez analyser du code HTML à partir d’un String, un File, un InputStream, ou (le plus souvent) le récupérer directement à partir d'une URL. Voici un exemple simple de connexion Jsoup :

// From a string, great for unit tests
Document fromString = Jsoup.parse("<html><body><p>Hello</p></body></html>");

// From a local file
Document fromFile = Jsoup.parse(new File("page.html"), "UTF-8");

// From a live URL: issues the HTTP request, then parses the response
Document doc = Jsoup.connect("https://example.com").get();

Par rapport à la création de votre propre HttpURLConnection, l'API fluide Jsoup.connect(...) vous évite beaucoup de code standard : elle gère la connexion, lit le corps du message, décode le jeu de caractères et renvoie le contenu analysé Document en un seul appel. Ce Document est le DOM en mémoire avec lequel vous travaillez pour tout le reste, des sélecteurs CSS à la modification du DOM.

Configuration de la connexion Jsoup (en-têtes, cookies, délais d'expiration, agent utilisateur)

Jsoup.connect(url) renvoie un Connection objet que vous pouvez configurer avant d'envoyer la requête. Les valeurs par défaut conviennent pour les points de terminaison conviviaux, mais la plupart des cibles réelles nécessitent au moins un User-Agent valide et un délai d'expiration raisonnable :

Document doc = Jsoup.connect("https://example.com/listing")
    .userAgent("Mozilla/5.0 (compatible; MyJavaScraper/1.0; +https://yourdomain.tld/bot)")
    .referrer("https://example.com")
    .header("Accept-Language", "en-US,en;q=0.9")
    .cookie("session", "abc123")
    .timeout(10_000)
    .data("q", "java")
    .method(Connection.Method.GET)
    .get();

Choisissez un User-Agent qui identifie honnêtement votre bot. De nombreux serveurs renvoient une réponse allégée, voire bloquent purement et simplement l'accès, lorsque l'UA ressemble à un client HTTP Java par défaut.

Gestion des erreurs HTTP, des codes d'état et des délais d'expiration

Deux exceptions sont importantes ici. HttpStatusException est levée lorsque le serveur renvoie un code 4xx ou 5xx et vous fournit à la fois l'URL incriminée et le code d'état. IOException couvre tout le reste : échecs DNS, réinitialisations de connexion, délais d'attente des sockets. Interceptez les deux :

try {
    Document doc = Jsoup.connect(url).timeout(10_000).get();
} catch (HttpStatusException e) {
    log.warn("Bad status {} for {}", e.getStatusCode(), e.getUrl());
} catch (IOException e) {
    // retry with exponential backoff, then escalate
}

Si vous avez réellement besoin du corps d'une page 404 (pour la détection des soft-404), enchaînez .ignoreHttpErrors(true) avant .get(). Enveloppez les appels réseau dans une boucle de réessai avec un délai d'attente exponentiel pour les scrapers en production ; les erreurs 5xx transitoires et les erreurs de réinitialisation sont normales à grande échelle.

Sélection d'éléments avec les sélecteurs CSS de Jsoup

Une fois que vous disposez d’un Document, l'interroger se fait en une seule ligne. Document.select(String cssQuery) accepte la même syntaxe que celle que vous utiliseriez dans querySelectorAll et renvoie une Elements collection qui n'est jamais null, même lorsqu’aucun élément ne correspond. Cela suffit à éliminer toute une catégorie d’exceptions NullPointerException que vous rencontreriez autrement avec un code DOM naïf.

Le vocabulaire des sélecteurs CSS de Jsoup va bien au-delà des balises et des classes. Un petit tour d'horizon qui mérite d'être mis en favori à côté de n'importe quelle fiche de référence sur les sélecteurs CSS :

Sélecteur

Correspondances

div.post-card

<div> avec la classe post-card

article > h2

enfant direct h2 d'un article

a[href^=https]

liens dont href commence par https

img[src*=authors]

images dont src contient la sous-chaîne authors

li:nth-child(2)

deuxième li dans son parent

section:has(h2)

sections qui contiennent au moins un h2

p:contains(error)

paragraphe contenant le texte littéral « error »

Combinez-les librement. Une méthode efficace consiste à définir la portée d’un sélecteur enfant par rapport à un élément Element plutôt que de relancer des requêtes à partir de la racine du document.

getElementById, getElementsByClass et select Comparé

Jsoup reflète l'API DOM de JavaScript pour les lecteurs qui souhaitent des accesseurs explicites. getElementById(id) renvoie le seul Element (ou null) ayant cet identifiant, de la même manière que document.getElementById dans un navigateur. getElementsByClass(name) renvoie toutes les correspondances, tout comme document.getElementsByClassName. select(cssQuery) est l'équivalent de querySelectorAll et est le plus flexible des trois.

Utilisez les getters explicites lorsque l'intention est évidente (un ID stable ou une classe sémantique unique) et select() lorsque vous avez besoin d'une composition ou d'un filtrage d'attributs. Une mise en garde concrète : évitez d'utiliser les classes utilitaires générées par le framework comme sélecteurs d'ancrage. Une classe Tailwind telle que p-[10px] ou text-slate-700 est un détail de la sortie de compilation qui peut disparaître lors du prochain déploiement. Privilégiez les identifiants stables, les rôles ARIA ou les balises sémantiques, et vos scrapers vieilliront bien mieux.

Parcourir l'arborescence DOM : parents, frères et sœurs, enfants, premier/dernier/nième

Les sélecteurs vous ouvrent la porte ; la traversée vous mène aux frères et sœurs et aux ancêtres. L'API Document de Jsoup expose parent(), parents(), children(), et siblingElements(), ainsi qu'un accès indexé via first(), last(), et get(int n). Chaque Element dispose également de sa propre select() méthode qui limite une requête à ce sous-arbre, ce qui est la manière la plus propre d'écrire des sélecteurs résilients :

Element card = doc.selectFirst("article.post-card");
String title  = card.select("h2 > a").text();
String author = card.parent().select(".byline").text();
Elements tags = card.children().select("span.tag");

Remonter jusqu’à un ancêtre stable puis redescendre est bien plus fiable que d’enchaîner des sélecteurs de classe fragiles à partir de la racine du document, en particulier sur les pages qui utilisent du CSS-in-JS ou des frameworks de classes utilitaires.

Extraction de texte, de HTML et d’attributs à partir d’éléments

Une fois que vous avez sélectionné un Element, quatre méthodes couvrent presque tous les cas d'extraction de données HTML en Java. text() renvoie le texte visible, avec les espaces blancs condensés (de manière analogue à innerText). html() renvoie le HTML interne sous forme de chaîne. outerHtml() inclut les balises propres à l'élément. ownText() ne renvoie que les nœuds de texte directs de l'élément, en ignorant les descendants.

Pour les attributs, attr("href") lit une valeur et absUrl("href") résout les URL relatives par rapport à l'URI de base du document, ce qui est très utile lors de l'extraction de listes de liens. L'itération est simple, puisque Elements est Iterable:

for (Element link : doc.select("a[href]")) {
    System.out.println(link.text() + " -> " + link.absUrl("href"));
}

Vous pouvez également utiliser le flux, forEachou extraire par index avec get(n). Choisissez la méthode qui vous semble la plus naturelle pour votre base de code.

Modification et génération de HTML avec Jsoup

La plupart des tutoriels s'arrêtent à l'extraction, mais l'analyse HTML en Java avec Jsoup est véritablement bidirectionnelle. Le même attr(), text()et html() méthodes font également office de setters. Vous pouvez créer de nouveaux nœuds avec new Element(Tag.valueOf("...")), les attacher avec appendChild() ou appendElement(), et les supprimer avec remove(). L'interface de modification HTML de Jsoup se présente comme suit :

Document doc = Jsoup.parse(rawHtml);

// Edit existing nodes
doc.select("a.tracker").forEach(a -> a.attr("rel", "nofollow"));
doc.selectFirst("h1").text("Updated Title");

// Add a new node
Element note = new Element(Tag.valueOf("p"), "")
    .text("Edited by my scraper at " + Instant.now());
doc.body().appendChild(note);

// Remove ad slots
doc.select("div.ad-slot").remove();

// Serialize back to a clean HTML string
String cleaned = doc.html();

C'est ce cycle complet (analyse, modification, sérialisation) qui rend Jsoup utile pour les migrations de contenu, la validation du code HTML et la normalisation des flux, et pas seulement pour le scraping ponctuel.

Projet pratique : scraping d'une liste de blogs de bout en bout

Pour mettre tout cela en pratique, créez un petit scraper qui extrait le titre, le lien, l'image d'en-tête et l'avatar de l'auteur de chaque fiche de publication sur une liste de blogs publique. Ouvrez d'abord la page dans DevTools ; une reconnaissance manuelle vaut toujours mieux que des suppositions. Identifiez un sélecteur de conteneur stable pour chaque fiche, puis écrivez des sélecteurs champ par champ en fonction de celui-ci.

Document doc = Jsoup.connect("https://example.com/blog")
    .userAgent("MyJavaScraper/1.0")
    .timeout(10_000)
    .get();

for (Element card : doc.select("article.post-card")) {
    String title   = card.select("h2 > a").text();
    String url     = card.select("h2 > a").absUrl("href");
    String header  = card.selectFirst("img.header-image").absUrl("src");
    String avatar  = card.select("img[src*=authors]").attr("abs:src");

    System.out.printf("%s | %s | %s | %s%n", title, url, header, avatar);
}

Chaque champ dispose de son propre sélecteur basé sur l'intention. img[src*=authors] filtre par sous-chaîne d'attribut, ce qui s'avère plus fiable que le chaînage de sélecteurs structurels lorsque le balisage change. Ce type de scraping web Java structuré avec Jsoup l'emporte à chaque fois sur l'analyse fragile basée sur les index.

Itération sur les pages paginées

La plupart des listes suivent un schéma d'URL prévisible tel que /blog, /blog/page/2/, /blog/page/3/. Traitez la page 1 comme un cas particulier et bouclez jusqu’à ce que vous tombiez sur un ensemble de résultats vide ou une erreur 404 de HttpStatusException. Attendez une ou deux secondes entre chaque requête, aléatorisez légèrement le processus et respectez le fichier robots.txt de la cible (RFC 9309). La pagination sans limitation de débit est le moyen le plus rapide de se faire bannir et la raison la plus courante pour laquelle les gens finissent par lire des articles expliquant pourquoi vous avez été bloqué.

Limites de Jsoup et quand envisager une alternative

La limite inhérente à Jsoup réside dans JavaScript. Il analyse ce que le serveur renvoie initialement, donc tout ce qui est rendu côté client (SPAs React, Vue ou Angular, défilement infini à chargement différé, contenu masqué derrière l'hydratation) lui est invisible. Il n'offre par ailleurs aucune prise en charge du rendu sans interface graphique, de la rotation de proxys ou du contournement des filtres anti-bot.

Lorsque la page est dynamique, associez Jsoup à un navigateur headless : Selenium et Playwright pilotent un véritable Chromium ; HtmlUnit est une option native JVM plus légère ; Jaunt propose une API Java similaire avec HTTP intégré. Lorsque la page est statique mais hostile (Cloudflare, interdictions fréquentes d'IP, empreintes digitales), acheminez la requête via une API de scraping gérée qui gère les proxys et les CAPTCHA, puis renvoyez directement le code HTML de réponse à Jsoup. Cela permet de garder votre code de parsing propre et de réduire les éléments mobiles.

Conclusion : créer des parseurs HTML Java résilients

Le workflow complet pour l'analyse HTML en Java avec Jsoup se résume à quatre verbes : charger, sélectionner, extraire ou modifier, puis afficher. Pour approfondir le sujet, le guide pratique Jsoup et la documentation Javadocs constituent les références incontournables. Avant de vous lancer dans un nouveau projet de scraping, passez en revue une liste de contrôle rapide : la page est-elle statique ou rendue par JavaScript ? La cible est-elle susceptible de me bloquer ? Dois-je modifier le code HTML ou simplement le lire ? Ces trois réponses vous indiqueront si Jsoup seul suffit.

Points clés

  • Utilisez Jsoup pour tout travail d'analyse HTML en Java où le balisage est rendu par le serveur. Il gère le HTML mal formé comme le ferait un navigateur moderne.
  • Jsoup.connect(url).get() Il regroupe la récupération et l'analyse en un seul appel. Définissez toujours un User-Agent réel et un délai d'expiration non par défaut, et interceptez à la fois HttpStatusException et IOException.
  • select() renvoie une Elements liste qui peut être vide mais qui ne l'est jamais null. Privilégiez les identifiants stables, les rôles ARIA et les sélecteurs sémantiques plutôt que les classes utilitaires générées par le framework.
  • Jsoup est bidirectionnel : attr, text, et html en tant que setters, ainsi que appendChild et remove, vous permettent de modifier et de resérialiser le HTML, et pas seulement de le lire.
  • Jsoup n'exécute pas de JavaScript. Pour les applications SPA, associez-le à Selenium, Playwright ou HtmlUnit ; pour les cibles bloquées, acheminez la requête via une API de scraping gérée.

FAQ

Jsoup peut-il extraire des données d'applications rendues en JavaScript ou d'applications monopages ?

Non. Jsoup analyse uniquement le code HTML brut renvoyé par le serveur ; tout ce qui est généré par un framework côté client après le chargement de la page lui est donc invisible. Pour extraire des données de SPA ou de pages qui s’hydratent côté client, utilisez un navigateur réel ou headless avec Selenium, Playwright ou HtmlUnit, capturez le code HTML entièrement rendu, puis transmettez cette chaîne à Jsoup.parse(...) pour une extraction basée sur des sélecteurs.

En quoi Jsoup diffère-t-il de HtmlUnit, Jaunt ou Selenium pour l'analyse HTML ?

Jsoup est un analyseur HTML pur. Il n'exécute pas de JavaScript, ne fait pas tourner de moteur JS et ne simule pas de navigateur. HtmlUnit et Selenium affichent tous deux les pages à l'aide d'un moteur JS (HtmlUnit au sein de la JVM, Selenium via un pilote de navigateur réel). Jaunt se rapproche davantage de Jsoup en tant qu'analyseur associé à un simple client HTTP. Utilisez Jsoup lorsque la page est statique ; utilisez les autres lorsque vous avez besoin d'un rendu ou d'une interaction.

Comment éviter d'être bloqué ou soumis à une limitation de débit lors de l'analyse de pages avec Jsoup ?

Identifiez honnêtement votre bot dans l'en-tête User-Agent, limitez les requêtes à quelques-unes par seconde et par hôte, aléatorisez les délais et réutilisez les cookies lorsque cela est approprié. Lisez et respectez robots.txt. Pour les tâches à haut volume ou les cibles hostiles, acheminez les requêtes via un pool de proxys résidentiels ou rotatifs, car Jsoup ne dispose pas en soi de rotation d'IP, de falsification d'empreinte digitale ou de gestion des CAPTCHA intégrés.

Jsoup peut-il analyser du XML, des flux RSS ou du HTML mal formé ?

Oui, pour les trois. Passez explicitement un analyseur XML avec Jsoup.parse(input, baseUri, Parser.xmlParser()) pour les flux RSS, les plans de site et autres documents XML. Pour le HTML mal formé, l'analyseur par défaut est tolérant et normalise le balisage comme le ferait un navigateur moderne ; ainsi, les balises non fermées et les caractères parasites produisent généralement un résultat utilisable Document.

Quelle est la dernière version stable de Jsoup et comment la maintenir à jour ?

Consultez directement Maven Central, car les numéros de version changent fréquemment et tout numéro mentionné dans un tutoriel peut déjà être obsolète. Abonnez-vous aux notes de mise à jour sur le dépôt GitHub de Jsoup, ou exécutez un plugin de mise à jour des dépendances Maven tel que versions:display-dependency-updates dans CI pour faire apparaître automatiquement les mises à jour disponibles. Renovate et Dependabot fonctionnent tous deux si votre dépôt est hébergé en conséquence.

Conclusion

Si vous terminez ce guide et que vous ne devez retenir qu’une seule chose, que ce soit ce rythme en quatre étapes : chargez le HTML dans un Document, sélectionnez ce qui vous intéresse, extrayez-le ou modifiez-le, puis sérialisez-le à nouveau. Cette séquence est la colonne vertébrale de chaque scraper basé sur Jsoup, de chaque migration de contenu et de chaque nettoyeur HTML que vous écrirez. Ajoutez un véritable User-Agent, des délais d'attente raisonnables, une gestion structurée des exceptions et une politique de réessai avec backoff, et vous obtiendrez un parseur capable de résister au trafic de production.

Une mise en garde honnête s'impose toutefois : Jsoup n'exécute pas de JavaScript et ne contourne pas les défenses anti-bot. Si la page s'affiche côté client, vous aurez besoin d'un navigateur sans interface graphique. Si la cible bloque votre adresse IP ou identifie votre outil de récupération, vous aurez besoin d'une couche de requêtes plus intelligente.

C'est dans ce deuxième cas qu'une API de scraping gérée prend tout son sens. L'API Scraper de WebScrapingAPI renvoie le code HTML brut même des cibles hostiles, en gérant de son côté la rotation des proxys, les CAPTCHA et l'empreinte digitale du navigateur. Vous pouvez ainsi conserver votre code d'analyse Jsoup tel quel et simplement remplacer l'étape de récupération. C'est la méthode la plus propre que nous ayons trouvée pour ajouter une résilience de production à un analyseur Java allégé.

À propos de l'auteur
Mihai Maxim, Développeur Full Stack @ WebScrapingAPI
Mihai MaximDéveloppeur Full Stack

Mihai Maxim est développeur Full Stack chez WebScrapingAPI ; il participe à l'ensemble du produit et contribue à la création d'outils et de fonctionnalités fiables pour 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.