Volver al blog
Guías
Sorin-Gabriel MaricaLast updated on Mar 31, 20269 min read

La guía definitiva para iniciarse en el web scraping con Go

La guía definitiva para iniciarse en el web scraping con Go

El web scraping con Go es una forma estupenda de crear un rastreador rápido y potente. Esto se debe a que GoLang es uno de los mejores lenguajes de programación que se pueden utilizar para la concurrencia. Pero antes de entrar en materia, debo explicarte primero en qué consiste el web scraping y cómo puede ayudarte.

El web scraping es el proceso de extraer datos de sitios web. Este proceso se puede realizar manualmente, pero este enfoque no es recomendable cuando se trata de grandes cantidades de datos. En este artículo exploraremos cómo puedes crear tu propio scraper web automatizado desde cero con Go.

Si eres nuevo en esto, quizá te preguntes cuáles son algunos de los casos de uso del web scraping. Aquí tienes una pequeña lista con algunos de los más comunes:

  • Herramientas de comparación de precios: puedes crear muchas herramientas utilizando un scraper web. Una de las más comunes y útiles es una herramienta de comparación de precios. Dicha herramienta recopilaría los precios de un producto de muchas fuentes y mostraría la mejor oferta posible.
  • Aprendizaje automático: si quieres crear un modelo utilizando aprendizaje automático, necesitarás un conjunto de datos de entrenamiento. Aunque a veces puedes encontrar conjuntos de datos existentes que puedas utilizar, a menudo tendrás que hacer un trabajo adicional y obtener tú mismo los datos que necesitas.
  • Investigación de mercado: un tercer caso de uso es extraer información de Internet para averiguar quiénes son tus competidores y qué están haciendo. De esta forma, puedes mantenerte al día o adelantarte a la competencia, estando al tanto de cualquier nueva función que puedan haber añadido.

¿Qué necesitas para extraer datos con Go?

Antes de empezar, necesitarás poder ejecutar código GoLang en tu máquina. Para ello, solo tienes que instalar Go, si aún no lo has hecho. Puedes encontrar más detalles sobre cómo instalar Go y cómo comprobar si lo tienes instalado aquí.

Lo otro que necesitarás es un IDE o un editor de texto de tu elección donde escribiremos el código. Yo prefiero usar Visual Studio Code, pero siéntete libre de usar el que te parezca más adecuado.

Y eso es todo. Bastante sencillo, ¿no? Ahora pasemos al tema principal de este artículo: el web scraping con Go.

Crear un rastreador web con Go

Para crear nuestro scraper, primero necesitaremos un objetivo, un conjunto de datos que queramos recopilar de una fuente específica. Por lo tanto, como tema para nuestro scraper, he elegido extraer las descargas semanales de los primeros paquetes de npmjs.com que utilizan la palabra clave «framework». Puedes encontrarlos en esta página: https://www.npmjs.com/search?q=keywords:framework&page=0&ranking=optimal)

Inspecciona el contenido de la página que quieres rastrear

Para realizar el scraping correctamente, antes de empezar a extraer los datos, tendrás que ver dónde se encuentran. Con esto me refiero a que tendrás que crear los selectores HTML para consultar los datos, basándote en la estructura HTML de la página.

Para ver la estructura HTML de la página, puedes utilizar las herramientas de desarrollo disponibles en la mayoría de los navegadores modernos. En Chrome, puedes hacerlo en la página haciendo clic con el botón derecho del ratón sobre el elemento que deseas extraer y seleccionando «Inspeccionar página». Una vez hecho esto, verás algo como esto:

Basándonos en el HTML que se ve a la derecha (la ventana de inspección), ahora podemos crear los selectores que vamos a utilizar. De esta página solo necesitamos las URL de cada uno de los paquetes.

Al revisar el HTML, vemos que las clases CSS utilizadas por el sitio web son generadas por código. Esto hace que no sean fiables para el scraping, por lo que utilizaremos las etiquetas HTML en su lugar. En la página vemos que los paquetes se encuentran dentro de etiquetas <section> y que el enlace al paquete está en el primer div de la sección.

Sabiendo esto, podemos crear el siguiente selector para extraer los enlaces de todos los paquetes: section > div:first-child > div:first-child a. Antes de probarlo en el código, podemos comprobar el selector desde las herramientas de desarrollo del navegador. Para ello, ve a la pestaña de la consola y ejecuta document.querySelectorAll("{{ SELECTOR }}"):

Al pasar el cursor por encima de cada uno de los elementos de la lista de nodos devueltos, podemos ver que son exactamente los que buscábamos, por lo que podemos utilizar este selector.

Rastrear una página con Go

¡Por fin empezamos a crear el scraper! Para ello, primero debes crear una carpeta donde colocaremos todo nuestro código. A continuación, debes abrir una ventana de terminal, ya sea desde tu IDE o desde tu sistema operativo, y dirigirte a nuestra carpeta.

Para abrir un terminal en la carpeta, si utilizas Visual Studio Code, puedes hacer clic en Terminal -> Nuevo terminal (en la barra superior).

Ahora que tenemos la terminal abierta, es el momento de inicializar el proyecto. Puedes hacerlo ejecutando el comando:

go mod init webscrapingapi.com/my-go-scraper

Esto creará en tu carpeta un archivo llamado go.mod con el siguiente contenido:

module webscrapingapi.com/my-go-scraper
go 1.19

Para realizar la solicitud a la página y extraer los selectores del HTML, utilizaremos Colly, un paquete de GoLang (consulta la documentación de Colly para obtener más información). Para instalar este paquete, debes ejecutar

go get github.com/gocolly/colly

Ahora que lo tenemos todo preparado, solo nos queda crear nuestro archivo main.go y escribir algo de código. El código para extraer todos los enlaces de la primera página de marcos de npmjs es el siguiente:

package main

import (
    "fmt"
    "github.com/gocolly/colly"
)

func scrape() {
    c := colly.NewCollector()

    // Find and print all links
    c.OnHTML("section > div:first-child > div:first-child a", func(e *colly.HTMLElement) {
        fmt.Println(e.Attr("href"))
    })
    c.Visit("https://www.npmjs.com/search?q=keywords:framework&page=0&ranking=optimal")
}

func main() {
    scrape()
}

Si al principio te parece difícil de leer, no te preocupes, lo desglosaremos en los siguientes párrafos y te lo explicaremos. 

Todo archivo de Go debe comenzar con el nombre del paquete y las importaciones que utilizará Go. En este caso, los dos paquetes que usamos son «fmt» para imprimir los enlaces que extraemos, y «Colly» (para la extracción propiamente dicha).

En la siguiente parte, hemos creado la función scrape(), que se encarga de extraer los enlaces que necesitamos. Para ello, la función visita la primera página y espera a encontrar el selector que hemos elegido. Cuando aparece un elemento de ese selector, procede a imprimir el atributo href de dicho elemento.

La última parte es la función main, que es la función que se llama cada vez que ejecutamos un script de Go. Para ejecutar el código anterior, ejecuta go run main.go desde tu terminal, y deberías obtener el siguiente resultado:

Como puedes ver, el atributo href contiene rutas relativas a los enlaces, por lo que tendremos que anteponerle la URL de npmjs.

Usa la concurrencia de GoLang para ganar en eficiencia

Una de las características más interesantes de GoLang son las GoRoutines. Las GoRoutines son subprocesos sencillos y ligeros gestionados por el tiempo de ejecución de Go. Lo mejor de esto es que Go nos permite rastrear muchas URL al mismo tiempo a una velocidad vertiginosa.

Antes extrajimos los enlaces de los primeros 20 paquetes bajo la palabra clave «framework» en npmjs.com. Ahora intentaremos rastrear todos estos enlaces al mismo tiempo y extraer las descargas semanales de cada uno de ellos. Para ello, utilizaremos GoRoutines y WaitGroups.

Este es el código final para extraer las descargas semanales utilizando las goroutines:

package main

import (
    "fmt"
    "github.com/gocolly/colly"
    "sync"
)

func scrapeWeeklyDownloads(url string, wg *sync.WaitGroup) {
    defer wg.Done()

    c := colly.NewCollector()

    // Find and print the weekly downloads value
    c.OnHTML("main > div > div:last-child > div:not([class]) p", func(e *colly.HTMLElement) {
        fmt.Println(fmt.Sprintf("%s - %s", url, e.Text))
    })
    c.Visit(url)
}

func scrape() {
    c := colly.NewCollector()

    var wg sync.WaitGroup

    // Find and print all links
    c.OnHTML("section > div:first-child > div:first-child a", func(e *colly.HTMLElement) {
        wg.Add(1)
        go scrapeWeeklyDownloads(fmt.Sprintf("%s%s", "https://www.npmjs.com", e.Attr("href")), &wg)
    })
    c.Visit("https://www.npmjs.com/search?q=keywords:framework&page=0&ranking=optimal")

    wg.Wait()
}

func main() {
    scrape()
}

Ahora veamos qué se ha añadido a nuestro código anterior. En primer lugar, notarás que hemos importado un nuevo paquete llamado «sync». Esto nos ayudará a utilizar las rutinas de Go y a esperar a que los subprocesos terminen antes de detener la ejecución del programa.

Lo siguiente que se ha añadido es la nueva función llamada «scrapeWeeklyDownloads». Esta función acepta dos parámetros: la URL del enlace que vamos a rastrear y un puntero a un WaitGroup. Lo que hace esta función es visitar la URL dada y extraer las descargas semanales (utilizando el selector main > div > div:last-child > div:not([class]) p).

Los últimos cambios que notarás se encuentran en la función scrape, donde creamos un WaitGroup utilizando var wg sync.WaitGroup. Aquí, para cada enlace de la página de paquetes, utilizamos wg.Add(1) y luego creamos una GoRoutine que llama a la función scrapeWeeklyDownloads. Al final de la función, la instrucción wg.Wait() hace que el código espere hasta que todas las GoRoutines terminen de ejecutarse. 

Para obtener más información sobre los WaitGroups, consulta este ejemplo de Golang

¿Por qué GoRoutines y WaitGroups?

Al utilizar la concurrencia en Go con GoRoutines y WaitGroups, podemos crear un scraper muy rápido. Al ejecutar el ejemplo de código anterior, se mostrará la página y las descargas semanales de cada paquete. Sin embargo, dado que estamos utilizando multihilo, el orden en el que aparecerá esta información es impredecible (ya que los subprocesos se ejecutan a diferentes velocidades).

Si estás ejecutando el código en Linux o en el subsistema de Linux para Windows (WSL), puedes usar `time go run main.go` para ver el tiempo de ejecución de todo el script. En mi caso, el tiempo de ejecución ronda los 5 o 6 segundos. Esto es muy rápido, teniendo en cuenta que estamos rastreando 21 páginas (primero la página con los paquetes y luego las páginas de cada uno de los paquetes).

Otros obstáculos

La mayoría de los rastreadores suelen basarse en realizar una simple solicitud HTTP a la página para obtener el contenido que necesitan. Esta solución es buena, pero a veces los sitios web muestran su información mediante renderización con JavaScript. Eso significa que el sitio web primero te mostrará solo una parte de su contenido, cargando el resto de forma dinámica a través de JavaScript.

Para extraer datos de este tipo de páginas, necesitarás utilizar ChromeDriver y controlar un navegador Chrome real. Aunque existen algunas opciones para hacerlo en Golang, tendrás que investigar un poco más sobre este tema.

Incluso una vez resuelta la cuestión del renderizado de JavaScript, siguen existiendo algunos obstáculos adicionales a la hora de extraer datos de un sitio web. Algunos sitios web pueden utilizar detección de bots, bloqueos de IP o captchas para impedir que los bots extraigan su contenido. Para poder extraer datos de esos sitios web de todos modos, puedes intentar utilizar algunos consejos y trucos para la extracción de datos web, como ralentizar tu extractor y hacer que actúe de forma más similar a un humano.

Pero, si quieres mantener tu scraper rápido y superar estos obstáculos de forma sencilla, puedes utilizar WebScrapingAPI. WebScrapingAPI es una API diseñada para ayudarte con el scraping rotando tu IP y evitando las detecciones antibot. De esta forma, puedes seguir aprovechando la velocidad relámpago que ofrece GoLang y extraer tus datos en un abrir y cerrar de ojos.

Conclusión sobre el web scraping con Go

El web scraping es una forma sencilla y rápida de extraer datos de Internet, y se puede utilizar para muchos casos de uso diferentes. Puedes optar por extraer datos para tu modelo de aprendizaje automático o crear una aplicación desde cero utilizando los datos que has extraído.

GoLang es una de las mejores soluciones que existen en lo que respecta a la concurrencia. Con GoLang y Colly puedes crear un scraper rápido que te proporcionará tus datos en un abrir y cerrar de ojos. Esto hace que el web scraping con Go sea muy fácil y eficiente una vez que te acostumbras a la sintaxis de Go.

Acerca del autor
Sorin-Gabriel Marica, Desarrollador full-stack @ WebScrapingAPI
Sorin-Gabriel MaricaDesarrollador full-stack

Sorin Marica es ingeniero Full Stack y DevOps en WebScrapingAPI, donde se encarga de desarrollar funciones para los productos y de mantener la infraestructura que garantiza el buen funcionamiento de la plataforma.

Empieza a crear

¿Estás listo para ampliar tu recopilación de datos?

Únete a más de 2000 empresas que utilizan WebScrapingAPI para extraer datos de la web a escala empresarial sin ningún gasto de infraestructura.