Retour au blog
Guides
Mihai Maxim31 janvier 202310 min de lecture

JSoup : analyse syntaxique du HTML en Java

JSoup : analyse syntaxique du HTML en Java

Présentation de JSoup

Le web scraping peut être considéré comme une chasse au trésor numérique. Vous parcourez un site web et en extrayez toutes les informations dont vous avez besoin. C'est une technique utilisée à toutes sortes de fins, comme trouver les prix les plus bas, analyser l'opinion des clients ou collecter des données à des fins de recherche.

Java est considéré comme un excellent langage de programmation pour le web scraping, car il dispose d'une grande variété de bibliothèques et de frameworks pouvant faciliter ce processus. L'une des bibliothèques les plus connues pour le web scraping en Java est JSoup. JSoup vous permet de parcourir et d'effectuer des recherches dans le code HTML d'un site web et d'extraire toutes les données dont vous avez besoin.

En combinant Java et JSoup, vous pouvez créer de superbes applications de web scraping capables d'extraire des données de sites web rapidement et facilement. Dans cet article, je vais vous présenter les bases du web scraping avec JSoup.

Configuration d'un projet JSoup

Dans cette section, nous allons créer un nouveau projet Java avec Maven et le configurer pour qu'il s'exécute depuis la ligne de commande à l'aide du plugin exec-maven-plugin. Cela vous permettra de packager et d'exécuter facilement votre projet sur un serveur, ce qui facilitera l'automatisation et l'évolutivité du processus d'extraction de données. Ensuite, nous installerons la bibliothèque JSoup.

Création d'un projet Maven

Maven est un outil d'automatisation de la construction pour les projets Java. Il gère les dépendances, les builds et la documentation, ce qui facilite la gestion des projets Java complexes. Avec Maven, vous pouvez facilement gérer et organiser le processus de construction, les dépendances et la documentation de votre projet. Il permet également une intégration aisée avec d'autres outils et frameworks.

L'installation de Maven est un processus simple qui s'effectue en quelques étapes.

Commencez par télécharger la dernière version de Maven depuis le site officiel (https://maven.apache.org/download.cgi).

Une fois le téléchargement terminé, extrayez le contenu de l'archive dans un répertoire de votre choix.

Ensuite, vous devrez configurer les variables d'environnement.

Sous Windows, définissez la variable JAVA_HOME sur l'emplacement de votre JDK et ajoutez le dossier bin de l'installation de Maven à la variable PATH.

Sous Linux/macOS, vous devrez ajouter les lignes suivantes à votre fichier ~/.bashrc ou ~/.bash_profile :

export JAVA_HOME=path/to/the/jdk

export PATH=$PATH:path/to/maven/bin

Vérifiez l'installation de Maven en exécutant mvn --version dans un terminal.

Une fois Maven installé, vous pouvez désormais créer un nouveau projet Java Maven :

 mvn archetype:generate -DgroupId=com.project.scraper 

-DartifactId=jsoup-scraper-project 

-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Cela crée un nouveau dossier appelé « jsoup-scraper-project » contenant le contenu du projet.

Le point d'entrée de l'application (la classe principale) se trouvera dans le paquet « com.project.scraper ».

Exécution du projet depuis la ligne de commande

Pour exécuter un projet Java Maven depuis la ligne de commande, nous utiliserons le plugin exec-maven-plugin.

Pour installer le plugin, vous devez l'ajouter au fichier pom.xml du projet. Pour ce faire, ajoutez l'extrait de code suivant à la section <build><plugins> du fichier pom.xml :

<build>

 <plugins>

   <plugin>

     <groupId>org.codehaus.mojo</groupId>

     <artifactId>exec-maven-plugin</artifactId>

     <version>3.1.0</version>

     <executions>

       <execution>

         <goals>

           <goal>java</goal>

         </goals>

       </execution>

     </executions>

     <configuration>

       <mainClass>com.project.scraper.App</mainClass>

     </configuration>

   </plugin>

 </plugins>

</build>

Assurez-vous de sélectionner le bon chemin d'accès pour la classe principale du projet.

Utilisez mvn package exec:java dans le terminal (dans le répertoire du projet) pour exécuter le projet.

Installation de la bibliothèque JSoup

Pour installer la bibliothèque JSoup, ajoutez la dépendance suivante au fichier pom.xml de votre projet :

<dependency>

 <groupId>org.jsoup</groupId>

 <artifactId>jsoup</artifactId>

 <version>1.14.3</version>

</dependency>

Rendez-vous sur https://mvnrepository.com/artifact/org.jsoup/jsoup pour vérifier la dernière version.

Analyse du HTML en Java avec JSoup

Dans cette section, nous allons explorer le site web https://www.scrapethissite.com/pages/forms/ et voir comment extraire les informations sur les équipes de hockey. En examinant un site web réel, vous comprendrez les concepts et les techniques utilisés dans le web scraping avec JSoup et comment vous pourriez les appliquer à vos propres projets.

Récupération du code HTML

Pour récupérer le code HTML du site web, vous devez lui envoyer une requête HTTP. Dans JSoup, la méthode connect() est utilisée pour établir une connexion vers une URL spécifiée. Elle renvoie un objet Connection, qui peut être utilisé pour configurer la requête et récupérer la réponse du serveur.

Voyons comment utiliser la méthode connect() pour récupérer le code HTML de notre URL, puis l'enregistrer dans un fichier HTML local (hockey.html) :

package com.project.scraper;

import org.jsoup.Jsoup;

import org.jsoup.nodes.Document;

import java.io.*;

import java.io.IOException;

public class App

{

   public static void main( String[] args )

   {

       String RAW_HTML;

       try {

           Document document = Jsoup.connect("https://www.scrapethissite.com/pages/forms/")

                   .get();

           RAW_HTML = document.html();

           FileWriter writer = new FileWriter("hockey.html");

           writer.write(RAW_HTML);

           writer.close();

       } catch (IOException e) {

           e.printStackTrace();

       }

   }

}

Nous pouvons maintenant ouvrir le fichier et examiner la structure du code HTML à l'aide des outils de développement :

Webpage showing an HTML table of hockey team statistics, with browser developer tools open beside it

Les données dont nous avons besoin se trouvent dans un tableau HTML sur la page. Maintenant que nous avons accédé à la page, nous pouvons extraire le contenu du tableau à l'aide de sélecteurs.

Écrire des sélecteurs

Les sélecteurs de JSoup présentent des similitudes avec ceux de JavaScript. Tous deux ont une syntaxe similaire et vous permettent de sélectionner des éléments d'un document HTML en fonction de leur nom de balise, de leur classe, de leur identifiant et de leurs propriétés CSS.

Voici quelques-uns des principaux sélecteurs que vous pouvez utiliser avec JSoup :

  • getElementsByTag() : sélectionne les éléments en fonction de leur nom de balise.
  • getElementsByClass() : sélectionne les éléments en fonction de leur nom de classe.
  • getElementById() : sélectionne un élément en fonction de son identifiant.
  • select() : sélectionne des éléments en fonction d'un sélecteur CSS (similaire à querySelectorAll)

Utilisons maintenant certains d'entre eux pour extraire tous les noms d'équipes :

try {

   Document document = Jsoup.connect("https://www.scrapethissite.com/pages/forms/")

           .get();

   Elements rows = document.getElementsByTag("tr");

   for(Element row : rows) {

      

       Elements teamName = row.getElementsByClass("name");

      

       if(teamName.text().compareTo("") != 0)

           System.out.println(teamName.text());

      

   }

} catch (IOException e) {

   e.printStackTrace();

}

// Prints the team names:

Boston Bruins

Buffalo Sabres

Calgary Flames

Chicago Blackhawks

Detroit Red Wings

Edmonton Oilers

Hartford Whalers

...

Nous avons parcouru chaque ligne et, pour chacune d'entre elles, nous avons affiché le nom de l'équipe à l'aide du sélecteur de classe « name ».

Le dernier exemple met en évidence la flexibilité et la possibilité d'appliquer plusieurs fois des méthodes de sélection aux éléments qui ont été extraits. Cela est particulièrement utile lorsqu'on traite des documents HTML complexes et volumineux.

Voici une autre version qui utilise les flux Java et la méthode select() pour afficher tous les noms d'équipes :

try {

   Document document = Jsoup.connect("https://www.scrapethissite.com/pages/forms/")

           .get();

   Elements teamNamesElements = document.select("table .team .name");

   String[] teamNames = teamNamesElements.stream()

                                         .map(element -> element.text())

                                         .toArray(String[]::new);

   for (String teamName : teamNames) {

       System.out.println(teamName);

   }

} catch (IOException e) {

   e.printStackTrace();

}

// Also prints the team names:

Boston Bruins

Buffalo Sabres

Calgary Flames

...

Affichons maintenant tous les en-têtes et toutes les lignes du tableau :

try {

   Document document = Jsoup.connect("https://www.scrapethissite.com/pages/forms/")

           .get();

   Elements tableHeadersElements = document.select("table th");

   Elements tableRowsElements = document.select("table .team");

   String[] tableHeaders =

   tableHeadersElements.stream()

                       .map(element -> element.text())

                       .toArray(String[]::new);

   String[][] tableRows =

   tableRowsElements.stream()

            .map(

                table_row -> table_row

                .select("td")

                .stream()

                .map(row_element -> row_element.text())

                .toArray(String[]::new)

               )

            .toArray(String[][]::new);

   for (int i = 0; i < tableHeaders.length; i++) {

       System.out.print(tableHeaders[i] + " ");

   }

   for (int i = 0; i < tableRows.length; i++) {

       for (int j = 0; j < tableRows[i].length; j++) {

           System.out.print(tableRows[i][j] + " ");

       }

       System.out.println();

   }

} catch (IOException e) {

   e.printStackTrace();

}

// Prints

Team Name Year Wins Losses OT Losses Win ...

Boston Bruins 1990 44 24  0.55 299 264 35 

Buffalo Sabres 1990 31 30  0.388 292 278 14 

Calgary Flames 1990 46 26  0.575 344 263 81 

Chicago Blackhawks 1990 49 23  0.613 284 211 73 

Detroit Red Wings 1990 34 38  0.425 273 298 -25

...

Notez que nous avons utilisé des flux pour stocker les lignes. Voici une méthode plus simple pour y parvenir, en utilisant des boucles « for » :

String[][] tableRows = new String[tableRowsElements.size()][];

for (int i = 0; i < tableRowsElements.size(); i++) {

   Element table_row = tableRowsElements.get(i);

   Elements tableDataElements = table_row.select("td");

   String[] rowData = new String[tableDataElements.size()];

   for (int j = 0; j < tableDataElements.size(); j++) {

       Element row_element = tableDataElements.get(j);

       String text = row_element.text();

       rowData[j] = text;

   }

   tableRows[i] = rowData;

}

Gestion de la pagination

Lors de l'extraction de données d'un site web, il est courant que les informations soient réparties sur plusieurs pages. Afin de récupérer toutes les données pertinentes, il est nécessaire d'envoyer des requêtes à chaque page du site web et d'extraire les informations de chacune d'entre elles. Nous pouvons facilement implémenter cette fonctionnalité dans notre projet.

Paginated stats table on scrapethissite.com with page number links below the table

Il suffit de modifier le paramètre de requête page_num dans l'URL et d'effectuer une nouvelle requête HTTP avec la méthode connect().

int pageLimit = 25;

String [] tableHeaders = new String[0];

Vector<String[][]> rowsGroups = new Vector<String [][]>();

for (int currentPage=1; currentPage<pageLimit; currentPage++) {

   try {

       Document document = Jsoup.connect("https://www.scrapethissite.com/pages/forms/?page_num=" + currentPage)

               .get();

       if(currentPage == 1) {

           Elements tableHeadersElements = document.select("table th");

           tableHeaders = tableHeadersElements.stream()

                   .map(element -> element.text())

                   .toArray(String[]::new);

       }

       Elements tableRowsElements = document.select("table .team");

       String[][] tableRows = new String[tableRowsElements.size()][];

       for (int i = 0; i < tableRowsElements.size(); i++) {

           Element table_row = tableRowsElements.get(i);

           Elements tableDataElements = table_row.select("td");

           String[] rowData = new String[tableDataElements.size()];

           for (int j = 0; j < tableDataElements.size(); j++) {

               Element row_element = tableDataElements.get(j);

               String text = row_element.text();

               rowData[j] = text;

           }

           tableRows[i] = rowData;

       }

       rowsGroups.add(tableRows);

   } catch (IOException e) {

       e.printStackTrace();

   }

   // do something with the headers and the the table rows groups

}

Comme les tableaux de chaque page ont les mêmes en-têtes, veillez à ne pas les extraire plusieurs fois.

Le code complet

Voici le code complet qui extrait tous les tableaux du site web https://www.scrapethissite.com/pages/forms/. J'ai également inclus une fonction qui enregistre les données au format .CSV :

package com.project.scraper;

import org.jsoup.Jsoup;

import org.jsoup.nodes.Document;

import org.jsoup.nodes.Element;

import org.jsoup.select.Elements;

import java.io.*;

import java.io.IOException;

import java.util.Vector;

public class App

{

   public static void main( String[] args )

   {

       int pageLimit = 25;

       String [] tableHeaders = new String[0];

       Vector<String[][]> rowsGroups = new Vector<String [][]>();

       for (int currentPage=1; currentPage<pageLimit; currentPage++) {

           try {

               Document document = Jsoup.connect("https://www.scrapethissite.com/pages/forms/?page_num=" + currentPage)

                       .get();

               if(currentPage == 1) {

                   Elements tableHeadersElements = document.select("table th");

                   tableHeaders = tableHeadersElements.stream()

                           .map(element -> element.text())

                           .toArray(String[]::new);

               }

               Elements tableRowsElements = document.select("table .team");

               String[][] tableRows = new String[tableRowsElements.size()][];

               for (int i = 0; i < tableRowsElements.size(); i++) {

                   Element table_row = tableRowsElements.get(i);

                   Elements tableDataElements = table_row.select("td");

                   String[] rowData = new String[tableDataElements.size()];

                   for (int j = 0; j < tableDataElements.size(); j++) {

                       Element row_element = tableDataElements.get(j);

                       String text = row_element.text();

                       rowData[j] = text;

                   }

                   tableRows[i] = rowData;

               }

               rowsGroups.add(tableRows);

           } catch (IOException e) {

               e.printStackTrace();

           }

       }

       writeFullTableToCSV(rowsGroups, tableHeaders, "full_table.csv");

   }

   public static void writeFullTableToCSV(Vector<String[][]> rowsGroups, String[] headers, String fileName) {

       File file = new File(fileName);

       try {

           FileWriter writer = new FileWriter(file);

           // write the headers first

           for (int i = 0; i < headers.length; i++) {

               writer.append(headers[i]);

               if (i != headers.length - 1) {

                   writer.append(",");

               }

           }

           writer.append("\n");

           // write all the rows groups

           for (String [][] rowsGroup : rowsGroups) {

               for (String[] row : rowsGroup) {

                   for (int i = 0; i < row.length; i++) {

                       writer.append(row[i]);

                       if (i != row.length - 1) {

                           writer.append(",");

                       }

                   }

                   writer.append("\n");

               }

           }

           writer.flush();

           writer.close();

       } catch (IOException e) {

           e.printStackTrace();

       }

   }

}

Conclusion

Dans cet article, nous avons vu comment installer Maven et créer un nouveau projet Java Maven, ainsi que comment exécuter le projet depuis la ligne de commande. Nous avons également abordé l'installation de la bibliothèque JSoup en ajoutant la dépendance au fichier pom.xml du projet. Enfin, nous avons examiné un exemple d'utilisation de JSoup pour analyser du code HTML et extraire des données d'un site web. En suivant les étapes décrites dans cet article, vous devriez disposer d'une base solide pour mettre en place un projet JSoup et commencer à extraire des données de sites web. JSoup offre un large éventail d'options et de possibilités pour le web scraping, et je vous encourage à les explorer et à les appliquer à vos propres projets.

Comme vous l'avez vu, les données sont souvent partagées entre plusieurs pages web. Envoyer des requêtes à un rythme soutenu vers le même domaine peut entraîner le bannissement de votre adresse IP. Avec notre produit, WebScrapingAPI, vous n'aurez plus jamais à vous soucier de ce genre de problèmes. Notre API vous garantit de pouvoir effectuer autant de requêtes que nécessaire. Et le meilleur dans tout ça, c'est que vous pouvez l'essayer gratuitement.

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