Voltar ao blogue
Guias
Robert Sfichi6 de julho de 20218 min de leitura

Como construir um Web Scraper com Python e Selenium

Como construir um Web Scraper com Python e Selenium

Uma visão geral do Selénio

Tal como o site oficial do Selenium indica, o Selenium é um conjunto de ferramentas para automatizar os navegadores Web que foi introduzido pela primeira vez como uma ferramenta para testes entre navegadores.

A API criada pela equipa do Selenium utiliza o protocolo WebDriver para assumir o controlo de um navegador Web, como o Chrome ou o Firefox, e executar diferentes tarefas, como:

  • Preenchimento de formulários
  • Deslocação
  • Tirar capturas de ecrã
  • Clicar em botões

Agora deve estar a perguntar-se como é que tudo isto se traduz em web scraping. É simples, de facto.

A extração de dados pode, por vezes, ser uma verdadeira dor de cabeça. Hoje em dia, os sítios Web estão a ser construídos como aplicações de página única, mesmo quando não há necessidade disso. Estão a aparecer CAPTCHAs com mais frequência do que o necessário e até a bloquear IPs de utilizadores regulares.

Em suma, a deteção de bots é uma funcionalidade muito frustrante que parece um bug.

O Selenium pode ajudar nestes casos, compreendendo e executando o código Javascript e automatizando muitos processos tediosos da recolha de dados da Web, como percorrer a página, apanhar elementos HTML ou exportar dados recolhidos.

Instalação

Para mostrar o verdadeiro poder do Selenium e do Python, vamos extrair algumas informações do subreddit /r/learnprogramming. Além de extrair dados, também mostrarei como o login pode ser implementado. Agora que já entendemos a ferramenta principal e o site que vamos usar, vamos ver quais outros requisitos precisamos ter instalados:

1. Python. Iremos utilizar Python 3.0. No entanto, pode utilizar Python 2.0 fazendo pequenos ajustes. Pode descarregá-lo e instalá-lo a partir daqui.

2. Pacote Selenium. Pode instalar o pacote Selenium utilizando o seguinte comando:

pip3 install selenium

3. Pacote Pandas. Será utilizado para extrair e armazenar os dados recolhidos num ficheiro .csv. Execute o seguinte comando para o instalar no seu dispositivo.

pip3 install pandas

4. Pacote BeautifulSoup. Utilizado para analisar documentos HTML e XML. Basta executar esta linha:

pip3 install beautifulsoup

5. Google Chrome. Consulte esta hiperligação para saber mais sobre como descarregá-lo e instalá-lo.

6. Controlador do Chrome. Ajudar-nos-á a configurar o controlador Web para o Selenium. Siga este link para descarregar e instalar a versão mais recente do chromedriver. Não se esqueça de guardar o caminho onde o instalou.

Iniciar o browser

Vamos começar. Crie um novo arquivo scraper.py e importe o pacote Selenium copiando a seguinte linha:

from selenium import webdriver

Vamos agora criar uma nova instância do Google Chrome escrevendo:

driver = webdriver.Chrome(LOCATION)

Substitua LOCATION pelo caminho onde o driver do Chrome pode ser encontrado no seu computador. Consulte a documentação do Selenium para encontrar o PATH mais exato para o controlador Web, com base no sistema operativo que está a utilizar.

O passo final é aceder ao Web site do qual pretendemos extrair dados. No nosso caso, trata-se de https://www.reddit.com/r/learnprogramming/top/?t=month. Copie a seguinte linha no ficheiro python recém-criado:

driver.get("https://www.reddit.com/r/learnprogramming/top/?t=month")

Executando o seguinte comando numa janela de terminal:

python3 scraper.py

Devemos agora ter uma nova instância do Google Chrome aberta que especifica "O Chrome está a ser controlado por software de teste automatizado" no topo da nossa página.

Localização de dados específicos

Como já deve ter percebido, neste tutorial vamos fazer scrape do subreddit /r/learnprogramming. Vamos guardar o título, o autor e o número de votos positivos dos posts e armazená-los num novo ficheiro .csv. Vamos ver onde estão situados na página HTML e como podemos extraí-los.

Depois que o Google Chrome finalmente carregou a página, vamos clicar com o botão direito do mouse em qualquer post e clicar em "Inspecionar". Podemos encontrar o contentor HTML da publicação sob o nome de classe _1oQyIsiPHYt6nx7VOmd1sz.

Captura de ecrã do navegador mostrando uma página do Reddit ao lado das ferramentas de programador que analisam o código HTML da página

Também é possível executar o Google Chrome sem uma interface gráfica do utilizador e registar o conteúdo HTML da página, adicionando algumas linhas de código. Definiremos a opção sem cabeça como verdadeira para o driver do Chrome (para remover a interface gráfica) e um tamanho de janela de 1080 pixels (para obter o código HTML correto para nosso caso de uso).

As duas últimas linhas de código saem do Chrome logo após terminarem de registar o HTML da página.

O novo ficheiro scraper.py terá o seguinte aspeto:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.headless = True
options.add_argument("--window-size=1920,1080")

driver = webdriver.Chrome("./chromedriver")
driver.get("https://www.reddit.com/r/learnprogramming/top/?t=month")

print(driver.page_source)
driver.quit()

Elemento Web

Um WebElement é um objeto do Selenium que representa um elemento HTML. Como você verá no tutorial a seguir, podemos executar muitas ações nesses elementos. Algumas delas são:

  • Clicar nele utilizando o método .click()
  • Fornecer texto a um elemento de entrada específico chamando o método .send_keys()
  • Ler o texto de um elemento utilizando element.text
  • Verificar se um elemento é apresentado na página chamando-lhe .is_displayed()

Um exemplo do Selenium em ação

Agora que temos o nosso projeto configurado, podemos finalmente começar a raspar.

Iniciar sessão

Vamos mostrar o poder do Selenium fazendo login na nossa conta do Reddit e extraindo os dados apresentados anteriormente. Vamos começar fazendo o Selenium clicar no botão de login na parte superior da página. Depois de inspecionar o HTML da página, podemos ver que o nome da classe do botão de login é _2tU8R9NTqhvBrhoNAXWWcP.

login_button = driver.find_element_by_class_name('_2tU8R9NTqhvBrhoNAXWWcP')
login_button.click()
Página do Reddit com uma janela pop-up de início de sessão a bloquear o conteúdo, ilustrando um obstáculo na automatização da navegação

Isto abrirá o modal de início de sessão, onde podemos ver as entradas de utilizador e palavra-passe que temos de preencher. Vamos continuar com as linhas seguintes:

driver.switch_to_frame(driver.find_element_by_class_name('_25r3t_lrPF3M6zD2YkWvZU'))

driver.find_element_by_id("loginUsername").send_keys('USERNAME')
driver.find_element_by_id("loginPassword").send_keys('PASSWORD')

driver.find_element_by_xpath("//button[@type='submit']").click()

Se inspeccionarmos o elemento modal, podemos ver que o seu contentor é um iframe. É por isso que temos de mudar para a frame na primeira parte do código, uma vez que selecionar os inputs sem ela resultará num erro.

A seguir, obtemos os elementos de entrada e fornecemos-lhes as credenciais adequadas antes de premir o botão de submeter. Isto vai levar-nos de volta à página /r/learnprogramming, mas agora estamos registados e prontos para votar!

Tirar uma captura de ecrã

Tirar uma captura de ecrã utilizando o Selenium e o Python é bastante fácil. Tudo o que tem de fazer é escrever o seguinte comando no ficheiro scraper.py depois de declarar o web driver.

driver.save_screenshot('screenshot.png')

É útil saber que pode definir o tamanho da janela do Google Chrome adicionando as seguintes linhas de código:

from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--window-size=1920,1080")

É assim que a captura de ecrã ficará no nosso caso:

Página do Reddit r/learnprogramming com um banner de consentimento de cookies na parte inferior do ecrã

Extração de dados

Como dissemos anteriormente, precisamos de obter o título, o autor e o número de votos positivos dos posts. Vamos começar importando os pacotes BeautifulSoup e Pandas e criando três arrays vazios para cada tipo de informação que precisamos.

from bs4 import BeautifulSoup
import pandas as pd

titles = []
upvotes = []
authors = []

Vamos utilizar o BeautifulSoup para analisar o documento HTML, escrevendo as seguintes linhas:

content = driver.page_source
soup = BeautifulSoup(content, features="html.parser")

Depois de inspecionar com êxito o documento HTML e escolher os selectores corretos, vamos agora obter os títulos, os votos positivos e os autores e atribuí-los à matriz correta:

for element in soup.findAll('div', attrs={'class': '_1oQyIsiPHYt6nx7VOmd1sz'}):
   title = element.find('h3', attrs={'class': '_eYtD2XCVieq6emjKBH3m'})
   upvote = element.find('div', attrs={'class': '_3a2ZHWaih05DgAOtvu6cIo'})
   author = element.find('a', attrs={'class': '_23wugcdiaj44hdfugIAlnX'})
   titles.append(title.text)
   upvotes.append(upvote.text)
   authors.append(author.text)

Por fim, armazenaremos as informações num ficheiro CSV utilizando o pacote Pandas que importámos anteriormente.

df = pd.DataFrame({'Post title': titles, 'Author': authors, 'Number of upvotes': upvotes})
df.to_csv('posts.csv', index=False, encoding='utf-8')

É isso mesmo! Vejamos o ficheiro exportado:

Visualização em folha de cálculo do ficheiro posts.csv, que lista os títulos das publicações do Reddit, os autores e o número de votos positivos

Parece ter todas as informações de que necessitamos.

Dica de bónus: Por vezes, precisamos de mais dados do que aqueles que o sítio Web fornece no primeiro carregamento. Na maioria das vezes, a ação de obtenção de dados é activada quando o utilizador faz scroll para baixo. Se for necessário rolar para baixo para obter mais dados, você pode usar o método .execute_script() desta forma:

scrollDown = "window.scrollBy(0,2000);"
driver.execute_script(scrollDown)

Considerações finais

Espero que tenhas gostado de criar o web scraper tanto quanto eu. Programar nem sempre é divertido, mas construir pequenos scripts como este faz-me lembrar de quando eu estava a começar, e torna o processo muito mais divertido.

Ainda assim, o script que conseguimos construir neste tutorial não pode fazer muito trabalho duro. Faltam-lhe algumas funcionalidades essenciais que fazem com que o web scraping seja perfeito. A ligação através de proxies móveis ou residenciais e a resolução de CAPTCHAs são apenas algumas delas.

Se está à procura de uma forma mais profissional de extrair dados, veja o que o WebScrapingAPI pode fazer e veja por si próprio se existe uma correspondência. Existe um pacote gratuito, pelo que o único investimento são 30 minutos da sua atenção.

Obrigado por dedicar algum tempo a ler isto. Boa raspagem!

Sobre o autor
Robert Sfichi, Desenvolvedor Full-Stack na WebScrapingAPI
Robert SfichiDesenvolvedor Full-Stack

Robert Sfichi é membro da equipa da WebScrapingAPI, contribuindo para o produto e ajudando a criar soluções fiáveis que apoiam a plataforma e os seus utilizadores.

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.