Voltar ao blogue
Guias
Robert SfichiLast updated on Apr 29, 202632 min read

Web Scraping com Selenium: Tutorial passo-a-passo em Python

Web Scraping com Selenium: Tutorial passo-a-passo em Python
Resumo: O Selenium permite extrair dados de sites com muito JavaScript, controlando um navegador real a partir de código Python. Este tutorial orienta-o em todas as etapas: instalação do Selenium, configuração do Chrome, localização e interação com elementos, gestão de tempos de espera e paginação, exportação de dados limpos e escalabilidade do seu scraper com proxies, Selenium Grid e alternativas baseadas em API.

O Selenium é uma estrutura de automação de navegadores que controla uma instância real de navegador (Chrome, Firefox, Edge e outros) através de código. Embora tenha sido originalmente criado para testar aplicações web, tornou-se uma das ferramentas mais utilizadas para a extração de dados na web com o Selenium, especialmente em sites onde o JavaScript renderiza o conteúdo de que necessita.

Se já tentou fazer scraping de uma aplicação de página única ou de um feed de rolagem infinita com requests e o BeautifulSoup, já conhece o problema: o HTML que descarrega é uma estrutura vazia. Os dados reais carregam após a execução do JavaScript, e um cliente HTTP simples nunca executa esse JavaScript. O Selenium resolve isto ao iniciar um navegador completo, carregando a página exatamente como um visitante humano faria, e depois dando-lhe acesso programático ao DOM resultante.

Este tutorial abrange todos os passos práticos do web scraping com Selenium em Python: configuração do ambiente, estratégias de localização de elementos, espera por conteúdo dinâmico, rolagem, paginação, exportação de dados, integração de proxy e otimização de desempenho. No final, terá um scraper funcional de ponta a ponta e uma visão clara de quando o Selenium é a escolha certa em comparação com alternativas mais leves.

O que é o Selenium e por que usá-lo para web scraping?

O Selenium surgiu como uma estrutura de testes em 2004 e evoluiu através de várias versões principais desde então. Hoje, o Selenium WebDriver comunica com os navegadores através do protocolo W3C WebDriver, uma API padronizada que todos os principais fornecedores de navegadores implementam nativamente. Escreve instruções em Python (ou Java, JavaScript, Ruby, C# e várias outras linguagens), e o WebDriver traduz essas instruções em ações dentro de uma sessão real do navegador. O navegador renderiza HTML, executa JavaScript, aplica CSS e dispara pedidos de rede, tal como faria para um humano sentado ao teclado.

Esse pipeline de renderização completo é exatamente o que torna o Selenium valioso para o scraping. Bibliotecas HTTP tradicionais, como requests obtêm o documento HTML bruto que o servidor devolve. Se a página depende de JavaScript do lado do cliente para preencher uma grelha de produtos, carregar avaliações ou montar um painel, não obtém nenhum desses dados. O Selenium, por outro lado, aguarda que o JavaScript seja executado e fornece-lhe o DOM totalmente renderizado.

O Selenium também suporta todos os principais navegadores (Chrome, Firefox, Edge, Opera, Safari) e funciona em todos os sistemas operativos. Este suporte multibrowsers é importante quando um site de destino se comporta de forma diferente dependendo do motor do navegador. E como o Selenium imita o comportamento genuíno do utilizador (clicar, digitar, percorrer), consegue navegar por fluxos de trabalho interativos que os scrapers estáticos simplesmente não conseguem alcançar.

A desvantagem é o custo de recursos. Executar um navegador completo consome CPU e RAM reais, e é visivelmente mais lento do que disparar uma solicitação HTTP leve. O Selenium foi concebido como uma ferramenta de teste, pelo que algumas das suas abstrações (a sobrecarga do protocolo WebDriver, a falta de espera automática integrada) criam atrito para casos de utilização de scraping puro. Dito isto, a sua enorme comunidade, documentação extensa e amplo suporte a linguagens tornam-no um dos pontos de partida mais seguros para quem se inicia na extração de dados baseada em navegador. Abordaremos considerações de desempenho e alternativas mais adiante neste tutorial.

Quando o Selenium é (e não é) a ferramenta de scraping certa

O Selenium é a escolha certa quando a página que precisa de ser scraped requer a execução de JavaScript para renderizar o seu conteúdo. Pense em aplicações de página única construídas com React, Angular ou Vue; sites protegidos por formulários de login; páginas com scroll infinito; e painéis onde os dados são carregados através de chamadas AJAX após o carregamento inicial da página.

Não é a melhor escolha para rastreamento em grande escala de páginas HTML estáticas. Para essas tarefas, requests em conjunto com o BeautifulSoup ou uma estrutura como o Scrapy será mais rápido, mais leve em termos de memória e mais fácil de escalar. A comparação entre o Scrapy e o Selenium resume-se a saber se precisa mesmo de um navegador. Bibliotecas de automação de navegadores mais recentes, como o Playwright e o Puppeteer, também merecem ser consideradas quando se pretende APIs assíncronas modernas com funcionalidades de espera automática integradas.

Aqui está uma lista de verificação rápida para a decisão:

  • HTML estático, sem necessidade de JS: Use requests + BeautifulSoup.
  • Rastreamento de grande porte, páginas estáticas: use o Scrapy.
  • Páginas renderizadas em JS, equipa multilingue: Use o Selenium.
  • Páginas renderizadas com JS, apenas Python/JS, se quiser uma API moderna: considere o Playwright.

Uma regra prática: comece com a ferramenta mais leve que funcione. Se requests ela obtiver os dados de que precisa, pare por aí. Se o conteúdo for renderizado em JavaScript e quiser um amplo suporte a linguagens, além de um ecossistema maduro, o web scraping com o Selenium é um meio-termo sólido.

Pré-requisitos e configuração do ambiente

Antes de escrever uma única linha de código de scraping, precisa de ter três coisas instaladas: Python 3.8 ou posterior, o pacote Selenium e um driver de navegador compatível com a versão do seu navegador.

Instalar o Python e o Selenium

Abra um terminal e verifique a sua versão do Python:

python --version

Em seguida, instale o Selenium através do pip:

pip install selenium

A partir da versão 4.6, o Selenium vem com uma ferramenta integrada chamada selenium-manager, que pode descarregar e configurar automaticamente o driver de navegador correto para si. Nas versões anteriores, era necessário descarregar manualmente o ChromeDriver (ou o GeckoDriver para o Firefox) e adicioná-lo ao PATH do sistema. Se estiver a utilizar o Selenium 4.6 ou posterior, pode ignorar a gestão manual do driver na maioria dos casos, embora valha a pena verificar se as versões do Chrome e do ChromeDriver estão alinhadas caso encontre erros de inicialização.

Verifique a instalação

Crie um script de teste rápido para confirmar que tudo funciona:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://example.com")
print(driver.title)  # Should print "Example Domain"
driver.quit()

Se uma janela do Chrome abrir, carregar a página e imprimir o título na sua consola, o seu ambiente está pronto. Caso contrário, verifique se o Chrome está instalado e se a sua versão do Selenium corresponde à versão principal do Chrome na sua máquina.

Ambientes virtuais

É boa prática trabalhar dentro de um ambiente virtual para que o Selenium e as suas dependências não entrem em conflito com outros projetos:

python -m venv scraper-env
source scraper-env/bin/activate   # On Windows: scraper-env\Scripts\activate
pip install selenium beautifulsoup4 pandas

O BeautifulSoup lida com a análise rápida de HTML assim que o Selenium obtém o código-fonte da página renderizada, e o pandas simplifica a limpeza de dados e a exportação para CSV. Ambos são opcionais, mas aparecem frequentemente em tarefas reais de web scraping com fluxos de trabalho do Selenium em Python; por isso, tê-los instalados desde o início poupa tempo.

Neste ponto, o seu ambiente está pronto. O próximo passo é configurar o Chrome para que se comporte da forma que deseja durante uma sessão de scraping.

Configurar as opções do Chrome para scraping

O Selenium inicia o Chrome com as suas definições predefinidas, mas essas definições não são ideais para o scraping. A ChromeOptions classe permite-lhe personalizar a sessão do navegador antes de esta começar.

from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument("--headless=new")          # Run without a visible window
options.add_argument("--disable-gpu")           # Prevents GPU-related issues in headless
options.add_argument("--window-size=1920,1080") # Consistent viewport for element visibility
options.add_argument("--no-sandbox")            # Required in some CI/Docker environments
options.add_argument("--disable-dev-shm-usage") # Avoids shared memory issues in containers
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                     "AppleWebKit/537.36 (KHTML, like Gecko) "
                     "Chrome/125.0.0.0 Safari/537.36")

driver = webdriver.Chrome(options=options)

O modo headless executa o Chrome sem renderizar uma janela gráfica. Isto reduz o consumo de recursos e acelera a execução, o que é importante quando se executam scrapers num servidor ou num pipeline de CI. O --headless=new substituiu o antigo --headless no Chrome 109 e oferece melhor paridade de funcionalidades com o modo com interface gráfica. Para mais informações sobre navegadores headless e quando usá-los, um guia introdutório dedicado à arquitetura de navegadores headless é uma referência útil.

Definir uma string de user-agent personalizada ajuda as suas solicitações a misturarem-se com o tráfego normal do navegador, em vez de revelarem que provêm de uma ferramenta automatizada. Combine isto com um tamanho de janela realista para que os layouts responsivos apresentem a versão para computador da página que pretende analisar.

Outros sinalizadores úteis incluem --disable-extensions (ignora o carregamento de extensões que aumentam o tempo de inicialização), --disable-infobars (oculta o banner «O Chrome está a ser controlado») e --disable-notifications (bloqueia pop-ups que podem ocultar elementos). Em conjunto, estas opções criam um perfil de navegador simplificado, otimizado para a extração de dados em vez da navegação interativa.

Iniciar um navegador e navegar para um URL

Com as suas opções configuradas, iniciar um navegador e visitar uma página requer duas linhas:

driver = webdriver.Chrome(options=options)
driver.get("https://books.toscrape.com/")

driver.get() espera até que o navegador dispare o seu load evento, o que significa que o HTML inicial, o CSS e o JavaScript síncrono foram concluídos. Não aguarda chamadas AJAX que são disparadas após o evento de carregamento, pelo que poderá ainda ser necessário esperar explicitamente por conteúdo injetado dinamicamente (abordado na secção sobre esperas abaixo).

Algumas propriedades úteis logo após a navegação:

print(driver.title)        # Page <title> text
print(driver.current_url)  # Final URL after any redirects

Chame sempre driver.quit() quando terminar, seja num finally ou utilizando o Selenium como gestor de contexto. Deixar os processos do navegador em execução irá causar uma fuga de memória rápida, especialmente em loops. Um padrão simples tem o seguinte aspeto:

try:
    driver = webdriver.Chrome(options=options)
    driver.get("https://example.com")
    # ... scraping logic ...
finally:
    driver.quit()

Isto garante que o navegador seja encerrado mesmo que o seu código lance uma exceção a meio do processo. Familiarizar-se com este tipo de gestão de recursos desde cedo irá poupá-lo de processos Chrome órfãos a consumir a memória do seu servidor em produção. Numa máquina de desenvolvimento, verifique periodicamente o seu gestor de tarefas para confirmar que não há chrome ou chromedriver processos obsoletos de scripts que falharam.

Localizar elementos na página

Encontrar elementos é o cerne de qualquer tutorial de scraping com Selenium. O Selenium fornece dois métodos principais, find_element() (retorna a primeira correspondência) e find_elements() (retorna uma lista de todas as correspondências), cada um dos quais aceita uma By estratégia de localização.

Estratégias de localização comuns

from selenium.webdriver.common.by import By

# By ID (fastest, most reliable when available)
driver.find_element(By.ID, "search-input")

# By class name
driver.find_elements(By.CLASS_NAME, "product-card")

# By CSS selector
driver.find_element(By.CSS_SELECTOR, "div.results > a.item-link")

# By XPath
driver.find_element(By.XPATH, "//table[@id='data']//tr")

# By tag name
driver.find_elements(By.TAG_NAME, "tr")

# By name attribute
driver.find_element(By.NAME, "email")

Os localizadores baseados em ID são normalmente os mais rápidos, porque o navegador pode saltar diretamente para o elemento sem percorrer a árvore DOM. Se o elemento alvo não tiver um ID, os seletores CSS são a segunda melhor opção para a maioria dos casos de utilização: são compactos, legíveis e bem suportados.

XPath vs. Seletores CSS

O XPath destaca-se quando é necessário navegar para cima no DOM (eixo pai), corresponder por conteúdo de texto ou utilizar predicados complexos. Por exemplo, //div[contains(text(), 'Price')] é fácil em XPath, mas não tem equivalente direto em CSS. Os seletores CSS são geralmente mais rápidos de avaliar e mais fáceis de ler para padrões simples como div.card > h3.title. Use o XPath quando o CSS não conseguir expressar a relação de que necessita; opte pelo CSS para tudo o resto. Vale a pena analisar mais a fundo as vantagens e desvantagens entre o XPath e os seletores CSS se estiver a criar seletores para estruturas de página complexas.

find_element vs. find_elements

find_element() lança um NoSuchElementException se nada corresponder, enquanto find_elements() retorna uma lista vazia. Ao fazer scraping, find_elements() é geralmente mais seguro porque pode verificar o comprimento da lista antes do processamento, evitando blocos try/except para elementos em falta.

cards = driver.find_elements(By.CSS_SELECTOR, ".product-card")
if cards:
    for card in cards:
        title = card.find_element(By.CSS_SELECTOR, "h3").text
        price = card.find_element(By.CSS_SELECTOR, ".price").text
        print(title, price)

Note que pode encadear find_element chamadas num WebElement (não apenas no driver). Isto limita a pesquisa à subárvore desse elemento, o que é mais rápido e mais preciso quando se está a iterar sobre estruturas repetidas, como cartões ou linhas de tabela.

O fluxo de trabalho de web scraping do selenium find element é essencialmente: identificar a estratégia de localização, testá-la na consola do DevTools do navegador e, em seguida, codificá-la no seu script Python. O Chrome DevTools permite-lhe testar seletores CSS com $$() e o XPath $x() diretamente no console, o que acelera consideravelmente o desenvolvimento de seletores.

Interagir com elementos da página

Depois de localizar um elemento, o Selenium oferece métodos para agir sobre ele exatamente como um utilizador humano faria. O objeto WebElement disponibiliza ações como clicar, digitar, ler texto e recuperar valores de atributos.

Clicar, Digitar e Ler

from selenium.webdriver.common.keys import Keys

# Click a button
driver.find_element(By.ID, "load-more").click()

# Type into an input field
search_box = driver.find_element(By.NAME, "q")
search_box.clear()
search_box.send_keys("web scraping with selenium")
search_box.send_keys(Keys.RETURN)

# Read text content
heading = driver.find_element(By.TAG_NAME, "h1").text

# Read an attribute value
link = driver.find_element(By.CSS_SELECTOR, "a.detail-link")
href = link.get_attribute("href")

A .text retorna o texto visível de um elemento, enquanto .get_attribute() lê qualquer atributo HTML (href, src, data-*, etc.). Estes dois métodos são as suas principais ferramentas de extração de dados ao nível do elemento.

Trabalhar com menus suspensos

Para <select> elementos, o Selenium fornece uma classe de conveniência:

from selenium.webdriver.support.ui import Select

dropdown = Select(driver.find_element(By.ID, "sort-by"))
dropdown.select_by_visible_text("Price: Low to High")

Também pode selecionar por valor (select_by_value("price_asc")) ou por índice com base zero (select_by_index(2)). As aplicações web modernas utilizam cada vez mais componentes de menus suspensos personalizados em vez de <select> , caso em que terá de clicar no botão de ativação do menu suspenso e, em seguida, clicar na opção desejada como find_element e click .

Encadeamento de ações

A ActionChains API permite-lhe compor interações complexas, tais como passar o cursor, arrastar e largar e clicar com o botão direito:

from selenium.webdriver.common.action_chains import ActionChains

menu = driver.find_element(By.ID, "mega-menu")
ActionChains(driver).move_to_element(menu).perform()

Isto é útil para extrair mega-menus, dicas de ferramentas e outros elementos que só aparecem ao passar o cursor. Pode encadear várias ações antes de chamar .perform() para as executar em sequência.

Cada um destes métodos de interação aguarda que o elemento esteja presente no DOM, mas não necessariamente visível ou clicável. Combine-os com esperas explícitas (abordadas a seguir) para evitar condições de corrida em páginas que carregam conteúdo de forma assíncrona.

Estratégias de espera: esperas implícitas, explícitas e fluentes

As páginas dinâmicas carregam conteúdo de forma assíncrona, e um dos erros mais comuns na extração de dados com o Selenium é tentar localizar um elemento antes de ele existir no DOM. Codificar time.sleep(5) funciona tecnicamente, mas desperdiça tempo em páginas rápidas e falha nas lentas. O Selenium oferece três alternativas mais inteligentes.

Esperas implícitas

Uma espera implícita diz ao driver para sondar o DOM durante um número especificado de segundos antes de lançar um NoSuchElementException:

driver.implicitly_wait(10)  # Applies globally to all find_element calls

Isto é simples de configurar, mas aplica-se a todas as pesquisas, o que pode mascarar problemas de desempenho e tornar o seu scraper mais lento quando os elementos realmente não existem. Também não é possível personalizar a condição: verifica apenas a presença, não a visibilidade ou a capacidade de clicar.

Esperas explícitas

As esperas explícitas são a abordagem recomendada para as melhores práticas do tutorial de scraping com Selenium. Especifica-se uma condição e um tempo limite, e o driver verifica até que a condição seja satisfeita:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

element = WebDriverWait(driver, 15).until(
    EC.visibility_of_element_located((By.CSS_SELECTOR, ".results-container"))
)

As condições comuns incluem:

  • presence_of_element_located: o elemento existe no DOM (pode estar oculto)
  • visibility_of_element_located: o elemento está presente e visível
  • element_to_be_clickable: o elemento está visível e ativado
  • text_to_be_present_in_element: o elemento contém texto específico
  • staleness_of: o elemento já não está associado ao DOM (útil após a navegação)

Isto permite-lhe esperar exatamente pelo que precisa e nada mais, o que mantém o seu scraper rápido sem sacrificar a fiabilidade.

Esperas Fluentes

Uma espera fluente é uma espera explícita com ajustes adicionais: define o intervalo de sondagem e quais as exceções a ignorar durante a sondagem.

from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import NoSuchElementException

wait = WebDriverWait(
    driver, timeout=20, poll_frequency=0.5,
    ignored_exceptions=[NoSuchElementException]
)
element = wait.until(
    EC.presence_of_element_located((By.ID, "dynamic-table"))
)

Utilize esperas fluidas quando o intervalo de sondagem padrão de 500 ms for demasiado agressivo para um alvo com limitação de taxa ou de carregamento lento. Na maioria dos cenários de web scraping com Selenium, uma espera explícita padrão com WebDriverWait cobre as suas necessidades. A lição principal é esta: opte sempre por WebDriverWait em vez de time.sleep(). É mais rápido e mais fiável.

Execução de JavaScript e técnicas de rolagem

Algumas interações são mais fáceis (ou apenas possíveis) através da execução direta de JavaScript. O método execute_script() executa qualquer trecho de JavaScript dentro do contexto do navegador e devolve o resultado ao seu código Python.

Execução básica de scripts

page_height = driver.execute_script("return document.body.scrollHeight;")
print(f"Total page height: {page_height}px")

Pode passar objetos Python como argumentos para o script e referenciá-los através de arguments[0], arguments[1], etc. dentro da string de JavaScript. Os valores de retorno são automaticamente convertidos para os seus equivalentes em Python (dicionários, listas, strings, números).

Deslizar até ao fundo da página

O caso de uso mais comum no scraping é a rolagem infinita. Aqui está um padrão de loop confiável para cenários de scraping de sites dinâmicos com o Selenium:

import time

last_height = driver.execute_script("return document.body.scrollHeight")

while True:
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(2)  # Allow content to load
    new_height = driver.execute_script("return document.body.scrollHeight")
    if new_height == last_height:
        break
    last_height = new_height

O loop compara a altura de rolagem antes e depois de cada rolagem. Quando a altura deixa de mudar, não está a carregar nenhum conteúdo novo e o loop termina. Pode querer adicionar um limite máximo de iterações para evitar loops infinitos em páginas que carregam conteúdo continuamente.

Deslizar até um elemento específico

Por vezes, é necessário trazer um elemento específico para a área de visualização (por exemplo, uma imagem carregada de forma diferida ou um botão «Carregar mais»):

element = driver.find_element(By.ID, "footer-section")
driver.execute_script("arguments[0].scrollIntoView({behavior: 'smooth'});", element)

Acionar ações ocultas

A execução de JavaScript também é útil para clicar em elementos que estão ocultos por sobreposições, remover cabeçalhos fixos que interferem nas capturas de ecrã ou extrair dados incorporados em variáveis JavaScript:

data = driver.execute_script("return window.__INITIAL_STATE__;")

Se o site armazenar dados estruturados num objeto JS global (comum em aplicações React e Next.js), obtê-los diretamente é mais rápido do que analisar o DOM renderizado. Recebe-se um dicionário Python de execute_script, que pode ser processado imediatamente sem qualquer análise de HTML.

Tirar capturas de ecrã para depuração

Quando um scraper falha silenciosamente ou devolve resultados inesperados, uma captura de ecrã do estado da página no momento da falha é inestimável.

driver.save_screenshot("debug_screenshot.png")

Também pode capturar um elemento específico:

element = driver.find_element(By.ID, "captcha-container")
element.screenshot("captcha_element.png")

Guarde capturas de ecrã dentro dos seus blocos de tratamento de erros para que possa inspecionar visualmente o que o navegador estava a renderizar quando algo correu mal. No modo headless, isto é especialmente importante porque não há nenhuma janela visível para se olhar. Combine capturas de ecrã com o registo de driver.current_url e driver.page_source[:500] para obter um instantâneo completo de depuração.

Para pipelines de scraping de longa duração, considere guardar capturas de ecrã com data e hora em pontos de verificação-chave (após o login, após a paginação, antes da extração de dados) para que possa rastrear exatamente onde uma execução se desviou do caminho esperado.

Tratamento da paginação em várias páginas

A maioria dos sites distribui os dados por várias páginas, e um scraper de nível de produção precisa de seguir automaticamente esses links de paginação. Existem dois padrões comuns: paginação por parâmetros de URL e paginação baseada em cliques.

Paginação por parâmetros de URL

Se o site utilizar cadeias de consulta como ?page=2, pode construir URLs diretamente:

all_results = []
for page_num in range(1, 50):
    driver.get(f"https://example.com/listings?page={page_num}")
    WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.CSS_SELECTOR, ".listing-card"))
    )
    items = driver.find_elements(By.CSS_SELECTOR, ".listing-card")
    if not items:
        break  # No results means we passed the last page
    for item in items:
        all_results.append({
            "title": item.find_element(By.CSS_SELECTOR, "h2").text,
            "price": item.find_element(By.CSS_SELECTOR, ".price").text,
        })

A if not items: break verificação é a forma mais simples de detetar a última página: quando uma página devolve zero resultados, pára. Uma abordagem alternativa é verificar se o número da página atual excede o total indicado no widget de paginação, ou procurar um link «próxima página» e parar quando este desaparecer.

Paginação baseada em cliques

Alguns sites carregam a página seguinte através de JavaScript quando clica no botão «Seguinte»:

from selenium.common.exceptions import NoSuchElementException

all_results = []
while True:
    items = driver.find_elements(By.CSS_SELECTOR, ".listing-card")
    for item in items:
        all_results.append(item.find_element(By.CSS_SELECTOR, "h2").text)

    try:
        next_btn = driver.find_element(By.CSS_SELECTOR, "a.next-page")
        if "disabled" in next_btn.get_attribute("class"):
            break
        next_btn.click()
        WebDriverWait(driver, 10).until(EC.staleness_of(items[0]))
    except NoSuchElementException:
        break

A staleness_of condição aguarda até que os elementos antigos sejam removidos do DOM, confirmando que a nova página foi carregada. Verificar se existe uma classe «disabled» no botão «Seguinte» lida com a página final de forma elegante.

Ambos os padrões necessitam de uma condição de terminação clara. Sem ela, o seu scraper ficará em loop infinito ou irá falhar na última página. Teste sempre a sua lógica de paginação em relação ao limite: o que acontece na última página?

Scraping de dados de vários URLs

Quando os seus dados-alvo se encontram em páginas de detalhes separadas (por exemplo, uma lista de produtos com links para páginas de produtos individuais), normalmente faz o scraping em duas etapas: recolhe os URLs da lista e, em seguida, visita cada um deles.

# Pass 1: Collect detail URLs from the listing page
driver.get("https://example.com/catalog")
links = driver.find_elements(By.CSS_SELECTOR, "a.product-link")
detail_urls = [link.get_attribute("href") for link in links]

# Pass 2: Visit each detail URL and extract data
products = []
for url in detail_urls:
    try:
        driver.get(url)
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, ".product-detail"))
        )
        products.append({
            "name": driver.find_element(By.CSS_SELECTOR, "h1.product-name").text,
            "description": driver.find_element(By.CSS_SELECTOR, ".description").text,
            "url": url,
        })
    except Exception as e:
        print(f"Skipped {url}: {e}")
        continue

driver.quit()

Reutilize a mesma instância do WebDriver durante todo o processo. Abrir um novo navegador para cada URL desperdiça tempo de inicialização e memória. Envolver o loop interno num try/except garante que uma única página com erros não faça com que todo o seu scraping falhe.

Este padrão mestre-detalhe é um dos fluxos de trabalho mais práticos para extrair dados de sites com Python Selenium. Combina bem com o ciclo de paginação da secção anterior para rastrear um catálogo inteiro. Recolha primeiro todos os URLs das páginas de lista em toda a paginação e, em seguida, percorra as páginas de detalhes numa segunda etapa.

Para listas de URLs extensas, considere adicionar um pequeno atraso entre os pedidos (0,5 a 2 segundos) para permanecer dentro dos limites de taxa do site e reduzir a probabilidade de ativar defesas anti-bot. Pode aleatorizar ligeiramente o atraso para tornar o seu padrão de pedidos menos previsível.

Extrair e analisar tabelas HTML

Os dados tabulares são um dos alvos mais estruturados (e, portanto, mais fáceis) para a extração de dados da Web com o Selenium. Aqui está um padrão genérico que funciona em qualquer tabela HTML padrão:

table = driver.find_element(By.CSS_SELECTOR, "table#stats")

# Extract headers
headers = [th.text for th in table.find_elements(By.CSS_SELECTOR, "thead th")]

# Extract rows
rows = []
for tr in table.find_elements(By.CSS_SELECTOR, "tbody tr"):
    cells = [td.text for td in tr.find_elements(By.TAG_NAME, "td")]
    rows.append(dict(zip(headers, cells)))

Isto dá-lhe uma lista de dicionários onde cada chave é um cabeçalho de coluna e cada valor é o texto da célula correspondente. É uma estrutura limpa e previsível que se integra diretamente no seu pipeline de exportação.

Se a tabela for grande ou se pretender fazer análises adicionais, passar o trabalho para o pandas é mais eficiente:

import pandas as pd

html = driver.page_source
tables = pd.read_html(html, attrs={"id": "stats"})
df = tables[0]

pd.read_html lida com colspan, rowspan e tabelas aninhadas de forma mais elegante do que a iteração manual de elementos. Use o page_source para lhe fornecer o HTML totalmente renderizado, que inclui quaisquer dados injetados pelo JavaScript.

Tenha cuidado com tabelas que carregam linhas dinamicamente à medida que se desloca. Nesses casos, é necessário deslocar o contentor da tabela (não apenas a página) para acionar o carregamento diferido antes de extrair as linhas. Alguns sites financeiros e de análise utilizam tabelas virtualizadas que apenas renderizam as linhas visíveis, o que requer uma deslocação incremental para capturar o conjunto de dados completo.

Combinar o Selenium com o BeautifulSoup para uma análise mais rápida

O Selenium é excelente na renderização de páginas, mas os seus métodos de pesquisa de elementos são relativamente lentos porque cada chamada atravessa a fronteira do protocolo WebDriver. Um truque comum de desempenho consiste em deixar o Selenium tratar da renderização e, em seguida, passar o HTML finalizado para o BeautifulSoup para análise.

from bs4 import BeautifulSoup

driver.get("https://example.com/products")
WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, ".product-grid"))
)

soup = BeautifulSoup(driver.page_source, "html.parser")
cards = soup.select(".product-card")

for card in cards:
    title = card.select_one("h3").get_text(strip=True)
    price = card.select_one(".price").get_text(strip=True)
    print(title, price)

Este padrão de web scraping com Selenium e BeautifulSoup oferece o melhor de ambos os mundos: o Selenium executa JavaScript para que o DOM fique completo, e o BeautifulSoup analisa o instantâneo HTML estático na memória sem qualquer ida e volta pela rede. Em páginas com centenas de elementos, a diferença de velocidade é notável.

O fluxo de trabalho é simples: use o Selenium para navegação e execução de JavaScript e, em seguida, mude para o BeautifulSoup (ou lxml) no momento em que tiver o page_source. Isto reduz o número de chamadas ao WebDriver de centenas para uma. Se é novo no BeautifulSoup, um guia sobre a extração e análise de dados da Web com o BeautifulSoup é um complemento útil para este tutorial.

Exportar dados extraídos para CSV e JSON

Os dados brutos armazenados numa lista Python só são úteis enquanto o seu script estiver a ser executado. Quase sempre vai querer mantê-los.

Exportação para CSV

import csv

fieldnames = ["title", "price", "url"]
with open("products.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(all_results)

Exportação para JSON

import json

with open("products.json", "w", encoding="utf-8") as f:
    json.dump(all_results, f, indent=2, ensure_ascii=False)

Atalho do Pandas

Se já estiver a usar o pandas, uma única linha de código lida com qualquer um dos formatos:

import pandas as pd

df = pd.DataFrame(all_results)
df.to_csv("products.csv", index=False)
df.to_json("products.json", orient="records", indent=2)

Escolha CSV quando as ferramentas a jusante esperam dados tabulares planos (folhas de cálculo, importações SQL). Escolha JSON quando os seus dados estiverem aninhados ou precisar de preservar tipos como matrizes e objetos. Para conjuntos de dados muito grandes, considere escrever linhas de forma incremental em vez de acumular tudo na memória primeiro. A csv.DictWriter abordagem suporta naturalmente gravações incrementais, pois pode esvaziar a memória após cada linha.

Limpeza e validação de dados extraídos

Os dados extraídos raramente estão prontos para análise assim que saem do navegador. Linhas duplicadas, campos em falta e formatação inconsistente são a regra, não a exceção.

import pandas as pd

df = pd.DataFrame(all_results)

# Remove exact duplicate rows
df.drop_duplicates(inplace=True)

# Drop rows where critical fields are missing
df.dropna(subset=["title", "price"], inplace=True)

# Normalize price strings to floats
df["price"] = (df["price"]
               .str.replace(r"[^0-9.]", "", regex=True)
               .astype(float))

# Strip extra whitespace from text fields
df["title"] = df["title"].str.strip()

Esta etapa de limpeza faz a ponte entre a saída bruta extraída e os dados que são realmente úteis para análise, relatórios ou alimentação de uma base de dados. Executar estas verificações antes da exportação permite detetar problemas precocemente, em vez de descobrir dados incorretos numa fase posterior.

Verificações de validação comuns que vale a pena adicionar incluem verificar se os URLs estão bem formados, se os campos numéricos se encontram dentro dos intervalos esperados (um preço de produto de $0,00 pode ser um erro de análise) e se os campos de texto obrigatórios não são cadeias vazias disfarçadas de valores presentes. Criar uma pequena função de validação que seja executada após cada sessão de scraping torna o seu pipeline mais robusto ao longo do tempo.

Utilizar proxies com o Selenium para evitar bloqueios

Se enviar demasiados pedidos a partir de um único endereço IP, o site de destino acabará por bloqueá-lo. Os proxies distribuem o seu tráfego por diferentes IPs, reduzindo a probabilidade de bloqueios e permitindo o acesso a conteúdos com restrições geográficas.

Configuração manual de proxies

from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument("--proxy-server=http://123.45.67.89:8080")

driver = webdriver.Chrome(options=options)
driver.get("https://httpbin.org/ip")
print(driver.find_element(By.TAG_NAME, "body").text)
driver.quit()

Esta abordagem funciona para um único proxy, mas alternar manualmente entre um conjunto (iniciando um novo driver por IP) é tedioso e lento. Os proxies de datacenter são mais baratos, mas mais fáceis de detetar pelos sites, enquanto os proxies residenciais encaminham o tráfego através de IPs de consumidores reais e são muito mais difíceis de distinguir de visitantes genuínos.

Proxies autenticados

Muitos fornecedores de proxies exigem autenticação com nome de utilizador/palavra-passe. O Chrome não suporta nativamente a autenticação de proxy através de sinalizadores de linha de comandos, pelo que é necessária uma solução alternativa. Um método comum é uma extensão de navegador leve que insere credenciais automaticamente no handshake do proxy. Outra opção é executar um proxy local (como o mitmproxy) que adiciona o cabeçalho de autenticação e encaminha para o proxy remoto.

Quando utilizar um serviço de proxy gerido

Manter o seu próprio conjunto de proxies, gerir a lógica de rotação e lidar com IPs banidos é uma sobrecarga operacional que cresce com a escala. Os serviços de proxy geridos oferecem-lhe um único ponto de acesso que gere a rotação, a autenticação e a integridade dos IPs nos bastidores. Isto é particularmente útil para a extração de dados da Web com proxy Selenium em volumes de produção, onde são necessários centenas de IPs rotativos em diferentes regiões geográficas.

Para dicas sobre como evitar bloqueios, as estratégias abordadas nos guias sobre como evitar bloqueios de IP durante o web scraping aplicam-se diretamente também a configurações baseadas em Selenium. As práticas-chave incluem a rotação de user agents juntamente com os IPs, a adição de atrasos aleatórios entre pedidos e o respeito pelas robots.txt diretivas.

Detetar e evitar armadilhas honeypot

Um honeypot é um elemento HTML oculto que é invisível para visitantes humanos, mas exposto aos bots. Se o seu scraper interagir com ele (clicar num link oculto, preencher um campo de formulário oculto), o site marca a sua sessão como automatizada e pode bloqueá-lo imediatamente.

O padrão mais comum é um campo de formulário com o estilo display:none ou visibility:hidden:

hidden_inputs = driver.find_elements(
    By.CSS_SELECTOR, "input[style*='display:none'], input[style*='visibility:hidden']"
)

for inp in hidden_inputs:
    print(f"Honeypot detected: name={inp.get_attribute('name')}")

Regras de codificação defensiva para honeypots:

  • Nunca percorra cegamente todos os campos de formulário e os preencha. Verifique primeiro a visibilidade.
  • Utilize element.is_displayed() antes de interagir com qualquer elemento que não tenha selecionado explicitamente.
  • Se um link tiver opacity: 0 ou estiver posicionado fora do ecrã com coordenadas negativas, ignore-o.
  • Algumas armadilhas utilizam classes CSS em vez de estilos inline. Inspecione o estilo calculado com execute_script se suspeitar que o site usa CSS externo para ocultar elementos de armadilha.

A deteção de honeypots torna-se especialmente importante quando o seu scraper preenche formulários (campos de pesquisa, campos de login, formulários de contacto). Uma simples verificação de visibilidade antes de cada interação acrescenta uma sobrecarga mínima e evita um tipo de deteção que, de outra forma, seria difícil de depurar.

Dicas de otimização de desempenho

O Selenium controla um navegador completo, pelo que todas as otimizações que reduzam o trabalho do navegador se traduzem diretamente em execuções de scraping mais rápidas e económicas.

Execute no modo headless. Remover a camada GUI reduz significativamente o tempo de arranque e o uso de memória. Use --headless=new nas suas opções do Chrome. Um guia sobre navegadores headless aborda as nuances em profundidade.

Bloqueie recursos desnecessários. Imagens, tipos de letra e ficheiros CSS aumentam o tempo de carregamento sem contribuírem com dados. Pode usar os comandos do Protocolo do Chrome DevTools para os bloquear:

driver.execute_cdp_cmd("Network.setBlockedURLs", {
    "urls": ["*.jpg", "*.png", "*.gif", "*.svg", "*.woff2", "*.css"]
})
driver.execute_cdp_cmd("Network.enable", {})

Dê preferência a localizadores rápidos. As pesquisas baseadas em ID são as mais rápidas. Expressões XPath complexas que percorrem grandes subárvores custam mais. Quando tiver escolha, use By.ID ou um seletor CSS curto.

Ajuste as suas esperas. Esperas implícitas excessivamente generosas tornam mais lenta a pesquisa de cada elemento. Use esperas explícitas direcionadas com WebDriverWait e defina tempos de espera com base no comportamento específico da página, em vez de um tempo de espera padrão de 30 segundos.

Minimize as reinicializações do navegador. Reutilize uma única instância do driver em todas as páginas sempre que possível. Cada webdriver.Chrome() chamada gera um processo completo do navegador.

Desative funcionalidades de que não necessita. Opções como --disable-extensions, --disable-infobarse --blink-settings=imagesEnabled=false reduzem ainda mais a sobrecarga do navegador.

Estratégia de carregamento de páginas. Defina options.page_load_strategy = "eager" para deixar de esperar que as imagens e as folhas de estilo terminem de carregar. O DOM fica interativo mais cedo e pode começar a extração mais cedo.

Estas otimizações somam-se. Aplicá-las todas em conjunto pode reduzir o tempo de execução de uma tarefa de scraping sem interface do Selenium em 50% ou mais, em comparação com uma configuração padrão.

Desafios comuns e como resolvê-los

Mesmo com um scraper bem configurado, irá deparar-se com problemas. Aqui estão os problemas mais frequentes e as suas soluções.

Desafio

Causa

Solução

NoSuchElementException

O elemento ainda não foi carregado

Utilize WebDriverWait com uma condição esperada apropriada

Referência a elemento desatualizada

O DOM foi alterado depois de localizar o elemento

Localize novamente o elemento após qualquer navegação na página ou recarregamento AJAX

Blocos CAPTCHA

O site deteta tráfego automatizado

Diminua a frequência das solicitações, alterne os user agents, utilize proxies residenciais

Dados inconsistentes

O layout da página varia entre produtos/categorias

Adicione verificações defensivas com find_elements e teste o comprimento da lista antes de aceder

Fugas de memória em execuções prolongadas

O navegador acumula estado ao longo de centenas de páginas

Reinicie o driver periodicamente (a cada N páginas) ou limpe os cookies/cache

Execução lenta

Sobrecarga total de renderização do navegador

Aplique as dicas de otimização da secção anterior

Padrão de tratamento de erros: Envolva o seu ciclo de scraping num try/except que capture WebDriverException como um mecanismo de fallback abrangente. Registe o URL, guarde uma captura de ecrã e avance para o item seguinte, em vez de interromper todo o trabalho.

from selenium.common.exceptions import WebDriverException

for url in urls:
    try:
        driver.get(url)
        # ... extraction logic ...
    except WebDriverException as e:
        driver.save_screenshot(f"error_{url.split('/')[-1]}.png")
        print(f"Failed on {url}: {e}")
        continue

Se estiver a observar falhas intermitentes num site que normalmente funciona, verifique se o site está a apresentar conteúdo diferente com base na geolocalização, no agente do utilizador ou na hora do dia. Registar o código-fonte completo da página em caso de falha (além da captura de ecrã) ajuda a diagnosticar este tipo de problemas ambientais. Contornar o Cloudflare e serviços de proteção semelhantes com o Selenium requer técnicas adicionais para além da configuração básica.

Escalabilidade com o Selenium Grid

Uma única instância do Selenium está limitada a um navegador de cada vez. Quando precisa de extrair milhares de páginas em paralelo, o Selenium Grid distribui as sessões do navegador por várias máquinas.

Como funciona o Grid

O Selenium Grid utiliza uma arquitetura de hub e nós. O hub é um servidor central que recebe pedidos do WebDriver e os encaminha para os nós disponíveis, cada um dos quais executa uma ou mais instâncias de navegador. Aponte o seu script para o URL do hub em vez de um driver local:

from selenium import webdriver

options = webdriver.ChromeOptions()
driver = webdriver.Remote(
    command_executor="http://grid-hub:4444/wd/hub",
    options=options
)

Pode executar o hub e os nós utilizando o Docker, o que simplifica o dimensionamento:

docker run -d -p 4444:4444 selenium/hub
docker run -d --link selenium-hub:hub selenium/node-chrome

Considerações práticas

Executar dezenas de sessões de navegador em paralelo consome muitos recursos de CPU e RAM. Monitorize os seus nós e defina um limite máximo de sessões para evitar sobrecarga. A depuração também é mais difícil numa configuração distribuída, porque as capturas de ecrã e os registos estão em máquinas remotas. Use a funcionalidade de gravação de vídeo integrada do Grid ou o registo centralizado para manter a visibilidade.

O Selenium Grid é uma escolha sólida para cargas de trabalho de web scraping do Selenium Grid que necessitem de paralelismo moderado (5 a 20 sessões simultâneas). Para além disso, a carga operacional de gerir nós, lidar com falhas e monitorizar a utilização de recursos cresce rapidamente. Para equipas que não queiram gerir a infraestrutura do Grid, os serviços de navegador alojados na nuvem ou as ferramentas de scraping baseadas em API oferecem o mesmo modelo de execução paralela que um serviço gerido.

Selenium vs. Playwright vs. Puppeteer: Comparação Rápida

O Selenium não é a única ferramenta de automação de navegadores. O Playwright e o Puppeteer são alternativas modernas populares, cada uma com pontos fortes diferentes.

Característica

Selenium

Playwright

Puppeteer

Suporte a linguagens

Python, Java, C#, JS, Ruby

Python, Java, .NET, JS/TS

Apenas JavaScript/TypeScript

Motores de navegador

Chrome, Firefox, Edge, Safari

Chromium, Firefox, WebKit

Apenas Chromium

Aguardar automaticamente

Manual (esperas explícitas/implícitas)

Espera automática integrada nas ações

Manual (waitForSelector)

Velocidade

Mais lento (protocolo WebDriver)

Mais rápido (CDP / canais do navegador)

Mais rápido (CDP)

Execução paralela

Através do Selenium Grid

Contextos nativos do navegador

Através de contextos de página/navegador

Comunidade

A maior e mais madura

Em rápido crescimento

Grande (focado no Chromium)

Escolha o Selenium quando precisar de suporte multilingue, compatibilidade para testes em vários navegadores ou quando a sua equipa já conhecer a API do Selenium. Escolha o Playwright se quiser espera automática integrada, padrões assíncronos modernos e suporte para vários navegadores a partir de uma única biblioteca. Escolha o Puppeteer se a sua pilha for apenas JavaScript e precisar apenas do Chromium.

Todas as três ferramentas podem lidar com scraping orientado por navegador, mas a espera automática integrada do Playwright e os contextos de navegador nativos para paralelismo conferem-lhe uma vantagem para novos projetos que não necessitam do ecossistema de linguagens mais abrangente do Selenium. Para um aprofundamento nas capacidades de scraping do Playwright, os recursos sobre web scraping do Playwright fornecem uma comparação exaustiva.

Renderização de JavaScript sem um navegador: alternativas baseadas em API

Executar um navegador completo funciona, mas é dispendioso em termos de CPU, RAM e manutenção de engenharia. Quando o seu objetivo é simplesmente obter o HTML renderizado de uma página com muito JavaScript, uma abordagem baseada em API pode ser muito mais eficiente.

As APIs de scraping geridas aceitam um URL e devolvem o HTML totalmente renderizado (ou mesmo JSON pré-analisado). Nos bastidores, elas tratam da renderização do navegador, rotação de proxies, resolução de CAPTCHA e lógica de repetição de tentativas. Envia-se um único pedido HTTP e obtêm-se dados limpos em resposta, o que significa que o seu código de scraping permanece tão simples quanto uma requests.get() chamada.

Este modelo destaca-se quando:

  • Está a fazer scraping em grande escala e não quer gerir a infraestrutura do Selenium Grid.
  • Os sistemas anti-bot são agressivos e exigem rotação de proxies residenciais, além de gestão de impressões digitais do navegador.
  • Quer separar totalmente a sua lógica de análise da camada de renderização.
  • A sua equipa não tem capacidade de DevOps para manter as versões do navegador e do driver em todos os ambientes.

A desvantagem é o controlo. Com o Selenium, pode clicar em botões, preencher formulários e navegar em fluxos de trabalho com várias etapas. Os renderizadores baseados em API normalmente lidam com recuperações de páginas únicas. Para scraping interativo complexo (fluxos de login, assistentes com várias etapas), o Selenium ou uma ferramenta de automação de navegador semelhante continua a ser a melhor opção.

Uma abordagem híbrida funciona bem na prática: utilize o Selenium localmente durante o desenvolvimento para compreender a estrutura da página e criar os seus seletores, depois mude para um serviço baseado em API na produção para evitar a sobrecarga operacional de executar navegadores em escala. Isto dá-lhe a flexibilidade do web scraping com o Selenium durante a prototipagem e a fiabilidade de um serviço gerido na produção. Mantém o mesmo código de análise em ambos os casos; apenas a camada de obtenção de dados muda.

Exemplo completo: Projeto de Web Scraping de ponta a ponta com o Selenium

Vamos reunir tudo num único script executável. Este exemplo extrai títulos e preços de livros de um site de demonstração paginado, limpa os dados e exporta-os para CSV.

import csv
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# --- Setup ---
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--window-size=1920,1080")
options.add_argument("--disable-gpu")
driver = webdriver.Chrome(options=options)

all_books = []
base_url = "https://books.toscrape.com/catalogue/page-{}.html"

# --- Scrape with Pagination ---
for page in range(1, 51):
    driver.get(base_url.format(page))
    try:
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, ".product_pod"))
        )
    except Exception:
        break  # No more pages

    books = driver.find_elements(By.CSS_SELECTOR, ".product_pod")
    if not books:
        break

    for book in books:
        title = book.find_element(By.CSS_SELECTOR, "h3 a").get_attribute("title")
        price = book.find_element(By.CSS_SELECTOR, ".price_color").text
        all_books.append({"title": title, "price": price})

driver.quit()

# --- Clean ---
seen = set()
cleaned = []
for book in all_books:
    key = (book["title"], book["price"])
    if key not in seen:
        seen.add(key)
        price_str = book["price"].replace("\xa3", "").strip()
        try:
            book["price"] = float(price_str)
        except ValueError:
            continue
        cleaned.append(book)

# --- Export ---
with open("books.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["title", "price"])
    writer.writeheader()
    writer.writerows(cleaned)

print(f"Scraped {len(cleaned)} books to books.csv")

Este script demonstra todo o ciclo de vida abordado neste tutorial: configuração do Chrome headless, esperas explícitas, localização de elementos com seletores CSS, paginação com deteção da última página, deduplicação, normalização de tipos de dados e exportação para CSV. Pode adaptá-lo a qualquer alvo, substituindo o padrão de URL e os seletores CSS.

Vale a pena destacar as principais decisões de design neste exemplo. Utilizamos --headless=new para obter velocidade. Envolvemos a espera num try/except para lidar com o caso de página não encontrada de forma elegante. Desduplicamos rastreando pares de título/preço já vistos num conjunto. E normalizamos os preços para valores flutuantes antes da exportação, para que as ferramentas a jusante possam ordenar e filtrar numericamente.

A partir daqui, pode alargar este script adicionando rotação de proxies, gravando os resultados numa base de dados em vez de CSV, ou implementando-o de forma programada com um executor de tarefas como o cron ou o Airflow. Os padrões que aprendeu ao longo deste tutorial encaixam-se como blocos de construção.

Pontos-chave

  • Use o Selenium quando for necessária a renderização em JavaScript. Para páginas HTML estáticas, ferramentas mais leves como requests BeautifulSoup ou Scrapy são mais rápidas e económicas de executar.
  • Utilize sempre esperas explícitas em vez de time.sleep(). WebDriverWait com expected_conditions torna o seu scraper mais rápido e mais fiável em páginas dinâmicas.
  • Bloqueie recursos desnecessários e execute em modo headless. Desativar imagens, fontes e CSS no modo headless pode reduzir o tempo de execução pela metade sem perder quaisquer dados extraídos.
  • Limpe os seus dados antes de exportar. A deduplicação, o tratamento de valores nulos e a normalização de tipos detetam problemas numa fase inicial e poupam tempo de depuração a jusante.
  • Planeie a escalabilidade desde o início. A rotação de proxies, o Selenium Grid e alternativas de renderização baseadas em API mantêm o seu scraper a funcionar à medida que os sites-alvo se tornam mais defensivos.

Perguntas frequentes

O Selenium é adequado para a extração de dados da Web em grande escala?

Pode funcionar, mas consome muitos recursos. Cada instância de navegador consome uma quantidade significativa de CPU e RAM, pelo que a execução de centenas de sessões paralelas requer uma infraestrutura robusta. O Selenium Grid ajuda a distribuir a carga entre máquinas, e o modo headless reduz a sobrecarga por sessão. Para trabalhos verdadeiramente em grande escala (milhões de páginas), os serviços de renderização baseados em API ou frameworks concebidos para rastreamento são frequentemente mais económicos.

O Selenium consegue fazer web scraping em sites que exigem autenticação de login?

Sim. Pode automatizar todo o fluxo de login: navegar até à página de login, localizar os campos de nome de utilizador e palavra-passe com find_element, introduzir as credenciais com send_keyse clicar no botão de envio. Após a autenticação, o Selenium mantém os cookies de sessão para que as páginas carregadas posteriormente permaneçam autenticadas durante toda a sessão.

Como lido com CAPTCHAs ao fazer scraping com o Selenium?

Os CAPTCHAs foram concebidos para impedir a automatização, pelo que não existe uma solução simples dentro do próprio navegador. As estratégias comuns incluem diminuir a frequência das solicitações para evitar ativar os CAPTCHAs desde o início, utilizar proxies residenciais para reduzir a deteção e integrar serviços de terceiros para resolver CAPTCHAs que devolvem tokens que se inserem na página através de JavaScript.

A legalidade depende da jurisdição, dos termos de serviço do site e do tipo de dados recolhidos. Nos Estados Unidos, a decisão do Supremo Tribunal no caso hiQ v. LinkedIn esclareceu que a extração de dados publicamente disponíveis não constitui necessariamente uma violação da CFAA. No entanto, a extração de dados pessoais pode implicar o RGPD na UE. Reveja sempre os robots.txt e os termos de serviço do site de destino e consulte um advogado para projetos de scraping comercial.

Qual é a diferença entre o Selenium e o BeautifulSoup?

Resolvem problemas diferentes. O Selenium controla um navegador real e pode executar JavaScript, clicar em botões e navegar em páginas interativas. O BeautifulSoup é um analisador que recebe uma sequência HTML e fornece métodos para consultar e extrair dados da mesma, mas não consegue carregar páginas nem executar JavaScript. Muitos scrapers combinam ambos: o Selenium renderiza a página e, em seguida, o BeautifulSoup analisa o instantâneo HTML para uma extração mais rápida.

Conclusão

O web scraping com o Selenium permite-lhe extrair dados de praticamente qualquer site, incluindo aplicações com muito JavaScript que as bibliotecas HTTP estáticas não conseguem lidar. Ao longo deste tutorial, viu como preparar o ambiente, configurar o navegador, localizar e interagir com elementos, lidar com conteúdo dinâmico com esperas explícitas, paginar conjuntos de resultados e exportar dados limpos.

A principal desvantagem do Selenium é o custo de recursos. Um navegador real consome mais CPU e memória do que uma solicitação HTTP leve, e esse custo multiplica-se à medida que se escala. Para muitos cenários de scraping, o caminho prático a seguir é usar o Selenium para desenvolvimento e prototipagem e, em seguida, transferir a complexidade da renderização e do anti-bot para um serviço dedicado quando se passa para a produção.

Se se vir a gastar mais tempo a gerir proxies, a lutar contra CAPTCHAs e a manter a infraestrutura do navegador do que a escrever a lógica de análise propriamente dita, a WebScrapingAPI pode tratar da camada de renderização e entrega por si, para que se possa concentrar nos dados em si. Essa separação de responsabilidades mantém a sua base de código limpa e o seu pipeline de scraping fiável.

Seja qual for a ferramenta que escolher, comece com a solução mais leve que funcione para o seu caso de uso, adicione complexidade apenas quando for necessário e respeite sempre os termos de serviço do site de destino.

Sobre o autor
Robert Sfichi, Desenvolvedor Full-Stack @ 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.