Web Scraping a la manera de Java

    Introducci贸n

    Por definici贸n, web scraping se refiere al proceso de extraer una cantidad significativa de informaci贸n de un sitio web mediante scripts o programas. Dichos scripts o programas permiten extraer datos de un sitio web, almacenarlos y presentarlos como los dise帽贸 el creador. Los datos recopilados tambi茅n pueden ser parte de un proyecto m谩s grande que utiliza los datos extra铆dos como entrada.

    Anteriormente, para extraer datos de un sitio web, ten铆a que abrir manualmente el sitio web en un navegador y emplear la antigua pero dorada funcionalidad de copiar y pegar. Este m茅todo funciona, pero su principal inconveniente es que puede resultar agotador si la cantidad de sitios web es grande o si hay mucha informaci贸n. Tampoco se puede automatizar.

    Con web scraping, no solo puede automatizar el proceso, sino tambi茅n escalar el proceso para manejar tantos sitios web como lo permitan sus recursos inform谩ticos.

    En esta publicaci贸n, exploraremos el web scraping utilizando el lenguaje Java. Tambi茅n espero que est茅 familiarizado con los conceptos b谩sicos del lenguaje Java y tenga Java 8 instalado en su m谩quina.

    驴Por qu茅 Web Scraping?

    El proceso de web scraping presenta varias ventajas que incluyen:

    • El tiempo necesario para extraer informaci贸n de una fuente en particular se reduce significativamente en comparaci贸n con copiar y pegar los datos manualmente.
    • Los datos extra铆dos son m谩s precisos y tienen un formato uniforme, lo que garantiza la coherencia.
    • Un raspador de banda se puede integrar en un sistema y alimentar datos directamente en el sistema mejorando la automatizaci贸n.
    • Algunos sitios web y organizaciones no proporcionan API que proporcionen la informaci贸n en sus sitios web. Las API facilitan la extracci贸n de datos, ya que son f谩ciles de consumir desde otras aplicaciones. En su ausencia, podemos utilizar web scraping para extraer informaci贸n.

    El web scraping es ampliamente utilizado en la vida real por las organizaciones de las siguientes formas:

    • Los motores de b煤squeda como Google y DuckDuckGo implementan el raspado web para indexar sitios web que finalmente aparecen en los resultados de b煤squeda.
    • Los equipos de comunicaci贸n y marketing de algunas empresas utilizan scrapers para extraer informaci贸n sobre sus organizaciones en Internet. Esto les ayuda a identificar su reputaci贸n en l铆nea y trabajar para mejorarla.
    • El web scraping tambi茅n se puede utilizar para mejorar el proceso de identificaci贸n y seguimiento de las 煤ltimas historias y tendencias en Internet.
    • Algunas organizaciones utilizan el web scraping para estudios de mercado donde extraen informaci贸n sobre sus productos y tambi茅n sobre sus competidores.

    Estas son algunas de las formas en que se puede utilizar el web scraping y c贸mo puede afectar las operaciones de una organizaci贸n.

    Que utilizar

    Hay varias herramientas y bibliotecas implementadas en Java, as铆 como API externas, que podemos usar para construir web scrapers. El siguiente es un resumen de algunos de los m谩s populares:

    • JSoup – esta es una biblioteca simple de c贸digo abierto que proporciona una funcionalidad muy conveniente para extraer y manipular datos mediante el uso de DOM transversal o selectores CSS para encontrar datos. No admite el an谩lisis basado en XPath y es compatible con principiantes. Puede encontrar m谩s informaci贸n sobre el an谩lisis de XPath Aqu铆.
    • HTMLUnit – es un marco m谩s poderoso que puede permitirle simular eventos del navegador, como hacer clic y enviar formularios al raspar, y tambi茅n tiene soporte para JavaScript. Esto mejora el proceso de automatizaci贸n. Tambi茅n es compatible con el an谩lisis basado en XPath, a diferencia de JSoup. Tambi茅n se puede utilizar para pruebas unitarias de aplicaciones web.
    • Excursi贸n – esta es una biblioteca de automatizaci贸n web y scraping que se puede usar para extraer datos de p谩ginas HTML o cargas 煤tiles de datos JSON mediante un navegador sin cabeza. Puede ejecutar y manejar solicitudes y respuestas HTTP individuales y tambi茅n puede interactuar con API REST para extraer datos. Recientemente se ha actualizado para incluir compatibilidad con JavaScript.

    Estas son solo algunas de las bibliotecas que puede utilizar para eliminar sitios web que utilizan el lenguaje Java. En esta publicaci贸n, trabajaremos con JSoup.

    Implementaci贸n simple

    Habiendo aprendido las ventajas, los casos de uso y algunas de las bibliotecas que podemos usar para lograr el raspado web con Java, implementemos un raspador simple usando la biblioteca JSoup. Vamos a eliminar este sencillo sitio web que encontr茅: CodeTriage que muestra proyectos de c贸digo abierto a los que puede contribuir en Github y que se pueden ordenar por idiomas.

    Aunque hay API disponibles que brindan esta informaci贸n, lo encuentro un buen ejemplo para aprender o practicar el raspado web.

    Prerrequisitos

    Antes de continuar, aseg煤rese de tener lo siguiente instalado en su computadora:

    Vamos a utilizar Maven para gestionar nuestro proyecto en t茅rminos de generaci贸n, empaque, gesti贸n de dependencias, pruebas entre otras operaciones.

    Verifique que Maven est茅 instalado ejecutando el siguiente comando:

    $ mvn --version
    

    La salida debe ser similar a:

    Apache Maven 3.5.4 (1edded0938998edf8bf061f1ceb3cfdeccf443fe; 2018-06-17T21:33:14+03:00)
    Maven home: /usr/local/Cellar/Maven/3.5.4/libexec
    Java version: 1.8.0_171, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre
    Default locale: en_KE, platform encoding: UTF-8
    OS name: "mac os x", version: "10.14.1", arch: "x86_64", family: "mac"
    

    Preparar

    Con Maven configurado correctamente, generemos nuestro proyecto ejecutando el siguiente comando:

    $ mvn archetype:generate -DgroupId=com.codetriage.scraper -DartifactId=codetriagescraper -DarchetypeArtifactId=Maven-archetype-quickstart -DinteractiveMode=false
    $ cd codetriagescraper
    

    Esto generar谩 el proyecto que contendr谩 nuestro raspador.

    En la carpeta generada, hay un archivo llamado pom.xml que contiene detalles sobre nuestro proyecto y tambi茅n las dependencias. Aqu铆 es donde agregaremos la dependencia de JSoup y una configuraci贸n de plugin para permitir que Maven incluya las dependencias del proyecto en el archivo jar producido. Tambi茅n nos permitir谩 ejecutar el archivo jar usando java -jar mando.

    Eliminar el dependencies secci贸n en el pom.xml y reempl谩celo con este fragmento, que actualiza las dependencias y las configuraciones del plugin:

      <dependencies>
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.12</version>
              <scope>test</scope>
          </dependency>
         <!-- our scraping library -->
          <dependency>
              <groupId>org.jsoup</groupId>
              <artifactId>jsoup</artifactId>
              <version>1.11.3</version>
          </dependency>
      </dependencies>
    
      <build>
          <plugins>
              <!--
              This plugin configuration will enable Maven to include the project dependencies
              in the produced jar file.
              It also enables us to run the jar file using `java -jar command`
              -->
              <plugin>
                  <groupId>org.apache.Maven.plugins</groupId>
                  <artifactId>Maven-shade-plugin</artifactId>
                  <version>3.2.0</version>
                  <executions>
                      <execution>
                          <phase>package</phase>
                          <goals>
                              <goal>shade</goal>
                          </goals>
                          <configuration>
                              <transformers>
                                  <transformer
                                          implementation="org.apache.Maven.plugins.shade.resource.ManifestResourceTransformer">
                                      <mainClass>com.codetriage.scraper.App</mainClass>
                                  </transformer>
                              </transformers>
                          </configuration>
                      </execution>
                  </executions>
              </plugin>
          </plugins>
      </build>
    

    Verifiquemos nuestro trabajo hasta ahora ejecutando los siguientes comandos para compilar y ejecutar nuestro proyecto:

    $ mvn package
    $ java -jar target/codetriagescraper-1.0-SNAPSHOT.jar
    

    El resultado debe ser Hello World! impreso en la consola. Estamos listos para comenzar a construir nuestro raspador.

    Implementaci贸n

    Antes de implementar nuestro scraper, necesitamos crear un perfil del sitio web que vamos a eliminar para ubicar los datos que pretendemos eliminar.

    Para lograr esto, necesitamos abrir el CodeTriage sitio web y seleccione Java Language en un navegador e inspeccione el c贸digo HTML con las herramientas de desarrollo.

    En Chrome, haga clic derecho en la p谩gina y seleccione “Inspeccionar” para abrir las herramientas de desarrollo.

    El resultado deber铆a verse as铆:

    Como puede ver, podemos recorrer el HTML e identificar en qu茅 parte del DOM se encuentra la lista de repositorios.

    Desde el HTML, podemos ver que los repositorios est谩n contenidos en una lista desordenada cuya clase es repo-list. En su interior est谩n los elementos de la lista que contienen la informaci贸n del repositorio que requerimos, como se puede ver en la siguiente captura de pantalla:

    Cada repositorio est谩 contenido en una entrada de elemento de lista cuyo class atributo es repo-item y la clase incluye una etiqueta de anclaje que contiene la informaci贸n que necesitamos. Dentro de la etiqueta de anclaje, tenemos una secci贸n de encabezado que contiene el nombre del repositorio y la cantidad de problemas. A esto le sigue una secci贸n de p谩rrafo que contiene la descripci贸n y el nombre completo del repositorio. Esta es la informaci贸n que necesitamos.

    Construyamos ahora nuestro raspador para capturar esta informaci贸n. Abre el App.java archivo que deber铆a verse un poco as铆:

    package com.codetriage.scraper;
    
    import java.io.IOException;
    
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    import org.jsoup.select.Elements;
    
    
    public class App {
    
      public static void main(String[] args) {
        System.out.println( "Hello World!" );
      }
    }
    

    En la parte superior del archivo, importamos IOException y algunas clases de JSoup que nos ayudar谩n a analizar los datos.

    Para construir nuestro raspador, modificaremos nuestra funci贸n principal para manejar las tareas de raspado. As铆 que comencemos imprimiendo el t铆tulo de la p谩gina web en el terminal usando el siguiente c贸digo:

      public static void main(String[] args) {
         try {
           // Here we create a document object and use JSoup to fetch the website
           Document doc = Jsoup.connect("https://www.codetriage.com/?language=Java").get();
    
           // With the document fetched, we use JSoup's title() method to fetch the title
           System.out.printf("Title: %sn", doc.title());
    
         // In case of any IO errors, we want the messages written to the console
         } catch (IOException e) {
           e.printStackTrace();
         }
      }
    

    Guarde el archivo y ejecute el siguiente comando para probar lo que hemos escrito hasta ahora:

    $ mvn package && java -jar target/codetriagescraper-1.0-SNAPSHOT.jar
    

    La salida debe ser la siguiente:

    Nuestro raspador est谩 tomando forma y ahora podemos extraer m谩s datos del sitio web.

    Identificamos que los repositorios que necesitamos todos tienen un nombre de clase de repo-item, usaremos esto junto con JSoup getElementsByClass() funci贸n, para obtener todos los repositorios de la p谩gina.

    Para cada elemento del repositorio, el nombre del repositorio est谩 contenido en un elemento de encabezado que tiene el nombre de la clase repo-item-title, el n煤mero de problemas est谩 contenido en un intervalo cuya clase es repo-item-issues. La descripci贸n del repositorio est谩 contenida en un elemento de p谩rrafo cuya clase es repo-item-description, y el nombre completo que podemos usar para generar el enlace de Github cae dentro de un intervalo con la clase repo-item-full-name.

    Usaremos la misma funci贸n getElementsByClass() para extraer la informaci贸n anterior, pero el alcance estar谩 dentro de un solo elemento del repositorio. Esa es mucha informaci贸n de un tir贸n, as铆 que describir茅 cada paso en los comentarios de la siguiente parte de nuestro programa. Volvemos a nuestro m茅todo principal y lo ampliamos de la siguiente manera:

     public static void main(String[] args) {
        try {
          // Here we create a document object and use JSoup to fetch the website
          Document doc = Jsoup.connect("https://www.codetriage.com/?language=Java").get();
    
          // With the document fetched, we use JSoup's title() method to fetch the title
          System.out.printf("Title: %sn", doc.title());
    
          // Get the list of repositories
          Elements repositories = doc.getElementsByClass("repo-item");
    
          /**
           * For each repository, extract the following information:
           * 1. Title
           * 2. Number of issues
           * 3. Description
           * 4. Full name on github
           */
          for (Element repository : repositories) {
            // Extract the title
            String repositoryTitle = repository.getElementsByClass("repo-item-title").text();
    
            // Extract the number of issues on the repository
            String repositoryIssues = repository.getElementsByClass("repo-item-issues").text();
    
            // Extract the description of the repository
            String repositoryDescription = repository.getElementsByClass("repo-item-description").text();
    
            // Get the full name of the repository
            String repositoryGithubName = repository.getElementsByClass("repo-item-full-name").text();
    
            // The reposiory full name contains brackets that we remove first before generating the valid Github link.
            String repositoryGithubLink = "https://github.com/" + repositoryGithubName.replaceAll("[()]", "");
    
            // Format and print the information to the console
            System.out.println(repositoryTitle + " - " + repositoryIssues);
            System.out.println("t" + repositoryDescription);
            System.out.println("t" + repositoryGithubLink);
            System.out.println("n");
          }
    
        // In case of any IO errors, we want the messages written to the console
        } catch (IOException e) {
          e.printStackTrace();
        }
    }
    

    Ahora compilemos y ejecutemos nuestro raspador mejorado con el mismo comando:

    $ mvn package && java -jar target/codetriagescraper-1.0-SNAPSHOT.jar
    

    La salida del programa deber铆a verse as铆:

    隆Si! Nuestro raspador funciona siguiendo la captura de pantalla de arriba. Hemos logrado escribir un programa simple que extraer谩 informaci贸n de CodeTriage para nosotros y la imprimir谩 en nuestro terminal.

    Por supuesto, este no es el lugar de descanso final para esta informaci贸n, puede almacenarla en una base de datos y representarla en una aplicaci贸n u otro sitio web o incluso publicarla en una API para que se muestre en una extensi贸n de Chrome. Las oportunidades son muchas y depende de usted decidir qu茅 quiere hacer con los datos.

    Conclusi贸n

    En esta publicaci贸n, hemos aprendido sobre el raspado web usando el lenguaje Java y hemos construido un raspador funcional usando la biblioteca JSoup simple pero poderosa.

    Entonces, ahora que tenemos el raspador y los datos, 驴qu茅 sigue? El web scraping es m谩s de lo que hemos cubierto. Por ejemplo: llenado de formularios, simulaci贸n de eventos de usuario como hacer clic, y hay m谩s bibliotecas que pueden ayudarlo a lograrlo. La pr谩ctica es tan importante como 煤til, as铆 que cree m谩s raspadores que cubran nuevos terrenos de complejidad con cada uno nuevo e incluso con diferentes bibliotecas para ampliar sus conocimientos. Tambi茅n puede integrar raspadores en sus proyectos existentes o nuevos.

    El c贸digo fuente del raspador est谩 disponible en Github para referencia.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *