---
title: "Playwright ou Selenium: qual escolher no seu projeto?"
description: "O Playwright espera os elementos sozinho e toma o proxy por contexto; o Selenium cobre mais linguagens e o Safari real. Fizemos o mesmo trabalho nos dois."
url: https://proxynet.io/pt-br/blog/playwright-vs-selenium
date: 2026-09-19
author: "Acar Diveroli"
category: "Comparativos, Web scraping"
lang: pt-BR
---

# Playwright ou Selenium: qual escolher no seu projeto?

Você começa um projeto novo de coleta de dados ou de testes e a página é montada com JavaScript, então precisa de um navegador de verdade. No time tem alguém que escreve Selenium há anos, e a desenvolvedora nova sugere o Playwright. As duas ferramentas abrem o navegador a partir do código e clicam nele, as duas são gratuitas; é justamente essa semelhança que dificulta a escolha. A maioria das comparações olha o assunto com olhos de QA e pula os tópicos que decidem o resultado na coleta de dados, como proxies e espera.

Neste artigo comparamos as duas ferramentas em sete eixos: arquitetura, espera automática, gestão de proxy, suporte a linguagens, instalação do navegador, paralelismo e depuração. O código que faz o mesmo trabalho pequeno nas duas foi executado com Playwright 1.63, Selenium 4.49 e Chrome 153 no Windows 11, e contamos o que vimos em cada seção. "Qual delas é notada menos" não é o assunto deste artigo: as duas abrem um navegador real e, nas duas, respeitar as regras do site é tarefa sua.

> **Nota: Resposta rápida**
>
> O Playwright conversa com o navegador por uma conexão permanente, espera sozinho até o elemento ficar pronto e toma o proxy com usuário e senha para cada contexto separadamente; em projetos novos você chega ao resultado com menos código. O Selenium segue o padrão W3C WebDriver, suporta mais linguagens, inclusive Ruby, e o Safari real, e se espalha entre máquinas com o Grid; se você tem uma suíte de Selenium funcionando ou um time voltado para Java e C#, quase nunca há motivo para abandoná-la. A autenticação de proxy não faz parte do padrão no Selenium, e o caminho prático é a whitelist de IP.

## O que são Playwright e Selenium?

O Selenium é um projeto de automação de navegador de código aberto desenvolvido desde 2004. A parte usada hoje é o Selenium WebDriver: seu código envia comandos a um driver de navegador, e o driver controla o navegador. A instalação está no nosso artigo [Selenium com proxy](/pt-br/blog/selenium); o download do driver e a autenticação estão explicados lá.

O Playwright é uma biblioteca de automação de navegador de código aberto que a Microsoft publicou em 2020. Ele controla os motores Chromium, Firefox e WebKit com uma única API. A instalação e os ajustes de proxy estão em [O que é Playwright e como usá-lo com proxy](/pt-br/blog/playwright-proxy); aqui tratamos apenas dos pontos em que ele se separa do Selenium.

As duas respondem à mesma necessidade: conteúdo que não chega com uma requisição HTTP simples e que só aparece quando o JavaScript roda no navegador. Se a página precisa mesmo de um navegador, você descobre com a verificação de [Páginas estáticas e dinâmicas no web scraping](/pt-br/blog/static-vs-dynamic-pages). Se o dado está no código-fonte da página, um cliente HTTP simples ou o [Scrapy](/pt-br/blog/scrapy-proxy) sai mais barato do que qualquer uma das duas.

## Qual é a diferença de arquitetura: WebDriver, BiDi e CDP

Quase toda diferença de comportamento entre as duas ferramentas nasce de como elas conversam com o navegador.

No Selenium o caminho de um comando é este:

1. Seu código chama `driver.find_element(...)`.
2. A biblioteca do Selenium transforma isso em uma requisição HTTP do padrão W3C WebDriver.
3. A requisição vai para o programa driver escrito pelo fabricante do navegador: ChromeDriver para o Chrome, GeckoDriver para o Firefox.
4. O driver aplica o comando ao navegador e devolve o resultado como resposta HTTP.

Cada comando é uma requisição e uma resposta à parte; o navegador não consegue avisar nada por conta própria. Um erro no console ou uma requisição de rede saindo em segundo plano fica invisível enquanto você não perguntar. Para fechar essa lacuna, o projeto Selenium escreve junto com os fabricantes de navegadores o padrão [WebDriver BiDi](https://www.w3.org/TR/webdriver-bidi/): um protocolo bidirecional sobre WebSocket. No Selenium 4 ele é ligado com `options.enable_bidi = True`; como a transição ainda está em curso, hoje dois mundos convivem no Selenium.

No Playwright o caminho é diferente:

1. Seu código chama `page.locator(...).click()`.
2. A biblioteca de Python, Java ou .NET passa essa chamada ao driver do Playwright embutido no pacote. O driver é um processo Node.js; no ambiente virtual ele fica como `playwright/driver/node.exe`.
3. O driver conversa com o navegador por uma conexão permanente. No Chromium isso é o Chrome DevTools Protocol (CDP). Para Firefox e WebKit, o Playwright usa as próprias compilações com patch.
4. Como a conexão é bidirecional, os eventos do navegador (requisição, resposta, mensagem de console, download) chegam ao seu código sem que você peça.

Essa escolha tem um preço. O [documento de navegadores do Playwright](https://playwright.dev/python/docs/browsers) diz com clareza: por depender de patches, ele não funciona com o Firefox e o Safari de marca. O Chrome e o Edge você usa com a opção `channel`, mas uma compilação do WebKit não atende à necessidade de "testar no Safari real"; o Selenium controla o Safari instalado com o driver da própria Apple.

## Tabela comparativa

| | Playwright | Selenium |
|---|---|---|
| Protocolo | Conexão permanente; CDP no Chromium, compilações com patch no Firefox e no WebKit | W3C WebDriver (HTTP), ao lado do WebDriver BiDi em formação (WebSocket) |
| Camada intermediária | Driver do Playwright embutido no pacote | Driver do fabricante do navegador (ChromeDriver, GeckoDriver) |
| Navegadores | Chromium, Firefox, WebKit; Chrome e Edge com `channel` | Chrome, Edge, Firefox, Safari |
| Linguagens oficiais | JavaScript e TypeScript, Python, Java, .NET | Java, Python, C#, Ruby, JavaScript |
| Espera | Automática antes das ações | Você escreve: `WebDriverWait` |
| Alcance do proxy | Por navegador ou por contexto | Por sessão de navegador |
| Usuário e senha do proxy | Campos próprios no objeto `proxy` | Não há campo no padrão; o caminho prático é a whitelist de IP |
| Escutar e bloquear requisições | Embutido (`route`, `expect_response`) | Chega com o BiDi; não existe no WebDriver clássico |
| Instalação do navegador | `playwright install`, compilações presas à versão | O Selenium Manager baixa o driver sozinho e usa o navegador instalado |
| Paralelismo | Muitos contextos em um navegador | Um navegador por tarefa; Selenium Grid entre máquinas |
| Depuração | Trace Viewer, Inspector, codegen | Captura de tela, log do navegador, Selenium IDE |

## Como escrever o mesmo trabalho nas duas ferramentas?

Nossa página de teste é `quotes.toscrape.com/js-delayed/`: um site de prática que imprime as citações com JavaScript e dez segundos de atraso. O trabalho: abrir a página por um proxy, ler as citações, clicar no link "Next" e conferir a segunda página.

Com o Playwright:

```python
from playwright.sync_api import sync_playwright

URL = "https://quotes.toscrape.com/js-delayed/"
PROXY = {
    "server": "http://pr.proxynet.io:8000",
    "username": "user",
    "password": "pass",
}

with sync_playwright() as p:
    browser = p.chromium.launch(proxy=PROXY)
    page = browser.new_page()
    page.goto(URL)
    quotes = page.locator("div.quote")
    print("immediately:", quotes.count())  # 0: count() não espera
    quotes.first.wait_for()  # espera até a primeira citação aparecer na página
    for quote in quotes.all():
        text = quote.locator("span.text").inner_text()
        author = quote.locator("small.author").inner_text()
        print(author, "-", text[:50])
    page.get_by_role("link", name="Next").click()  # espera sozinho antes do clique
    page.wait_for_url("**/page/2/")
    print(page.url)
    browser.close()
```

Com o Selenium:

```python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

URL = "https://quotes.toscrape.com/js-delayed/"

options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
# Sem usuário e senha: seu IP de saída precisa estar na whitelist do painel
options.add_argument("--proxy-server=http://pr.proxynet.io:8000")

driver = webdriver.Chrome(options=options)  # o driver é encontrado pelo Selenium Manager
try:
    driver.get(URL)
    print("immediately:", len(driver.find_elements(By.CSS_SELECTOR, "div.quote")))  # 0
    wait = WebDriverWait(driver, 15)
    quotes = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "div.quote")))
    for quote in quotes:
        text = quote.find_element(By.CSS_SELECTOR, "span.text").text
        author = quote.find_element(By.CSS_SELECTOR, "small.author").text
        print(author, "-", text[:50])
    wait.until(EC.element_to_be_clickable((By.PARTIAL_LINK_TEXT, "Next"))).click()
    wait.until(EC.url_contains("/page/2/"))
    print(driver.current_url)
finally:
    driver.quit()
```

Os dois scripts imprimiram as mesmas dez citações pelos nossos proxies de teste locais e passaram para `/js-delayed/page/2/`. O número de linhas é parecido; a diferença está no detalhe. No Playwright as credenciais do proxy ficam dentro do código, no Selenium não; o clique no Playwright é uma linha, e no Selenium a condição de o elemento estar clicável é escrita à mão. Nos dois scripts a linha "immediately" devolveu `0`: a página conta como carregada, mas o conteúdo ainda não está lá. É disso que trata a seção seguinte.

## Qual é a diferença entre a espera automática e o WebDriverWait?

Em páginas dinâmicas, a maior parte dos erros sai do tempo: o código procura um elemento que o JavaScript ainda não imprimiu. O [documento de esperas do Selenium](https://www.selenium.dev/documentation/webdriver/waits/) chama isso de condição de corrida; às vezes o navegador fica pronto primeiro e o código funciona, às vezes o código se adianta e você recebe um erro.

No Selenium a solução está na sua mão. O `driver.get()` espera o evento `load` da página, mas não sabe nada do conteúdo que o JavaScript acrescenta depois. O valor padrão da espera implícita é zero; se o elemento não está lá, o erro volta na hora. O caminho recomendado é a espera explícita: o `WebDriverWait` consulta a página até uma condição se tornar verdadeira. O documento faz mais um alerta: não use as duas juntas, porque os tempos ficam imprevisíveis.

O Playwright coloca esse mesmo trabalho dentro da ação. Segundo o [documento de actionability](https://playwright.dev/python/docs/actionability), uma chamada de `click()` espera o elemento ficar visível, a posição estável, apto a receber o clique e ativo; se as condições não forem atendidas dentro do prazo, ele lança um `TimeoutError`. Chamadas que trabalham com um único elemento, como `fill()` e `inner_text()`, também esperam o elemento aparecer.

Isso tem um limite: a espera automática vale para ações, não para contagens. No exemplo acima, `quotes.count()` devolveu `0` sem esperar. O documento da API do Playwright faz a mesma observação para `locator.all()`: ele não espera pelos elementos correspondentes, entrega o que está na página naquele momento. Se você vai ler uma lista, espere antes pelo primeiro elemento com `first.wait_for()`. É por isso que a frase "no Playwright não se escreve espera" é só meia verdade.

A segunda diferença está na referência ao elemento. No Selenium, `find_element` devolve uma referência ao nó do DOM como ele está; se a página redesenha aquele trecho, a referência envelhece e você recebe uma `StaleElementReferenceException`. No Playwright, um `locator` é uma receita resolvida de novo a cada uso, e esse erro quase não aparece. A linguagem de seletores fica com você nas duas ferramentas: [Seletor CSS ou XPath: qual usar no web scraping?](/pt-br/blog/css-selector-vs-xpath).

## Como a gestão de proxy se diferencia?

O lado do Playwright contamos no artigo irmão; aqui vai o resumo: o objeto `proxy` é passado para `launch()` ou `new_context()`, `username` e `password` são campos à parte e, em um único navegador, cada contexto pode sair por um IP diferente. Um contexto isola cookies, armazenamento e proxy. Como o navegador e a máquina continuam os mesmos, o [fingerprint do navegador](/pt-br/blog/browser-fingerprinting) não muda entre contextos; um contexto é um separador de sessões, não um dispositivo à parte.

No Selenium o proxy é uma capacidade de sessão: é entregue quando o navegador inicia e prende todas as abas daquele navegador; para outro proxy você fecha com `driver.quit()` e abre um navegador novo. O lado da autenticação falta no próprio padrão. [A definição de proxy do W3C WebDriver](https://www.w3.org/TR/webdriver2/#proxy) lista as chaves `httpProxy`, `sslProxy`, `socksProxy`, `socksVersion` e `noProxy`; não existe chave para usuário ou senha. O exemplo oficial do Selenium também mostra só o formato `<HOST:PORT>`. O padrão diz que o endereço do servidor pode carregar credenciais, mas o [documento de proxy do Chromium](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md#Proxy-credentials-in-manual-proxy-settings) escreve que o Chrome não usa credenciais embutidas nos ajustes de proxy.

Testamos aonde isso leva na prática com um proxy local que pede autenticação. Os resultados são de execuções únicas nesta máquina (Selenium 4.49, Chrome 153):

| O que testamos | O que aconteceu |
|---|---|
| `--proxy-server=http://servidor:porta`, sem credenciais | O proxy devolveu `407`. O `driver.get()` não lançou erro; a página ficou em branco e `driver.title` voltou vazio |
| `--proxy-server=http://user:pass@servidor:porta` | O Chrome abriu a página de erro `ERR_NO_SUPPORTED_PROXIES`, de novo sem exceção |
| `user:pass@servidor:porta` no objeto `Proxy` | A página abriu, mas nenhuma requisição chegou ao registro do proxy: o navegador conectou direto, com o nosso próprio IP |
| Porta que não pede autenticação (o equivalente da whitelist de IP) | Funcionou sem problema |

A terceira linha é a mais perigosa: o script parece funcionar, e o tráfego não está passando pelo proxy. Também não existe um argumento do Chrome chamado `--proxy-auth`, que aparece em artigos antigos. A chamada `add_auth_handler` do lado BiDi do Selenium é descrita na documentação para a autenticação Basic do próprio site; não é um caminho documentado para proxy, e nossa tentativa com um proxy definido terminou em tempo esgotado no carregamento da página.

Por isso o caminho que recomendamos no Selenium é a whitelist de IP: você adiciona o IP de saída do servidor onde o script roda à lista do painel e passa o valor de `--proxy-server` sem credenciais. A comparação dos dois métodos está em [Autenticação de proxy: user:pass ou whitelist de IP](/pt-br/blog/proxy-authentication-methods), e a sintaxe de proxy do SeleniumBase em [Proxy com SeleniumBase: autenticação e rotação](/pt-br/blog/how-to-use-proxy-with-seleniumbase).

Nas mesmas execuções fizemos outra observação: o Chrome instalado que o Selenium abriu conectou pelo proxy também aos serviços de atualização e de conta do Google, além do site de destino; na compilação própria de Chromium do Playwright, só as requisições da página apareceram no registro do proxy. Quando você paga o tráfego por gigabyte com [Proxies residenciais](https://proxynet.io/pt-br/residential-proxy), vale acompanhar esse tráfego de fundo pelo painel.

## Suporte a linguagens e ecossistema

As bibliotecas oficiais do Selenium são para Java, Python, C#, Ruby e JavaScript. As do Playwright, para JavaScript e TypeScript, Python, Java e .NET. Se o time é de Ruby, a escolha se faz sozinha.

Mesmo com as linguagens se sobrepondo no papel, os centros de gravidade são outros. O Selenium é um projeto de vinte anos; boa parte dos times corporativos de teste escreve Selenium em Java ou C#, existem suítes de centenas de cenários montadas com TestNG, JUnit, NUnit e Cucumber, e reescrevê-las quase sempre custa mais do que a comodidade que o Playwright traz. A face mais madura do Playwright é a do Node.js: o executor de testes próprio vem com execução paralela, comparação de capturas de tela e gravação automática de trace. Em Python o caminho recomendado é o plugin do pytest. A coleta de dados com C# está em [Extrair dados de um site com C#: HttpClient e proxy](/pt-br/blog/csharp-web-scraping).

Em scraping, a escolha da linguagem costuma vir antes da escolha da ferramenta: se a esteira que processa os dados está em Python, as duas servem; se está em Node.js, o Playwright fica mais natural. A comparação das duas linguagens está em [Extração de dados: JavaScript ou Python?](/pt-br/blog/web-scraping-javascript-vs-python).

## Instalação do navegador: Selenium Manager e playwright install

Os guias antigos de Selenium mandam baixar à mão o ChromeDriver que corresponde à sua versão do Chrome e passar o caminho com `executable_path`. As duas coisas ficaram para trás: no Selenium 4.49, `webdriver.Chrome()` aceita apenas os parâmetros `options`, `service` e `keep_alive`, e encontrar o driver é trabalho do [Selenium Manager](https://www.selenium.dev/documentation/selenium_manager/) desde a versão 4.6, entregue junto com a biblioteca: ele detecta a versão do navegador instalado, baixa o driver correspondente e guarda na pasta `~/.cache/selenium`. No nosso teste ele baixou o ChromeDriver 153 para o Chrome 153 instalado sem nenhum passo extra. Segundo o documento, ele também pode baixar Chrome, Firefox e Edge se o navegador não estiver instalado; a ferramenta continua versionada como beta.

A abordagem do Playwright é o contrário: ele não confia no navegador do sistema. O `playwright install chromium` baixa a compilação própria, e cada versão do Playwright fica presa a uma compilação específica do navegador. Se você atualiza a biblioteca e esquece de rodar o `install` de novo, recebe o erro "Executable doesn't exist"; aconteceu conosco nos testes deste artigo.

A troca é esta: o Selenium dirige o navegador que os seus usuários realmente usam e que se atualiza sozinho, o que faz sentido para teste, mas o comportamento pode mudar quando o navegador é atualizado. No Playwright a versão do navegador fica travada com o código; a atualização você escolhe.

## Trabalho paralelo: Grid ou contexto?

No Playwright a unidade do paralelismo é o contexto. Um processo de navegador é aberto e cada tarefa toma o próprio contexto e, se quiser, o próprio proxy:

```python
import asyncio

from playwright.async_api import async_playwright

URLS = [f"https://quotes.toscrape.com/js/page/{n}/" for n in range(1, 4)]
PROXY = {"server": "http://pr.proxynet.io:8000", "username": "user", "password": "pass"}

async def scrape(browser, url):
    context = await browser.new_context(proxy=PROXY)  # sessão isolada com proxy próprio
    try:
        page = await context.new_page()
        await page.goto(url)
        quotes = page.locator("div.quote span.text")
        await quotes.first.wait_for()
        return url, await quotes.count()
    finally:
        await context.close()

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch()  # um único processo de navegador
        for url, count in await asyncio.gather(*(scrape(browser, u) for u in URLS)):
            print(url, count)
        await browser.close()

asyncio.run(main())
```

No Selenium a unidade é o próprio navegador. O mesmo trabalho é escrito com um pool de threads que abre um driver por tarefa:

```python
from concurrent.futures import ThreadPoolExecutor

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

URLS = [f"https://quotes.toscrape.com/js/page/{n}/" for n in range(1, 4)]

def scrape(url):
    options = webdriver.ChromeOptions()
    options.add_argument("--headless=new")
    options.add_argument("--proxy-server=http://pr.proxynet.io:8000")  # com whitelist de IP
    driver = webdriver.Chrome(options=options)  # um processo de navegador por tarefa
    try:
        driver.get(url)
        quotes = WebDriverWait(driver, 15).until(
            EC.presence_of_all_elements_located((By.CSS_SELECTOR, "div.quote span.text"))
        )
        return url, len(quotes)
    finally:
        driver.quit()

with ThreadPoolExecutor(max_workers=3) as pool:
    for url, count in pool.map(scrape, URLS):
        print(url, count)
```

Os dois scripts devolveram dez citações de cada uma das três páginas. A diferença está no consumo de recursos: no primeiro abre um navegador, no segundo três navegadores e três processos de driver. Com vinte sessões simultâneas essa diferença cai direto na memória. Quando a concorrência e o paralelismo ajudam no scraping está em [Concorrência e paralelismo no web scraping](/pt-br/blog/concurrency-vs-parallelism).

Onde o Selenium é forte é na distribuição entre máquinas. O Selenium Grid encaminha comandos para navegadores em máquinas remotas; segundo o documento oficial, o objetivo é rodar testes em paralelo em mais de uma máquina. Rodar a matriz "Edge no Windows, Safari no macOS, Firefox no Linux" a partir de uma única suíte é trabalho do Grid. O Playwright não tem equivalente direto: a distribuição entre máquinas fica a cargo do seu sistema de CI. A capacidade de conectar ao Grid está marcada como experimental na documentação e cobre só os navegadores baseados em Chromium.

## Ferramentas de depuração

Neste tópico o Playwright está claramente à frente. Uma gravação que começa com `context.tracing.start(screenshots=True, snapshots=True)` e termina com `tracing.stop(path="trace.zip")` abre com o comando `playwright show-trace trace.zip`: a visão do DOM antes e depois de cada ação, as requisições de rede e as mensagens de console ficam em uma linha do tempo. Por que uma varredura que rodou de madrugada voltou vazia, você responde de manhã por esse arquivo. O `PWDEBUG=1` abre o Inspector e percorre o script passo a passo, e o `playwright codegen` transforma em código o que você faz no navegador.

No Selenium não existe uma ferramenta equivalente única. Com `driver.save_screenshot()` você tira uma captura e, no Chrome, liga a capacidade `goog:loggingPrefs` e lê as mensagens de console com `driver.get_log("browser")`; testamos os dois e funcionam. A necessidade de gravar e reproduzir é atendida pela extensão Selenium IDE. Escutar as requisições de rede ao vivo chega com o BiDi, mas para um registro que você percorre depois vai se apoiar em frameworks de relatório.

## Velocidade: por que não damos números?

A maior parte das comparações na internet carrega uma porcentagem do tipo "o Playwright é tanto mais rápido"; esses números foram tirados na máquina do autor, na página do autor. A arquitetura cria uma expectativa a favor do Playwright: uma conexão aberta em vez de uma requisição HTTP por comando, um contexto em vez de um navegador. Mas em uma varredura real que passa por um proxy, a maior parte do tempo vai para a rede e para o tempo de resposta do site de destino; no nosso exemplo os dois scripts terminaram à sombra dos dez segundos de atraso da página.

Se for medir, meça no seu próprio destino, com o mesmo proxy e a mesma concorrência, com uma amostra de algumas dezenas de páginas. Na maioria dos projetos o ganho real não vem de trocar de ferramenta, e sim de não abrir o navegador sem necessidade.

## Casos de uso

- **Coletar dados de páginas dinâmicas:** em um projeto novo, escutar requisições e bloquear recursos no Playwright reduz o tráfego; o desenho geral está na página de [solução de extração de dados](/pt-br/data-scraping).
- **Varrer muitas páginas com regularidade:** a lógica de fila e descoberta não depende da ferramenta; veja a página de [solução de web crawler](/pt-br/web-crawler) e o artigo [O que é paginação e como varrer no scraping](/pt-br/blog/pagination-web-scraping).
- **Testar seu aplicativo a partir de países diferentes:** no Playwright um contexto por país, no Selenium uma sessão por país; o detalhe está na página de [teste de aplicativos](/pt-br/app-testing).
- **Teste de compatibilidade entre navegadores:** se precisa do Safari real e de uma matriz de sistemas operacionais, Selenium e Grid.
- **Varredura em massa de páginas independentes:** nas duas ferramentas basta um único endereço de gateway com [Proxies rotativos](https://proxynet.io/pt-br/rotating-proxy); a rotação é feita pelo gateway.

Seja qual for a ferramenta, o enquadramento não muda: siga as regras do `robots.txt` e os termos de uso, use a API oficial quando ela existir e mantenha o ritmo de requisições num nível que o site aguente. O detalhe está em [O que é robots.txt e como ler o arquivo?](/pt-br/blog/robots-txt).

## Erros comuns

- **Embutir as credenciais no endereço do proxy no Selenium.** O Chrome não usa; no nosso teste o resultado foi ou uma página de erro ou uma conexão direta sem proxy.
- **Supor que a página abriu porque o `driver.get()` não deu erro.** O Selenium não entrega o código de status; confira o elemento esperado e o IP de saída.
- **Achar que `count()` ou `all()` vão esperar no Playwright.** Não esperam; primeiro `first.wait_for()`.
- **Resolver a espera com `time.sleep()`.** É lento e frágil ao mesmo tempo; use `WebDriverWait` no Selenium e a espera do locator no Playwright.
- **Misturar espera implícita e explícita no Selenium.** O documento oficial avisa: os tempos ficam imprevisíveis.
- **Não chamar `driver.quit()` no Selenium.** Cada sessão deixada aberta deixa um processo do Chrome e um do driver; use `try/finally`.
- **Migrar uma suíte de Selenium que funciona só por modismo.** O custo da migração não está nos seletores, e sim na lógica de espera e na infraestrutura de testes.
- **Atualizar o Playwright e não atualizar os navegadores.** Cada versão quer a compilação dela; acrescente um passo `playwright install` à imagem de CI.

## Guia de decisão

| Necessidade | Recomendação |
|---|---|
| Projeto de scraping começando, em Python ou Node.js | Playwright |
| Proxy que funciona com usuário e senha | Playwright; no Selenium passe para a whitelist de IP |
| Dezenas de sessões independentes em uma máquina, um IP por sessão | Playwright, proxy por contexto |
| Suíte de testes de Selenium em uso e mantida | Fique no Selenium |
| Time corporativo de teste voltado para Java ou C# | As duas servem; decidem o framework existente e a experiência |
| Ruby | Selenium |
| Teste no Safari real e em sistemas operacionais diferentes | Selenium e Grid |
| Depuração posterior em trabalhos que rodam de madrugada | Playwright, Trace Viewer |
| Ler a resposta de rede, bloquear imagens e fontes | Playwright (embutido) |
| Dado no código-fonte da página ou em um endpoint JSON | Nenhuma das duas: cliente HTTP simples ou Scrapy |

## Perguntas frequentes

### O Playwright substitui o Selenium?

Em projetos novos ele é muitas vezes a primeira escolha, mas dizer que substituiu não seria correto. O Selenium é a implementação de referência de um padrão do W3C, os drivers dele são escritos pelos fabricantes de navegadores, e a comunicação bidirecional que faltava está sendo acrescentada pela via do padrão com o WebDriver BiDi. Os dois projetos são desenvolvidos de forma ativa.

### É difícil sair do Selenium para o Playwright?

Os seletores em boa parte se aproveitam; CSS e XPath funcionam nos dois. A parte que dá trabalho é a lógica de espera: os blocos de `WebDriverWait` somem e no lugar entra um fluxo baseado em locators; do lado de testes, os page objects, o relatório e os passos de CI também são remontados. Um script pequeno migra em um dia; em uma suíte de centenas de cenários é menos arriscado escrever primeiro os cenários novos no Playwright e deixar os antigos onde estão.

### As duas podem ser usadas no mesmo projeto?

Sim, uma não atrapalha a outra. O arranjo comum é manter a suíte de regressão do Selenium e escrever o trabalho novo no Playwright. O ponto de atenção é gerenciar juntos dois modelos de instalação de navegador na imagem de CI.

### No Selenium nunca dá para usar proxy com usuário e senha?

Pelo caminho padrão não: a definição de proxy do WebDriver não tem campo de credenciais, e o Chrome não usa as credenciais embutidas no endereço. Pacotes de terceiros que colocam no meio um proxy local de encaminhamento preenchem essa lacuna, mas trazem uma dependência a mais. Se você roda a partir de um servidor com IP fixo, a whitelist de IP é mais simples e mais segura; a senha não aparece no código.

### O Selenium em Python é mais lento que o Playwright?

Não há resposta geral. A arquitetura favorece o Playwright, mas em uma varredura por proxy o tempo é decidido na maior parte pela rede e pelo site de destino. Não transfira porcentagens publicadas para o seu trabalho; meça você mesmo no mesmo destino, com o mesmo proxy e a mesma concorrência.

### As duas se comportam de outro jeito no modo headless?

As duas rodam sem janela. O Playwright abre headless por padrão e baixa para isso uma compilação separada, a "headless shell"; para ver a janela você escreve `launch(headless=False)`. O Selenium abre com janela por padrão e passa ao modo sem janela no Chrome com o argumento `--headless=new`. O ajuste de proxy é o mesmo nos dois modos.

## Em resumo

O Playwright e o Selenium fazem o mesmo trabalho por caminhos diferentes. O Selenium envia os comandos por W3C WebDriver ao driver do fabricante do navegador; cobre mais linguagens, o Safari real e a distribuição entre máquinas com o Grid, e deixa a espera e as credenciais de proxy com você. O Playwright estabelece uma conexão permanente com o navegador; espera sozinho, toma o proxy com usuário e senha por contexto, escuta o tráfego de rede e facilita a depuração com um arquivo de trace. Em um projeto novo de scraping o Playwright faz você avançar com menos código; se já tem uma suíte de Selenium funcionando, quase sempre basta ligá-la ao proxy com uma whitelist de IP. Os tipos de proxy que dá para usar com as duas ferramentas estão nos nossos [serviços de proxy](/pt-br/proxy).
