O guia definitivo sobre como iniciar a raspagem da Web com Elixir

Suciu Dan em 18 de outubro de 2022

Introdução

Web scraping é o processo de extração de dados de sites disponíveis publicamente, como fóruns, sites de mídia social, sites de notícias, plataformas de comércio eletrônico etc. Para dar uma espreitadela ao que vai construir hoje, este artigo descreve a criação de um web scraper em Elixir.

Se a definição de web scraping ainda não é clara para si, consideremos que guardar uma imagem de um sítio é web scraping manual. Se quiser guardar todas as imagens de um sítio à mão, com base na complexidade do sítio, pode demorar horas ou mesmo dias. 

Pode automatizar este processo construindo um web scraper.

Talvez se esteja a perguntar quais são alguns casos de utilização de um raspador da Web. Aqui estão os mais comuns:

Acompanhamento de notícias

Pode recolher as últimas notícias do seu sítio de notícias financeiras favorito, executar um algoritmo de análise de sentimentos e saber em que investir minutos antes de o mercado começar a mover-se

Informações sobre redes sociais

Pode recolher os comentários das suas páginas nas redes sociais e analisar o que os seus subscritores estão a dizer e o que pensam do seu produto ou serviço.

Monitorização de preços

Se a sua paixão é colecionar consolas e jogos de vídeo, mas não quer gastar uma fortuna na PS5 mais recente, pode criar um web scraper que recupere as listas do eBay e lhe envie uma notificação quando uma consola barata estiver no mercado.

Formação em aprendizagem automática

Se quiser criar uma aplicação móvel capaz de identificar a raça de um gato em qualquer fotografia, vai precisar de muitos dados de treino; em vez de guardar manualmente centenas de milhares de fotografias com gatos para treinar o modelo, pode utilizar um web scraper para o fazer automaticamente.

Vamos construir o nosso web scraper em Elixir, uma linguagem de programação construída sobre Erlang, criada por José Valim, membro da equipa principal do Ruby on Rails. A linguagem de programação empresta a simplicidade da sintaxe do Ruby e combina-a com a capacidade do Erlang de construir sistemas de baixa latência, distribuídos e tolerantes a falhas.

Requisitos

Antes de escrever a primeira linha de código, certifique-se de que tem o Elixir instalado no seu computador. Baixe o instalador para seu sistema operacional e siga as instruções da página Instalar

Durante a instalação, você notará que a linguagem de programação Erlang também é necessária. Lembre-se de que o Elixir é executado na VM do Erlang, portanto, você precisa de ambos.

Como começar

Neste artigo, aprenderá a criar um raspador web em Elixir, a raspar os produtos do eBay para listagens PS5 e a armazenar localmente os dados extraídos (nome, url, preço).

Inspeção do alvo

É altura de inspecionar os resultados da pesquisa na página do eBay e recolher alguns selectores.

Aceda a ebay.com, introduza o termo PS5 na caixa de pesquisa e clique no botão Pesquisar. Quando a página de resultados da pesquisa estiver carregada, abra a ferramenta Inspecionar no seu browser (clique com o botão direito do rato em qualquer parte da página e selecione Inspecionar).

É necessário recolher os seguintes selectores:

  • Lista de produtos Item
  • URL do produto
  • Nome do produto
  • Preço do produto

Utilize a ferramenta de seleção de elementos e procure a lista de artigos de produto (ul) e o artigo de produto (li):

imagem do blogue

Utilizando estes dois elementos, é possível extrair as classes necessárias ao crawler para a extração de dados:

  • .srp-results .s-item os elementos filhos do elemento da lista de produtos (ul)
  • .s-item__title span o título do produto
  • .s-item__link o link do produto
  • .s-item__price o preço do produto

Criar o projeto

Vamos criar um projeto Elixir utilizando o comando mix:

misturar novo elixir_aranha --sup

O sinalizador --sup gera um esqueleto de aplicativo OTP incluindo uma árvore de supervisão, um recurso necessário para um aplicativo que gerencia vários processos simultâneos como um rastreador.

Criar a pasta temporária

Alterar o diretório atual para a raiz do projeto:

cd elixir_spider

Criar o diretório temporário:

mkdir temp

Utilizamos este diretório para armazenar os itens recolhidos.

Adicionar as dependências

Depois de o projeto ser criado, é necessário adicionar as duas dependências:

  • Crawly é uma estrutura de aplicação para rastrear sites e extrair dados estruturados
  • O Floki é um analisador HTML que permite a pesquisa de nós utilizando selectores CSS

Abra o ficheiro mix.exs e adicione as dependências no bloco deps:

defp deps do
[
{:crawly, "~> 0.14.0"},
{:floki, "~> 0.33.1"}
]
end

Obtenha as dependências executando este comando:

mix deps.get

Criar a configuração

Crie o ficheiro config/config.exs e cole nele esta configuração:

import Config

config :crawly,
closespider_timeout: 10,
concurrent_requests_per_domain: 8,
closespider_itemcount: 100,

middlewares: [
Crawly.Middlewares.DomainFilter,
Crawly.Middlewares.UniqueRequest,
{Crawly.Middlewares.UserAgent, user_agents: ["Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/105.0"]}
],
pipelines: [
{Crawly.Pipelines.Validate, fields: [:url, :title, :price]},
{Crawly.Pipelines.DuplicatesFilter, item_id: :title},
Crawly.Pipelines.JSONEncoder,
{Crawly.Pipelines.WriteToFile, extension: "jl", folder: "./temp"}
]

Opções gerais

Vamos analisar cada uma das propriedades e dar-lhes algum sentido:

  • closespider_timeout: número inteiro, o número máximo de segundos que a aranha permanecerá aberta
  • concurrent_requests_per_domain: o número máximo de pedidos que serão efectuados para cada domínio extraído
  • closespider_itemcount: o número máximo de itens que são transmitidos pela conduta de itens

Agente do utilizador

Ao definir o agente do utilizador, melhora os resultados da recolha de dados ao imitar um browser real. Os sites não gostam de scrapers e tentam bloquear quaisquer agentes de utilizador que não pareçam reais. Pode utilizar uma ferramenta como esta para obter o agente de utilizador do seu browser.

O WebScrapingAPI roda o agente do utilizador e o endereço IP em cada pedido e também implementa inúmeras evasões para evitar este tipo de situação. Os seus pedidos não serão bloqueados e a implementação de um mecanismo de retry dar-lhe-á resultados surpreendentes.

Condutas

Os pipelines são comandos processados de cima para baixo e permitem a manipulação dos itens processados. Utilizamos os seguintes pipelines:

  • Validar campos (título, preço, url): verifica se o item tem os campos extraídos definidos
  • Filtro de duplicados: verifica a existência de itens duplicados por título
  • Codificador JSON: codifica as estruturas para um objeto JSON
  • Escrever para ficheiro: escreve os itens na pasta ./temp

Criar a aranha

Um web crawler, ou spider, é um tipo de bot que percorre um site e extrai dados utilizando campos definidos pelo utilizador através de selectores CSS. Um rastreador pode extrair todos os links de uma página e usar links específicos (como links de paginação) para rastrear mais dados. 

Está na altura de definir a base para o crawler: crie o ficheiro ebay_scraper.ex na pasta lib/elixir_spider e cole-lhe o seguinte código:

# lib/elixir_spider/ebay.ex
defmodule EbayScraper do
use Crawly.Spider

@impl Crawly.Spider
def base_url(), do: ""

@impl Crawly.Spider
def init() do

end

@impl Crawly.Spider
def parse_item(response) do

end
end

Este é apenas o esqueleto do ficheiro e não será executado nem devolverá quaisquer resultados. Vamos falar primeiro de cada função e depois preenchemo-las uma a uma.

A função base_url() é chamada uma vez e devolve o URL de base para o sítio Web alvo que o rastreador irá recolher; é também utilizada para filtrar ligações externas e impedir o rastreador de as seguir. Não queremos recolher toda a Internet.

@impl Crawly.Spider
def base_url(), do: "https://www.ebay.com/"

A função init() é chamada uma vez e é utilizada para inicializar o estado predefinido do crawler; neste caso, a função devolve o start_url a partir do qual a recolha de dados começará.

Substitua a sua função em branco por esta:

@impl Crawly.Spider
def init() do
[start_urls: ["https://www.ebay.com/sch/i.html?_nkw=ps5"]]
end

Toda a magia da extração de dados acontece na função parse_item(). Esta função é chamada para cada URL extraído. Dentro desta função, usamos o analisador HTML do Floki para extrair os campos que precisamos: título, url e preço.

A função terá o seguinte aspeto:

@impl Crawly.Spider
def parse_item(response) do
# Parse response body to document
{:ok, document} = Floki.parse_document(response.body)

# Create item (for pages where items exists)
items =
document
|> Floki.find(".srp-results .s-item")
|> Enum.map(fn x ->
%{
title: Floki.find(x, ".s-item__title span") |> Floki.text(),
price: Floki.find(x, ".s-item__price") |> Floki.text(),
url: Floki.find(x, ".s-item__link") |> Floki.attribute("href") |> Floki.text(),
}
end)

%{items: items}
end

Como deve ter reparado, estamos a utilizar as classes que encontrámos na secção Introdução - Inspecionar o alvo para extrair os dados de que necessitamos dos elementos DOM.

A aranha em ação

É hora de testar o código e certificar-se de que ele funciona. A partir do diretório raiz do projeto, execute este comando:

iex -S mix run -e "Crawly.Engine.start_spider(EbayScraper)"

Se estiver a utilizar o PowerShell, certifique-se de que substitui iex por iex.bat, caso contrário receberá um erro devido ao parâmetro -S inexistente. Utilize este comando para o PowerShell:

iex.bat -S mix run -e "Crawly.Engine.start_spider(EbayScraper)"

Verificação dos resultados

Abra a pasta ./temp e verifique o ficheiro .jl. Deverá ver um ficheiro de texto que contém uma lista de objectos JSON, um por linha. Cada objeto contém as informações de que necessitávamos da lista de produtos do eBay: título, preço e URL.

Eis o aspeto que o objeto do produto deve ter:

{"url":"https://www.ebay.com/itm/204096893295?epid=19040936896&hash=item2f851f716f:g:3G8AAOSwNslhoSZW&amdata=enc%3AAQAHAAAA0Nq2ODU0vEdnTBtnKgiVKIcOMvqJDPem%2BrNHrG4nsY9c3Ny1bzsybI0zClPHX1w4URLWSfXWX%2FeKXpdgpOe%2BF8IO%2FCh77%2FycTnMxDQNr5JfvTQZTF4%2Fu450uJ3RC7c%2B9ze0JHQ%2BWrbWP4yvDJnsTTWmjSONi2Cw71QMP6BnpfHBkn2mNzJ7j3Y1%2FSTIqcZ%2F8akkVNhUT0SQN7%2FBD38ue9kiUNDw9YDTUI1PhY14VbXB6ZMWZkN4hCt6gCDCl5mM7ZRpfYiDaVjaWVCbxUIm3rIg%3D%7Ctkp%3ABFBMwpvFwvRg","title":"PS5 Sony PlayStation 5 Console Disc Version!  US VERSION!","price":"$669.99"}

Melhorar a aranha

Recuperámos todos os produtos da primeira página da lista de produtos, mas isso não é suficiente. É altura de implementar a paginação e permitir que o rastreador extraia todos os produtos disponíveis.

Vamos alterar a função parse_item() e adicionar um novo bloco que cria uma estrutura de pedidos com o próximo link de paginação. Adicione este código após o código de itens:

# Extrair a hiperligação da página seguinte e convertê-la num pedido
requests =
document
|> Floki.find(".s-pagination a.pagination__next")
|> Floki.attribute("href")
|> Crawly.Utils.build_absolute_urls(response.request_url)
|> Crawly.Utils.requests_from_urls()

Actualize a declaração de retorno da função parse_item() para incluir também os pedidos seguintes. A estrutura terá a seguinte aparência:

%{
:requests => requests,
:items => items
}

Executa o crawler novamente, mas desta vez prepara um café. A recolha de todas as páginas para as listagens da PS5 demorará alguns minutos.

Depois de o crawler terminar o seu trabalho, verifique a pasta ./temp para ver os resultados obtidos. O eBay foi bem sucedido na pesquisa de consolas PS5 e tem uma lista com os respectivos preços. Pode alargar este crawler para recolher quaisquer outros produtos.

Conclusão

Neste artigo aprendeu o que é um web scraper, quais os casos de utilização destes crawlers, como usar bibliotecas já criadas para configurar um scraper usando Elixir em minutos, e como executar e extrair os dados reais.

Se achou que isto foi muito trabalhoso, quero dar-lhe algumas notícias não tão boas: apenas arranhámos a superfície. Se utilizar este raspador durante muito tempo, vai começar a causar-lhe mais problemas do que possa imaginar.

O eBay detectará a sua atividade e assinalá-la-á como suspeita; o crawler começará a receber correcções Captcha; terá de alargar a funcionalidade do crawler para resolver captchas

Os sistemas de deteção do eBay podem assinalar o seu endereço IP e bloquear o acesso ao sítio Web; terá de obter um grupo de proxy e rodar os endereços IP em cada pedido. 

A sua cabeça já está a andar à roda? Vamos falar de mais uma questão: o agente do utilizador. É necessário criar uma grande base de dados com os agentes do utilizador e rodar esse valor com cada pedido. Os sistemas de deteção bloqueiam os scrapers com base no endereço IP e no agente do utilizador.

Se quiser concentrar-se mais na vertente comercial e investir o seu tempo na extração de dados em vez de resolver os problemas de deteção, utilizar um raspador como serviço é uma melhor escolha. Uma solução como o WebScrapingAPI resolve todos os problemas apresentados acima e muitos outros. 

Notícias e actualizações

Mantenha-se atualizado com os mais recentes guias e notícias sobre raspagem da Web, subscrevendo a nossa newsletter.

We care about the protection of your data. Read our <l>Privacy Policy</l>.Privacy Policy.

Artigos relacionados

miniatura
Ciência da recolha de dados da WebScrapy vs. Selenium: Um guia abrangente para escolher a melhor ferramenta de raspagem da Web

Explore a comparação aprofundada entre o Scrapy e o Selenium para raspagem da Web. Desde a aquisição de dados em grande escala até o tratamento de conteúdo dinâmico, descubra os prós, os contras e os recursos exclusivos de cada um. Saiba como escolher a melhor estrutura com base nas necessidades e na escala do seu projeto.

WebscrapingAPI
avatar do autor
WebscrapingAPI
14 min ler
miniatura
GuiasTutorial do Scrapy Splash: Dominando a arte de raspar sites renderizados em JavaScript com Scrapy e Splash

Aprenda a extrair sites dinâmicos renderizados em JavaScript usando o Scrapy e o Splash. Desde a instalação até à escrita de um spider, à manipulação da paginação e à gestão das respostas do Splash, este guia abrangente oferece instruções passo a passo tanto para principiantes como para especialistas.

Ștefan Răcila
avatar do autor
Ștefan Răcila
6 min. de leitura
miniatura
GuiasO guia definitivo para a recolha de trabalho online, os seus prós e contras

Definição e utilização da recolha de empregos em linha. Vantagens e desvantagens do job scraping, bem como estratégias e riscos potenciais.

Suciu Dan
avatar do autor
Suciu Dan
8 min. de leitura