Agora que abordámos alguns conceitos teóricos, penso que é seguro avançar e explorar a parte prática. Nesta secção, vou mostrar-lhe como criar um web scraper com o Selenium. Para este projeto, certifique-se de que o seu computador tem o Python e o Chrome instalados.
#1: Configurar o ambiente
Como de costume, em Python devemos encapsular tudo dentro de um ambiente virtual. Se não estiver familiarizado com ambientes virtuais, leia isto primeiro. Agora vamos abrir uma nova janela de terminal e vamos:
- Criar uma nova pasta
- Navegar até à pasta
- Criar um novo ambiente virtual
- Ativar o ambiente virtual
~ mkdir headless_scraper
~ cd headless_scraper
~ python3 -m venv env
~ source env/bin/activate
#2: Instalar dependências
É bastante óbvio que precisamos do Selenium e de um web driver para o nosso projeto. Felizmente, podemos instalar ambos usando o gestor de pacotes do Python, o `pip`. Na mesma janela do terminal, digite o seguinte comando:
~ pip install selenium webdriver-manager
Agora está tudo pronto para o sucesso! Podemos passar à programação propriamente dita. Uma breve nota: este artigo centra-se na interação com um navegador headless. Uma solução completa de web scraping requer muito mais esforço. Mas tenho a certeza de que, se acompanhar as nossas publicações no blogue, conseguirá fazê-lo num instante.
#3: Abrir um navegador automatizado
Até agora, temos o projeto, mas não há nenhum ficheiro que possamos executar. Vamos criar um novo ficheiro `.py` e abri-lo no nosso IDE:
~ touch headles_scraper.py
~ code .
Deve estar agora no Visual Studio Code ou no seu IDE. Pode começar por importar os pacotes necessários para dentro de `handle_scraper.py`:
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
Este último é um pacote que o ajuda a gerir facilmente os web drivers para os diferentes navegadores suportados pelo Selenium. Pode ler mais sobre isso aqui. A seguir, queremos criar um novo navegador com o Selenium e abrir um site:
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('https://webscrapingapi.com')
Execute este ficheiro agora e verá que funciona. Mas, em vez de utilizar um navegador Python headless, abre-se uma janela do Chrome com interface gráfica:
#4: Criar em modo headless
Configuramos para construir um web scraper que economize recursos. Portanto, idealmente, queremos abrir um navegador headless com o Selenium. Felizmente, existe um método fácil que podemos usar para mudar o Selenium de headful para headless. Só precisamos de utilizar as opções do driver web do Chrome. Então, vamos importar `Options` e adicionar mais duas linhas de código:
...
from selenium.webdriver.chrome.options import Options
...
options = Options()
options.headless = True
driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)
driver.get('https://webscrapingapi.com')
Execute o seu script novamente. Como pode ver, desta vez não aparece nenhuma janela. Mas será que está realmente a funcionar em segundo plano? Uma forma rápida de visualizar e verificar isso é tirar uma captura de ecrã usando o Selenium. Basta adicionar esta linha no final do seu script:
driver.get_screenshot_as_file('headless.png')
Se tudo correu bem, deve ter a mesma imagem que eu:
#5: Adicionar capacidades de scraping
O que é um web scraper? Bem, na sua essência, um web scraper é um programa que chama um endpoint de um servidor e recolhe dados a partir dele. No caso de sites, esses dados consistem geralmente em ficheiros HTML. Mas, atualmente, certos servidores também servem objetos JSON. Por isso, vamos manter este termo: dados. Para a secção seguinte, vamos elevar os nossos objetivos. Vamos usar alguma programação orientada para objetos! Os nossos objetivos são:
- Criar uma classe Scraper
- Adicionar um método para extrair dados brutos
- Adicionar um método para extrair dados de um único elemento
- Adicionar um método para extrair dados de elementos da mesma classe
Portanto, temos três métodos básicos que queremos construir. No entanto, para fins de aprendizagem, estes três métodos abrem um caminho não só para o web scraping, mas também para a POO com Python. E acho isso muito fixe! Agora vamos remover tudo o que codificámos e vamos começar do zero:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
class Scraper:
def __init__(self, headless: bool = True) -> None:
self.headless = headless
pass
def setup_scraper(self) -> None:
self.options = Options()
self.options.headless = self.headless
self.driver = webdriver.Chrome(options=self.options)
def navigate(self, target) -> None:
self.driver.get(target) if target else print('[!] No target given. Please specify a URL.')
def extract_raw_data(self) -> str:
return self.driver.page_source
def extract_single_element(self, selector: str, selector_type: By = By.CSS_SELECTOR) -> WebElement:
return self.driver.find_element(selector_type, selector)
def extract_all_elements(self, selector: str, selector_type: By = By.CSS_SELECTOR) -> list[WebElement]:
return self.driver.find_elements(selector_type, selector)
Adicionei anotações de tipo para facilitar a compreensão, em vez de melhorar o desempenho. Desta forma, pode realmente visualizar a aplicação de uma perspetiva de E/S. Agora, os métodos são bastante autoexplicativos. Não estamos a realizar qualquer tipo de ação sobre os dados, estamos apenas a devolvê-los. Se quiser, isso pode ser um ponto de partida para criar um scraper complexo com um navegador headless em Python.
Até agora, a execução do ficheiro não faz nada. Isso porque apenas declarámos o nosso Scraper e os seus métodos. Agora temos de os utilizar. Vamos, portanto, adicionar os seguintes trechos de código:
# Initialize a new Scraper and navigate to a target
scraper = Scraper()
scraper.setup_scraper()
scraper.navigate('https://httpbin.org')
# Extract and print the entire HTML document
raw_data = scraper.extract_raw_data()
print(raw_data)
# Extract and print an element by its class name
single_element = scraper.extract_single_element('title', By.CLASS_NAME)
print(single_element.text)
# Extract and print all elements belonging to a tag type
all_elements = scraper.extract_all_elements('a', By.TAG_NAME)
print([el.get_attribute('href') for el in all_elements])
E é isso. Se executares o teu script agora, poderás ver alguma ação a acontecer. Mais uma vez, isto é apenas um protótipo concebido para te ajudar a começar. Se quiseres saber mais sobre como um navegador headless em Python pode ser usado na extração de dados da web, desafio-te a:
Desta forma, irá adquirir conhecimentos e adicionar um projeto ao seu portfólio.