Para automatizar ou testar um navegador com Python, instale o Playwright, baixe os binários, abra uma página e interaja por meio de locators. A biblioteca cuida de grande parte das esperas antes de clicar ou preencher, enquanto expect valida estados visíveis para o usuário. Downloads e screenshots têm APIs próprias, e a integração com pytest permite isolar cada teste. O resultado é mais confiável do que scripts baseados em coordenadas, seletores frágeis e pausas fixas.

Playwright controla Chromium, Firefox e WebKit com uma API consistente. Ele é útil em testes de ponta a ponta, verificações de regressão e automações internas autorizadas. Para fundamentos de testes, consulte o guia de pytest em Python; para automação fora do navegador, veja automação de tarefas com Python.

Instalação e primeiro script

Crie um ambiente virtual Python e instale o pacote e um navegador:

python -m pip install playwright pytest pytest-playwright
python -m playwright install chromium

O segundo comando instala o navegador compatível com a versão da biblioteca. Em CI Linux, python -m playwright install --with-deps chromium também instala dependências do sistema. A documentação oficial do Playwright para Python mantém instruções por plataforma.

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto("https://example.com", wait_until="domcontentloaded")
    print(page.title())
    page.screenshot(path="evidencia.png", full_page=True)
    browser.close()

O modo síncrono é direto para scripts e pytest. A API assíncrona é apropriada quando a aplicação já usa asyncio; nesse caso, use async_playwright e await, seguindo os conceitos de async e await em Python. Não misture as duas APIs no mesmo fluxo.

Locators resistentes a mudanças

Um locator representa uma forma de encontrar elementos e é resolvido novamente a cada ação. Prefira atributos percebidos pelo usuário ou contratos explícitos de teste:

page.get_by_role("textbox", name="E-mail").fill("[email protected]")
page.get_by_label("Senha").fill("segredo-de-teste")
page.get_by_role("button", name="Entrar").click()
page.get_by_test_id("menu-perfil").click()

get_by_role aproxima o teste da acessibilidade e evita acoplamento à estrutura do HTML. get_by_label, get_by_placeholder e get_by_text expressam a interface. data-testid é uma boa saída quando o texto varia ou não existe papel acessível. CSS ainda é válido para casos específicos, mas seletores como div:nth-child(4) > span quebram quando o layout muda.

Locators são estritos: uma ação que encontra dois elementos falha em vez de escolher silenciosamente. Restrinja o escopo com filter, get_by_role encadeado ou um contêiner significativo. Evite .first apenas para esconder ambiguidade; torne a intenção do teste inequívoca.

Esperas sem pausas arbitrárias

Antes de agir, Playwright verifica se o elemento está visível, estável, habilitado e apto a receber eventos. Esse auto-waiting elimina muitos time.sleep. Para validar o resultado, use as asserções que tentam novamente até o prazo:

from playwright.sync_api import expect

page.get_by_role("button", name="Salvar").click()
expect(page.get_by_role("status")).to_have_text("Dados salvos")
expect(page).to_have_url("**/conta")

Espere o efeito relevante, não um intervalo escolhido por tentativa. Para uma resposta específica, envolva a ação com page.expect_response; para uma nova aba, use page.expect_popup. wait_for_load_state("networkidle") não deve ser uma regra geral, pois páginas com telemetria ou conexões persistentes podem nunca ficar ociosas. A asserção sobre o estado final comunica melhor o requisito.

Timeouts globais muito altos tornam falhas lentas. Mantenha um limite razoável e ajuste somente operações realmente demoradas. Se o sistema é instável, investigue a causa em vez de acumular esperas.

Downloads e screenshots

Capture o evento de download antes do clique para não perder uma conclusão rápida:

from pathlib import Path

with page.expect_download() as info:
    page.get_by_role("link", name="Baixar relatório").click()

download = info.value
destino = Path("artifacts") / download.suggested_filename
destino.parent.mkdir(exist_ok=True)
download.save_as(destino)
assert destino.stat().st_size > 0

Em testes, prefira o diretório temporário do pytest e valide conteúdo, extensão ou cabeçalhos, não somente a existência. Nunca confie cegamente no nome sugerido para gravar arquivos em locais sensíveis.

Screenshots ajudam a diagnosticar, mas não substituem asserções. É possível capturar a página inteira, um locator ou uma imagem com animações desativadas:

page.screenshot(path="falha.png", full_page=True)
page.get_by_test_id("resumo").screenshot(path="resumo.png")

Não publique capturas com senhas, tokens, dados pessoais ou informações de clientes. Defina retenção curta para artifacts de CI e use contas com dados fictícios.

Testes com pytest

O plugin pytest-playwright fornece a fixture page e encerra os recursos. Um teste pequeno fica assim:

from playwright.sync_api import Page, expect

def test_pagina_exibe_titulo(page: Page) -> None:
    page.goto("https://example.com")
    expect(page.get_by_role("heading", name="Example Domain")).to_be_visible()

Execute com pytest --browser chromium. Configure a URL base e tracing no projeto quando houver vários testes. Cada caso deve criar seu próprio estado; autenticação reutilizável pode ser salva em storage_state, mas o arquivo contém credenciais e deve ficar fora do Git. Para organizar fixtures e parametrização, o artigo de testes automatizados com pytest aprofunda essas práticas.

Teste comportamento observável. Uma sequência enorme que cadastra, edita, exporta e exclui dados é difícil de diagnosticar. Divida cenários, prepare dados por APIs autorizadas quando possível e reserve a interface para aquilo que precisa ser comprovado pela interface.

Ética, segurança e limites

Capacidade técnica não equivale a permissão. Automatize sistemas próprios ou para os quais exista autorização clara. Leia termos de uso, respeite limites de requisição e não use Playwright para contornar CAPTCHA, bloqueios, autenticação, paywalls ou controles de acesso. Minimize dados coletados e cumpra regras de privacidade.

Use contas de teste com privilégio mínimo, segredos no gerenciador da CI e ambientes separados de produção. Se uma automação repetitiva pode sobrecarregar um serviço, aplique concorrência limitada e interrupção diante de erros. Para extração legítima de conteúdo público, avalie primeiro uma API; o guia de web scraping com Python discute escolhas e cuidados adicionais.

Controle o estado e reproduza falhas

Cada contexto do navegador é uma sessão isolada, com cookies, armazenamento local, permissões, idioma e viewport próprios. Crie um contexto novo para cenários independentes em vez de limpar estado manualmente. Quando o fluxo exigir autenticação prévia, gere o storage_state em uma preparação autorizada, proteja o arquivo resultante como credencial e limite sua validade. Não compartilhe um contexto mutável entre testes paralelos, pois navegação, diálogos e alterações de sessão podem interferir entre si.

Registre no projeto as premissas do ambiente. Fixe idioma e fuso horário quando a formatação afetar as verificações, escolha um viewport representativo e conceda somente as permissões necessárias. Simular todas as respostas pode deixar a suíte rápida, mas incapaz de detectar defeitos de integração. Reserve a interceptação de rotas para dependências controladas e cenários de erro explícitos, mantendo um conjunto menor de testes contra um ambiente realista.

O tracing do Playwright registra ações, snapshots, rede e locais no código. Ative traces em novas tentativas ou falhas, evitando guardar indefinidamente todas as execuções bem-sucedidas. A documentação oficial do Trace Viewer mostra como inspecioná-los. Trate os arquivos como sensíveis, pois podem conter texto da página, URLs, cabeçalhos e dados de sessão.

Erros comuns e checklist

  • Não use time.sleep para sincronização normal; espere um estado ou evento.
  • Não baseie seletores em classes geradas ou posição no DOM.
  • Não compartilhe página e dados mutáveis entre testes paralelos.
  • Não trate screenshot como prova funcional sem asserções.
  • Não registre credenciais, cookies ou dados pessoais em traces.
  • Instale no CI a mesma família de navegador definida no projeto.
  • Use locators por papel, rótulo ou contrato de teste.
  • Valide o conteúdo dos downloads em diretório temporário.
  • Guarde traces e imagens apenas quando necessários.
  • Confirme autorização e impacto antes de automatizar.

Uma suíte confiável combina locators semânticos, esperas orientadas a estado, testes independentes e evidências protegidas. Comece por um fluxo crítico curto, rode-o localmente e na CI, examine qualquer intermitência e só então amplie a cobertura.