¿Qué se necesita para el scraping de datos con go?
Antes de empezar necesitarás poder ejecutar código GoLang en tu máquina. Para ello todo lo que necesitas es 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 lo que creas conveniente.
Y ya está. Bastante simple, ¿no? Ahora vamos a sumergirnos en el tema principal de este artículo, web scraping con go.
Crear un raspador web con Go
Para crear nuestro rastreador, primero necesitaremos un objetivo: un conjunto de datos que queramos recopilar de una fuente concreta. Por eso, como tema para nuestro rastreador, he elegido recopilar las descargas semanales de los primeros paquetes de npmjs.com que utilicen la palabra clave «framework». Puedes encontrarlos en esta página: https://www.npmjs.com/search?q=keywords:framework&page=0&ranking=optimal)
Inspeccione el contenido de la página que desea raspar
Para hacer un buen scraping, antes de empezar a extraer los datos, tendrás que ver dónde están. Con esto quiero decir que tendrás que construir 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 para desarrolladores disponibles en la mayoría de los navegadores modernos. En Chrome, puede hacerlo en la página haciendo clic con el botón derecho en el elemento que desea extraer y haciendo clic en "Inspeccionar página". Una vez hecho esto verás algo como esto:

Basándonos en el HTML que puedes ver a la derecha (la ventana de inspección), ahora podemos construir los selectores que utilizaremos. De esta página sólo necesitamos las URLs de cada uno de los paquetes.
By looking over the HTML, we can see that the css classes used by the website are code generated. This makes them not reliable for scraping so we will use the html tags instead. On the page we can see that the packages are in <section> tags and that the link to the package is in the first div from the first div of the section.
Knowing this we can build the following selector to extract the links of all the packages: section > div:first-child > div:first-child a. Before trying it in code, we can test the selector from the developer tools of the browser. To do this go to the console tab and run document.querySelectorAll("{{ SELECTOR }}"):

Al pasar el ratón por encima de cada uno de los elementos nodelist devueltos, podemos ver que son exactamente los que estábamos buscando, por lo que podemos utilizar este selector.
Raspado de una página con Go
¡Por fin empezamos a construir el scraper! Para ello, primero debes crear una carpeta donde pondremos todo nuestro código. A continuación, tienes que abrir una ventana de terminal, ya sea desde tu IDE o desde tu sistema operativo e ir a nuestra carpeta.
Para abrir un terminal en la carpeta, en Visual Studio Code puedes hacer clic en «Terminal» -> «Nuevo terminal» (en la barra superior).

Ahora que tenemos nuestro terminal abierto, es hora 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:
módulo webscrapingapi.com/my-go-scraper
Go 1.19
Para realizar la petición a la página y extraer los selectores del HTML, utilizaremos Colly, un paquete de GoLang(consulta la documentación de Colly para más información). Para instalar este paquete tienes que ejecutar
ir a github.com/gocolly/colly
Ahora que tenemos todo preparado, todo lo que necesitamos hacer es 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 frameworks 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 esto parece difícil de leer al principio, no se preocupe, en los párrafos siguientes lo desglosaremos y explicaremos.
Cada archivo golang debe comenzar con el nombre del paquete y las importaciones que Go utilizará. En este caso los dos paquetes que utilizamos son "fmt" para imprimir los enlaces que raspamos, y "Colly" (para el raspado real).
En la siguiente parte, creamos la función scrape() que se encarga de scrapear los enlaces que necesitamos. Para ello la función visita la primera página, y espera a encontrar el selector que decidimos. Cuando aparece un elemento de ese selector, sigue adelante e imprime el atributo href de ese elemento.
La última parte es la función main que es la función que se llama cada vez que ejecutamos un script golang. Para ejecutar el código anterior ejecuta main.go desde tu terminal, y deberías obtener la siguiente salida:

Como puedes ver, el atributo href tiene rutas relativas a los enlaces, por lo que necesitaremos anteponerle la url de npmjs.
Utilizar la concurrencia de GoLang en aras de la eficiencia
Una de las características más interesantes de GoLang son las GoRoutines. GoRoutines son simples hilos ligeros gestionados por el tiempo de ejecución Go. Lo bueno de esto es que Go puede ayudarnos a scrapear muchas urls al mismo tiempo con una velocidad de vértigo.
Antes hemos extraído los enlaces de los 20 primeros paquetes bajo la palabra clave "framework" en npmjs.com. Ahora intentaremos extraer todos estos enlaces al mismo tiempo y extraer las descargas semanales de cada uno de ellos. Para ello utilizaremos GoRoutines y WaitGroups.
Aquí está 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 vamos a discutir lo que se ha añadido a nuestro código anterior. Primero notarás que tenemos un nuevo paquete importado llamado "sync". Esto nos ayudará a utilizar rutinas golang y esperar a que los hilos terminen, antes de detener la ejecución del programa.
Lo siguiente que se añade es la nueva función llamada «scrapeWeeklyDownloads». Esta función admite dos parámetros: la URL del enlace que vamos a rastrear y un puntero a WaitGroup. Lo que hace esta función es visitar la URL indicada y extraer las descargas semanales (utilizando el selector main > div > div:last-child > div:not([class]) p).
Los últimos cambios que notarás fueron en la función scrape donde creamos un WaitGroup usando var wg sync.WaitGroup. Aquí, para cada enlace de la página de paquetes, usamos 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 más información sobre WaitGroups por favor revisa este ejemplo de golang.
¿Por qué GoRoutines y WaitGroups?
Usando concurrencia en golang con GoRoutines y WaitGroups podemos crear un scraper muy rápido. Ejecutando el ejemplo de código anterior nos devolverá la página y las descargas semanales de cada paquete. Pero, debido a que estamos usando multihilos, el orden en el que se mostrará esta información es desconocido (ya que los hilos se ejecutan a diferentes velocidades).
Si estás ejecutando el código usando linux o windows subsystem linux (wsl), puedes usar time go run main.go para ver el tiempo de ejecución de todo el script. Para mí, el tiempo de ejecución es de alrededor de 5 a 6 segundos. Esto es muy rápido, teniendo en cuenta que estamos raspando 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 scrapers suelen contar con hacer una simple petición 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 renderizado javascript. Esto significa que el sitio web le mostrará primero sólo una parte de su contenido, cargando el resto dinámicamente a través de javascript.
Para scrapear tales páginas necesitarás usar chromedriver y controlar un navegador chrome real. Si bien hay algunas opciones para hacer esto en Golang, usted tendrá que hacer un poco de investigación adicional para este tema.
Incluso con la renderización javascript cubierta, todavía hay algunos obstáculos adicionales cuando se raspa un sitio web. Algunos sitios web pueden utilizar detecciones antibot, bloqueos de IP o captchas para evitar que los bots raspen su contenido. Para seguir haciendo scraping de esos sitios web, puedes intentar utilizar algunos consejos y trucos para el scraping web, como hacer que tu scraper sea más lento y actúe de forma más humana.
Pero, si usted quiere mantener su raspador rápido y hacer frente a estos obstáculos de una manera fácil, puede utilizar WebScrapingAPI. WebScrapingAPI es una API diseñada para ayudarte con el scraping rotando tu IP y evitando detecciones antibot. De esta manera puedes seguir usando la velocidad relámpago que proporciona GoLang y raspar tus datos en poco tiempo.
Conclusión sobre Web Scraping con Go
Web Scraping es una forma agradable y rápida de extraer datos de Internet, y se puede utilizar para muchos casos de uso diferentes. Puedes elegir entre extraer datos para tu modelo de aprendizaje automático o crear una aplicación desde cero utilizando los datos que has raspado.
GoLang es una de las mejores soluciones cuando se trata de concurrencia. Usando GoLang y Colly puedes construir un scraper rápido que traerá tus datos en poco tiempo. Esto hace que el raspado web con Go sea muy fácil y eficiente una vez que te acostumbras a la sintaxis de Go.




