Voltar ao blogue
Guias
Sorin-Gabriel MaricaLast updated on Apr 22, 20269 min read

O guia definitivo sobre como começar a fazer web scraping com Go

O guia definitivo sobre como começar a fazer web scraping com Go

O web scraping com Go é uma excelente forma de criar um scraper rápido e potente. Isto porque o GoLang é uma das melhores linguagens de programação que se pode utilizar para a programação concorrente. Mas antes de entrarmos de cabeça no assunto, devo primeiro explicar-lhe melhor o que é o web scraping e como este pode ajudá-lo.

O web scraping é o processo de extrair dados de sites. Este processo pode ser feito manualmente, mas esta abordagem não é recomendada quando se lida com grandes quantidades de dados. Neste artigo, vamos explorar como pode construir o seu próprio scraper web automatizado a partir do zero com Go.

Se é novo nisto, poderá perguntar-se quais são alguns dos casos de utilização do Web Scraping. Aqui está uma pequena lista com alguns dos mais comuns:

  • Ferramentas de comparação de preços - Pode criar muitas ferramentas utilizando um web scraper. Uma das mais comuns e úteis é uma ferramenta de comparação de preços. Essa ferramenta iria extrair os preços de um produto de várias fontes e apresentar a melhor oferta possível.
  • Aprendizagem Automática - Se quiser construir um modelo utilizando aprendizagem automática, irá precisar de um conjunto de dados de treino. Embora por vezes possa encontrar conjuntos de dados existentes que possa utilizar, muitas vezes terá de fazer algum trabalho extra e obter os dados de que necessita por si próprio.
  • Estudo de mercado - Um terceiro caso de utilização consiste em extrair informações da Internet para descobrir quem são os seus concorrentes e o que estão a fazer. Desta forma, pode acompanhar ou manter-se à frente da concorrência, estando a par de qualquer nova funcionalidade que possam ter adicionado.

O que vai precisar para extrair dados com Go

Antes de começarmos, terá de poder executar código GoLang na sua máquina. Para isso, basta instalar o Go, caso ainda não o tenha feito. Pode encontrar mais detalhes sobre como instalar o Go e como verificar se já o tem instalado aqui.

Outra coisa de que vai precisar é de um IDE ou de um editor de texto à sua escolha, onde iremos escrever o código. Eu prefiro usar o Visual Studio Code, mas sinta-se à vontade para usar o que achar mais adequado.

E é isso. Bastante simples, não é? Agora vamos mergulhar no tema principal deste artigo: web scraping com Go.

Criar um web scraper usando Go

Para criar o nosso scraper, precisamos primeiro de um objetivo, um conjunto de dados que queremos recolher de uma fonte específica. Assim, como tema para o nosso scraper, escolhi extrair os downloads semanais dos primeiros pacotes do npmjs.com que utilizam a palavra-chave «framework». Podes encontrá-los nesta página: https://www.npmjs.com/search?q=keywords:framework&page=0&ranking=optimal)

Inspecione o conteúdo da página que pretende extrair

Para fazer o scraping corretamente, antes de começar a extrair os dados, terá de ver onde os dados se encontram. Com isto quero dizer que terá de criar os seletores HTML para consultar os dados, com base na estrutura HTML da página.

Para ver a estrutura HTML da página, pode usar as ferramentas de desenvolvimento disponíveis na maioria dos navegadores modernos. No Chrome, pode fazer isto na página clicando com o botão direito do rato no elemento que pretende extrair e clicando em “Inspecionar página”. Depois de fazer isso, verá algo como isto:

Com base no HTML que pode ver à direita (na janela de inspeção), podemos agora criar os seletores que iremos utilizar. Desta página, precisamos apenas dos URLs de cada um dos pacotes.

Ao analisar o HTML, podemos ver que as classes CSS utilizadas pelo site são geradas por código. Isto torna-as pouco fiáveis para a extração de dados, pelo que utilizaremos as tags HTML em vez disso. Na página, podemos ver que os pacotes estão em tags <section> e que o link para o pacote se encontra na primeira div da primeira div da secção.

Sabendo isto, podemos criar o seguinte seletor para extrair os links de todos os pacotes: section > div:first-child > div:first-child a. Antes de o testar no código, podemos testar o seletor a partir das ferramentas de desenvolvimento do navegador. Para tal, aceda ao separador da consola e execute document.querySelectorAll("{{ SELECTOR }}"):

Ao passar o cursor sobre cada um dos elementos da lista de nós devolvidos, podemos ver que são exatamente aqueles que procurávamos e, por isso, podemos usar este seletor.

Extrair uma página usando Go

Estamos finalmente a começar a construir o scraper! Para tal, deve primeiro criar uma pasta onde colocaremos todo o nosso código. Em seguida, precisa de abrir uma janela de terminal, seja a partir do seu IDE ou do seu sistema operativo, e aceder à nossa pasta.

Para abrir um terminal na pasta, utilizando o Visual Studio Code, pode clicar em Terminal -> Novo Terminal (na barra superior).

Agora que temos o nosso terminal aberto, é hora de inicializar o projeto. Pode fazer isso executando o comando:

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

Isto irá criar na sua pasta um ficheiro chamado go.mod com o seguinte conteúdo:

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

Para fazer a solicitação à página e extrair os seletores do HTML, usaremos o Colly, um pacote GoLang (consulte a documentação do Colly para mais informações). Para instalar este pacote, tem de executar

go get github.com/gocolly/colly

Agora que temos tudo preparado, basta criar o nosso ficheiro main.go e escrever algum código. O código para extrair todos os links da primeira página de frameworks do npmjs é o seguinte:

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()
}

Se isto parecer difícil de ler à primeira vista, não se preocupe, iremos decompor o código nos parágrafos seguintes e explicá-lo. 

Todos os ficheiros GoLang devem começar com o nome do pacote e as importações que o Go irá utilizar. Neste caso, os dois pacotes que usamos são o “fmt” para imprimir os links que extraímos e o “Colly” (para a extração propriamente dita).

Na parte seguinte, criámos a função scrape() que se encarrega de extrair os links de que precisamos. Para tal, a função visita a primeira página e aguarda até encontrar o seletor que definimos. Quando um elemento desse seletor aparece, a função prossegue e imprime o atributo href desse elemento.

A última parte é a função main, que é a função chamada sempre que executamos um script em Go. Para executar o código anterior, execute go run main.go no seu terminal e deverá obter o seguinte resultado:

Como pode ver, o atributo href contém caminhos relativos para os links, pelo que teremos de lhe antepor a URL do npmjs.

Use a concorrência do GoLang para maior eficiência

Uma das funcionalidades mais interessantes do GoLang são as GoRoutines. As GoRoutines são threads simples e leves geridas pelo runtime do Go. O que é fantástico nisto é que o Go pode ajudar-nos a rastrear muitos URLs ao mesmo tempo a uma velocidade relâmpago.

Anteriormente, extraímos os links dos primeiros 20 pacotes sob a palavra-chave “framework” no npmjs.com. Agora, vamos tentar rastrear todos esses links ao mesmo tempo e extrair os downloads semanais de cada um deles. Para isso, usaremos GoRoutines e WaitGroups.

Aqui está o código final para extrair os downloads semanais usando as 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()
}

Agora vamos discutir o que foi adicionado ao nosso código anterior. Primeiro, irá notar que importámos um novo pacote chamado “sync”. Isto irá ajudar-nos a usar as rotinas do Go e a aguardar que os threads terminem, antes de interromper a execução do programa.

A próxima coisa adicionada é a nova função chamada “scrapeWeeklyDownloads”. Esta função aceita dois parâmetros: a URL do link que vamos rastrear e um ponteiro WaitGroup. O que esta função faz é visitar a URL fornecida e extrair os downloads semanais (usando o seletor main > div > div:last-child > div:not([class]) p).

As últimas alterações que irá notar foram na função scrape, onde criámos um WaitGroup utilizando var wg sync.WaitGroup. Aqui, para cada link da página de pacotes, utilizámos wg.Add(1) e, em seguida, criámos uma GoRoutine que chama a função scrapeWeeklyDownloads. No final da função, a instrução wg.Wait() faz com que o código aguarde até que todas as GoRoutines terminem a execução. 

Para mais informações sobre WaitGroups, consulte este exemplo da golang

Porquê GoRoutines e WaitGroups?

Ao utilizar a concorrência em Golang com GoRoutines e WaitGroups, podemos criar um scraper muito rápido. A execução do exemplo de código anterior irá devolver a página e os downloads semanais de cada pacote. No entanto, como estamos a utilizar multithreading, a ordem em que estas informações serão apresentadas é desconhecida (uma vez que os threads executam a velocidades diferentes)

Se estiver a executar o código utilizando o Linux ou o subsistema Linux do Windows (WSL), pode utilizar `time go run main.go` para ver o tempo de execução de todo o script. No meu caso, o tempo de execução ronda os 5 a 6 segundos. Isto é muito rápido, considerando que estamos a fazer scraping de 21 páginas (primeiro a página com os pacotes e, em seguida, as páginas de cada um dos pacotes).

Outros obstáculos

A maioria dos scrapers conta normalmente com a realização de uma simples solicitação HTTP à página, para obter o conteúdo de que precisam. Esta solução é boa, mas, por vezes, os sites apresentam as suas informações através da renderização em JavaScript. Isso significa que o site irá mostrar-lhe primeiro apenas uma parte do seu conteúdo, carregando o resto dinamicamente através de JavaScript.

Para extrair essas páginas, terá de utilizar o chromedriver e controlar um navegador Chrome real. Embora existam algumas opções para fazer isto em Golang, terá de fazer alguma pesquisa adicional sobre este tema.

Mesmo com a renderização em JavaScript resolvida, ainda existem alguns obstáculos adicionais ao fazer scraping de um site. Alguns sites podem usar deteções antibot, bloqueios de IP ou captchas para impedir que os bots façam scraping do seu conteúdo. Para continuar a fazer scraping desses sites, pode tentar usar algumas dicas e truques para web scraping, como tornar o seu scraper mais lento e agir de forma mais semelhante a um humano.

Mas, se quiser manter o seu scraper rápido e superar estes obstáculos de forma fácil, pode utilizar a WebScrapingAPI. A WebScrapingAPI é uma API concebida para o ajudar no scraping, rodando o seu IP e evitando deteções antibot. Desta forma, pode continuar a utilizar a velocidade relâmpago que o GoLang proporciona e extrair os seus dados num instante.

Conclusão sobre Web Scraping com Go

O Web Scraping é uma forma agradável e rápida de extrair dados da Internet, e pode ser utilizado para muitos casos de utilização diferentes. Pode optar por extrair dados para o seu modelo de aprendizagem automática ou construir uma aplicação a partir do zero utilizando os dados que extraiu.

O GoLang é uma das melhores soluções disponíveis no que diz respeito à concorrência. Usando o GoLang e o Colly, pode criar um scraper rápido que irá recolher os seus dados num instante. Isto torna o web scraping com Go muito fácil e eficiente assim que se habituar à sintaxe do Go

Sobre o autor
Sorin-Gabriel Marica, Desenvolvedor Full-Stack @ WebScrapingAPI
Sorin-Gabriel MaricaDesenvolvedor Full-Stack

Sorin Marica é engenheiro Full Stack e DevOps na WebScrapingAPI, onde desenvolve funcionalidades do produto e mantém a infraestrutura que garante o bom funcionamento da plataforma.

Comece a construir

Pronto para expandir a sua recolha de dados?

Junte-se a mais de 2.000 empresas que utilizam a WebScrapingAPI para extrair dados da Web à escala empresarial, sem quaisquer custos de infraestrutura.