Páginas dinâmicas com Selenium

Em fase de testes Atividades: Esta seção está em validação e pode sofrer ajustes.

Quando o conteúdo de interesse é renderizado por JavaScript depois que a página carrega, requests não enxerga esse conteúdo. A solução é usar um navegador automatizado: Selenium controla um Chrome (ou Firefox) real e permite interagir com a página como um usuário.

Instalação

pip install selenium webdriver-manager

webdriver-manager cuida de baixar o driver compatível com a versão do navegador instalado.

Estrutura mínima

from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
from time import sleep


def acessar_pagina_dinamica(link):
    options = Options()
    options.add_argument("--headless=new")        # sem janela visível
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-dev-shm-usage")

    navegador = webdriver.Chrome(
        service=ChromeService(ChromeDriverManager().install()),
        options=options,
    )
    navegador.get(link)
    sleep(2)  # tempo para o JS carregar
    return navegador
💡 Dica

--headless=new roda o Chrome sem abrir interface gráfica. Útil para servidores e CI. Em desenvolvimento, remova essa opção para ver o que o coletor está fazendo.

Localizar elementos

Selenium localiza elementos usando seletores via classe By:

from selenium.webdriver.common.by import By

# Por ID
botao = navegador.find_element(By.ID, "button1")

# Por seletor CSS
campo_ano = navegador.find_element(By.CSS_SELECTOR, "#ano")

# Vários elementos
opcoes = campo_ano.find_elements(By.TAG_NAME, "option")

Interagir com a página

Diferente do BeautifulSoup, Selenium permite clicar, digitar e submeter formulários:

# Selecionar um ano em um dropdown e clicar em Pesquisar
opcoes_ano = navegador.find_element(By.CSS_SELECTOR, "#ano").find_elements(By.TAG_NAME, "option")
opcoes_ano[0].click()

navegador.find_element(By.CSS_SELECTOR, "#button1").click()
sleep(2)

Exemplo: baixar PDFs do Diário da Câmara

O portal imagem.camara.leg.br exibe os Diários por ano. Para cada ano, é preciso clicar em “Pesquisar”, esperar a renderização do calendário e extrair os links dos dias publicados:

from datetime import datetime
import requests

def baixar_diarios_do_ano(navegador, indice_ano):
    opcoes = navegador.find_element(By.CSS_SELECTOR, "#ano").find_elements(By.TAG_NAME, "option")
    opcoes[indice_ano].click()
    navegador.find_element(By.CSS_SELECTOR, "#button1").click()
    sleep(2)

    dias = navegador.find_elements(By.CSS_SELECTOR, ".calWeekDaySel, .calWeekEndSel")
    print(f"{len(dias)} dias publicados neste ano")

    for dia in dias:
        href = dia.find_element(By.TAG_NAME, "a").get_attribute("href")
        data_str = href.split("=")[-1]                              # "5/2/2019"
        data = datetime.strptime(data_str, "%d/%m/%Y")
        nome = data.strftime("%Y-%m-%d") + ".pdf"

        url_final = obter_url_final_apos_redirecionamentos(href)
        resposta = requests.get(url_final, timeout=60)
        if resposta.ok:
            with open(f"dados/{nome}", "wb") as f:
                f.write(resposta.content)

Esperas explícitas

sleep fixo desperdiça tempo (ou falha quando a rede está lenta). Para casos sérios, prefira esperas explícitas:

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

espera = WebDriverWait(navegador, 10)
elemento = espera.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#ano")))

A espera retorna assim que a condição é satisfeita (até o timeout).

Encerrar sempre o navegador

Cada webdriver.Chrome() abre um processo. Não esquecer de encerrar:

try:
    navegador = acessar_pagina_dinamica(link)
    # ...
finally:
    navegador.quit()

Em scripts longos, considere reaproveitar uma única instância do navegador em vez de abrir uma a cada chamada.

Quando preferir BS4

Selenium é mais lento e mais frágil do que requests + BS4. Sempre tente primeiro a coleta estática. Use Selenium apenas quando:

  • O conteúdo é injetado por JavaScript após o carregamento.
  • A navegação exige cliques, scroll ou login interativo.
  • O site usa proteção anti-bot que bloqueia clientes simples.

Para coletas pesadas em páginas dinâmicas, considere também Playwright (API mais moderna) ou Scrapy + scrapy-splash.