---
title: "O que é Playwright e como usá-lo com proxy"
description: "No Playwright, o proxy é definido ao iniciar o navegador ou por contexto. Explicamos autenticação, SOCKS5 e rotação com exemplos em Python e Node.js."
url: https://proxynet.io/pt-br/blog/playwright-proxy
date: 2026-09-19
author: "Acar Diveroli"
category: "Tutoriais, Web scraping"
lang: pt-BR
---

# O que é Playwright e como usá-lo com proxy

Você está coletando dados de uma loja que carrega os preços com JavaScript. O HTML que chega com Requests vem vazio, então você passa para o Playwright e a página abre sem problemas. Quando o trabalho cresce, é preciso passar o tráfego por um proxy, e a primeira tentativa termina com `net::ERR_TUNNEL_CONNECTION_FAILED` ou com "Browser does not support socks5 proxy authentication". A maioria dos tutoriais apresenta o Playwright como ferramenta de automação de testes, por isso a parte do proxy costuma ser montada a partir de tópicos de fórum e de issues no GitHub.

Neste artigo definimos rapidamente o que é o Playwright, mostramos a instalação em Python e em Node.js lado a lado e depois passamos ao proxy: a diferença entre proxy no nível do navegador e no nível do contexto, a autenticação com usuário e senha, o comportamento do Chromium com SOCKS5, a escolha entre rotativo e sticky, a economia de tráfego ao cortar as requisições de imagens e fontes, a verificação do IP e uma tabela de erros. Executamos todos os exemplos do artigo com Playwright 1.63 e Chromium, por meio de um proxy local de teste com autenticação.

> **Nota: Resposta rápida**
>
> O Playwright é uma biblioteca de código aberto para automação de navegadores que controla Chromium, Firefox e WebKit a partir do código. O proxy é definido com o objeto `proxy` passado à chamada `launch()` ou à chamada `new_context()`: `server`, `username` e `password` são campos separados. A primeira passa o navegador inteiro pelo proxy e a segunda apenas aquele contexto, de modo que, em um único navegador, cada contexto pode sair por um IP diferente. Com SOCKS5 não há suporte a usuário e senha; usa-se a whitelist de IP.

## O que é o Playwright?

O Playwright é uma biblioteca de código aberto para automação de navegadores desenvolvida pela Microsoft. Ele abre um navegador real a partir do código, vai até um endereço, clica, preenche formulários e lê os elementos da página. Controla os motores Chromium, Firefox e WebKit com a mesma API e tem versões oficiais para Node.js, Python, Java e .NET.

A ferramenta nasceu para testes de ponta a ponta, e a maioria dos guias a apresenta por esse lado. Para equipes de dados, o valor está em outro lugar: ela executa em um navegador real a página gerada com JavaScript, espera sozinha até que um elemento apareça e permite ouvir as chamadas de API que a página faz em segundo plano e cortar as requisições desnecessárias. Para saber se uma página realmente precisa de um navegador, consulte antes o nosso artigo [Páginas estáticas e dinâmicas no web scraping](/pt-br/blog/static-vs-dynamic-pages); se os dados estão no código-fonte da página ou em um endpoint JSON, abrir um navegador é um custo desnecessário.

Os trabalhos feitos com o Playwright se agrupam, em linhas gerais, em quatro frentes:

- Coletar dados de páginas dinâmicas (lista de produtos, preço, estoque, número de avaliações).
- Testar como o seu próprio site ou aplicativo aparece em diferentes países.
- Gerar capturas de tela e PDF.
- Fazer agentes de IA usarem um navegador. Os detalhes deste último ponto estão no nosso artigo sobre [o Playwright MCP, sua instalação e as configurações de proxy](/pt-br/blog/playwright-mcp).

As diferenças de arquitetura em relação ao Selenium e qual escolher em cada projeto são assunto de um artigo à parte: [diferenças entre Playwright e Selenium](/pt-br/blog/playwright-vs-selenium).

## Como instalar o Playwright?

A instalação tem dois passos: primeiro a biblioteca, depois os binários dos navegadores. O Playwright não usa o Chrome instalado no sistema, e sim navegadores que ele mesmo baixa e cuja versão ele fixa. O erro "instalei a biblioteca, mas o navegador não foi encontrado" acontece quando o segundo passo é pulado.

Em Python, crie um ambiente virtual e instale a biblioteca. A [documentação oficial da biblioteca Python](https://playwright.dev/python/docs/library) traz os mesmos passos também para poetry e uv.

```bash
python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install playwright
playwright install chromium
```

Em Node.js:

```bash
npm init -y
npm install playwright
npx playwright install chromium
```

Se você não informar um navegador ao comando `install`, os três motores são baixados. Em trabalhos de scraping, o Chromium costuma bastar. Se for escrever testes, recomenda-se o pacote `pytest-playwright` em Python e `@playwright/test` em Node.js; para coleta de dados, a instalação simples da biblioteca mostrada acima é suficiente.

Em Python há duas APIs: `sync_api` e `async_api`. Em scripts que abrem páginas uma a uma, a versão síncrona é mais legível. Se for processar várias páginas ao mesmo tempo, use a versão baseada em `asyncio`; o exemplo completo no fim do artigo foi escrito assim.

## Como definir um proxy no Playwright?

A [seção HTTP Proxy da documentação de rede do Playwright](https://playwright.dev/python/docs/network#http-proxy) define dois níveis: o proxy é informado para o navegador inteiro ou separadamente para cada contexto. Nos dois casos usa-se o mesmo objeto:

| Campo | Obrigatório? | Significado |
|---|---|---|
| `server` | Sim | `http://pr.proxynet.io:8000` ou `socks5://host:porta`. Sem o esquema, é tratado como proxy HTTP |
| `username` | Não | Usuário para a autenticação do proxy HTTP |
| `password` | Não | Senha para a autenticação do proxy HTTP |
| `bypass` | Não | Domínios que não passam pelo proxy, separados por vírgula (`.exemplo.com, api.suaempresa.com`) |

Em Python, a definição no nível do navegador fica assim:

```python
from playwright.sync_api import sync_playwright

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("https://httpbin.org/ip")
    print(page.inner_text("body"))  # IP de saída do proxy
    browser.close()
```

O equivalente em Node.js:

```js
import { chromium } from "playwright";

const browser = await chromium.launch({
  proxy: {
    server: "http://pr.proxynet.io:8000",
    username: "user",
    password: "pass",
  },
});
const page = await browser.newPage();
await page.goto("https://httpbin.org/ip");
console.log(await page.innerText("body")); // IP de saída do proxy
await browser.close();
```

O ponto de atenção é o lugar das credenciais. Escrever `http://user:pass@pr.proxynet.io:8000` por hábito do cURL ou do Requests não funciona aqui: o Playwright aproveita do valor `server` apenas o esquema, o host e a porta, e não repassa ao navegador o usuário e a senha embutidos no endereço. As credenciais vão sempre nos campos `username` e `password`. Há uma vantagem adicional: se a senha tiver caracteres como `@` ou `:`, você não precisa se preocupar com a codificação de URL. A lógica geral dos dois métodos está em [Autenticação de proxy: user:pass ou whitelist de IP](/pt-br/blog/proxy-authentication-methods).

## Qual a diferença entre proxy no nível do navegador e no nível do contexto?

No Playwright, um contexto é uma sessão de navegador isolada das demais: tem seus próprios cookies, seu próprio cache e seu próprio armazenamento local. Lembra uma janela anônima, mas dezenas deles podem ficar abertos ao mesmo tempo em um único processo de navegador, e abrir um contexto custa muito menos do que iniciar um navegador novo.

Quando você passa o proxy à chamada `new_context()` em vez de `launch()`, a configuração vale apenas para aquele contexto:

```python
from playwright.sync_api import sync_playwright

PROXIES = [
    {"server": "http://pr.proxynet.io:8000", "username": "user", "password": "pass"},
    {"server": "http://pr.proxynet.io:8001", "username": "user", "password": "pass"},
]

with sync_playwright() as p:
    browser = p.chromium.launch()  # o navegador abre uma vez, sem proxy
    for proxy in PROXIES:
        context = browser.new_context(proxy=proxy)  # cada contexto com o seu próprio proxy
        page = context.new_page()
        page.goto("https://httpbin.org/ip")
        print(proxy["server"], page.inner_text("body"))
        context.close()  # cookies e cache são apagados junto com o contexto
    browser.close()
```

Ao executar este exemplo com dois proxies locais diferentes, a requisição de cada contexto ficou registrada no log do seu próprio proxy, e um terceiro contexto sem proxy se conectou diretamente. Guias antigos dizem que, no Windows, para o Chromium, é preciso escrever na chamada `launch()` um proxy de preenchimento como `http://per-context`. Era uma limitação de versões antigas do Playwright e [foi removida do código em agosto de 2024](https://github.com/microsoft/playwright/pull/31724); a documentação atual também já não traz essa nota. Com o Playwright 1.63 no Windows 11, o exemplo funcionou sem proxy de preenchimento.

| | Nível do navegador (`launch`) | Nível do contexto (`new_context`) |
|---|---|---|
| Alcance | Todos os contextos e páginas | Apenas aquele contexto |
| IPs diferentes em um só navegador | Não | Sim, um proxy por contexto |
| Para trocar de proxy | Você fecha o navegador e abre de novo | Você fecha o contexto e abre outro |
| Cookies e sessão | Os contextos continuam separados | São isolados junto com o proxy |
| Indicado para | Scripts e testes para os quais basta um ponto de saída | Muitas sessões independentes, comparação entre países |

A regra prática é esta: uma sessão, um contexto, um IP. Não há como trocar o proxy dentro do mesmo contexto, e é bom que seja assim; uma sessão cujos cookies permanecem enquanto o IP muda é, para o site de destino, um visitante incoerente.

## O Playwright funciona com proxy SOCKS5?

Funciona, mas sem usuário e senha. Se você informar em `server` um endereço com o esquema `socks5://` e acrescentar `username`, o Playwright devolve este erro sem nem iniciar o navegador:

```text
BrowserType.launch: Browser does not support socks5 proxy authentication
```

A mesma verificação vale para `new_context()`. A causa é o próprio Chromium: [a documentação de proxy do Chromium](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md#SOCKSv5-proxy-scheme) afirma de forma expressa que nenhum método de autenticação é suportado para SOCKSv5. Testamos isso no dia da redação com um servidor SOCKS5 local. O único método que o Chromium ofereceu na mensagem de negociação foi `0x00`, ou seja, "sem autenticação"; o método de usuário e senha (`0x02`) da [RFC 1929](https://www.rfc-editor.org/rfc/rfc1929) não estava na lista. Embutir as credenciais no endereço (`socks5://user:pass@...`) também não mudou o resultado: o Playwright descartou essa parte e, como o servidor exigia autenticação, a conexão foi encerrada com `net::ERR_SOCKS_CONNECTION_FAILED`. Em um servidor SOCKS5 que não pedia autenticação, a página abriu sem problemas.

A solução é comprovar a sua identidade com o endereço IP, e não com senha. Você adiciona o IP de saída do servidor onde o script roda à whitelist de IP no painel do proxy e informa apenas o campo `server`:

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    # Sem usuário nem senha: o seu IP de saída precisa estar na whitelist de IP do painel
    browser = p.chromium.launch(proxy={"server": "socks5://pr.proxynet.io:1080"})
    page = browser.new_page()
    page.goto("https://httpbin.org/ip")
    print(page.inner_text("body"))
    browser.close()
```

Nos nossos registros de teste, o Chromium enviou ao servidor SOCKS5 o nome de domínio, e não um endereço IP; ou seja, a resolução de DNS é feita do lado do proxy, e a distinção `socks5h://` conhecida do cURL não é necessária aqui. Para abrir páginas, um proxy HTTP quase sempre basta, porque o tráfego HTTPS já viaja por um túnel `CONNECT`. Quando vale a pena preferir SOCKS5 está explicado em [Diferença entre SOCKS e HTTP proxy: qual escolher?](/pt-br/blog/socks-vs-http-proxy); o produto está na página de [Proxies SOCKS5](https://proxynet.io/pt-br/socks5-proxy).

## Rotativo ou sticky: qual para cada trabalho?

Um navegador não se comporta como um script que envia uma única requisição HTTP. Enquanto uma página carrega, são abertas conexões separadas com domínios diferentes para o documento principal, os scripts, as folhas de estilo, as imagens e as chamadas de API. Em um gateway que troca o IP de saída a cada conexão, essas conexões podem sair por IPs diferentes. Ao varrer páginas independentes entre si, isso não é um problema. Já em fluxos com login, carrinho ou formulário de várias etapas, a troca de IP no meio da sessão pode levar o site a encerrá-la.

- **Páginas independentes** (lista de produtos, categoria, resultado de busca): [Proxies rotativos](https://proxynet.io/pt-br/rotating-proxy) é adequado. A rotação é feita pelo gateway, e você não mantém uma lista de proxies no código. Como a rotação funciona está no nosso artigo sobre [rotação de IP](/pt-br/blog/ip-rotation-explained).
- **Fluxos que exigem sessão** (login com a sua própria conta, operação de várias etapas): com [Proxies de sessão fixa](https://proxynet.io/pt-br/sticky-proxy), o mesmo IP é mantido durante toda a vida do contexto. Você obtém os dados da sessão sticky no painel e os escreve no campo `proxy` do contexto.
- **Conteúdo que muda conforme o país**: você abre um contexto por país e informa o ponto de saída daquele país; um único navegador, comparação lado a lado.

Dar um proxy por contexto já é, por si só, um esquema de rotação: ao fechar o contexto e abrir outro, os cookies e o IP se renovam juntos.

## Como reduzir o tráfego bloqueando imagens e fontes?

O tráfego de [Proxies residenciais](https://proxynet.io/pt-br/residential-proxy) é cobrado por GB, e um navegador baixa tudo o que um cliente HTTP simples não baixa: imagens de produto, fontes web, vídeos. Se o que você precisa é o preço e o título, não faz sentido pagar por esses bytes. O mecanismo `route` do Playwright intercepta a requisição antes que ela saia para a rede, e você pode cancelá-la conforme o tipo de recurso.

```python
from playwright.sync_api import sync_playwright

BLOCKED = {"image", "media", "font"}

def filter_resources(route):
    if route.request.resource_type in BLOCKED:
        route.abort()
    else:
        route.continue_()

with sync_playwright() as p:
    browser = p.chromium.launch(proxy={
        "server": "http://pr.proxynet.io:8000",
        "username": "user",
        "password": "pass",
    })
    page = browser.new_page()
    page.route("**/*", filter_resources)
    page.goto("https://books.toscrape.com/")
    print(page.locator("article.product_pod h3 a").first.get_attribute("title"))
    browser.close()
```

O tamanho do ganho varia conforme a página; dar um percentual geral seria enganoso. Para medir no seu próprio destino, abra a mesma página com filtro e sem filtro e compare o contador de tráfego no painel do proxy. Dois avisos: bloquear as folhas de estilo (`stylesheet`) e os scripts (`script`) pode impedir que a página gere o seu conteúdo, então limite a lista a imagens, mídia e fontes. Esta técnica é um método de economia; ela não é usada para remover os scripts de proteção de um site.

A economia maior costuma estar dentro do tráfego que o navegador escuta. Páginas dinâmicas geralmente buscam os dados em um endpoint JSON, e o Playwright permite ler essa resposta diretamente:

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(proxy={
        "server": "http://pr.proxynet.io:8000",
        "username": "user",
        "password": "pass",
    })
    page = browser.new_page()
    with page.expect_response("**/api/quotes?page=1") as info:
        page.goto("https://quotes.toscrape.com/scroll")
    data = info.value.json()
    for quote in data["quotes"][:3]:
        print(quote["author"]["name"], "-", quote["text"][:60])
    browser.close()
```

Em vez de analisar o HTML com seletores, você recebe dados estruturados. Se o endpoint não exigir credenciais, o passo seguinte pode ser abandonar o navegador por completo e chamar esse endereço com um cliente HTTP simples.

## Como verificar se o proxy está funcionando?

Três verificações bastam:

1. Abra `https://httpbin.org/ip` com o Playwright e compare o IP retornado com o seu. Se for diferente, o tráfego está passando pelo proxy.
2. Abra o mesmo endereço com um contexto sem proxy. Se os dois resultados forem iguais, o objeto `proxy` foi passado à chamada errada ou o domínio entrou na lista `bypass`.
3. Se o seu alvo é um país, confira a localização do IP em um serviço de geolocalização. Por que os bancos de dados divergem entre si está explicado em [Por que meu IP mostra outra localização? O que ele revela](/pt-br/blog/ip-geolocation-accuracy).

Testar o proxy fora do Playwright mostra se o problema está no código ou na rede. Os testes pela linha de comando estão em [Seu proxy está funcionando? Como testar um proxy](/pt-br/blog/how-to-test-a-proxy).

## Exemplo completo: contextos simultâneos, novas tentativas e bloqueio de recursos

O script abaixo varre seis páginas geradas com JavaScript. Ele mantém no máximo três contextos abertos ao mesmo tempo, usa um contexto e uma conexão de proxy limpos a cada tentativa, bloqueia imagens e fontes e tenta de novo, nos erros transitórios, com espera exponencial e um componente aleatório. Nos erros que indicam que o proxy não foi alcançado, ele não tenta de novo, porque o que resolve essa situação não é esperar, e sim corrigir a configuração.

```python
import asyncio
import random

from playwright.async_api import Error, async_playwright

PROXY = {
    "server": "http://pr.proxynet.io:8000",
    "username": "user",
    "password": "pass",
}
URLS = [f"https://quotes.toscrape.com/js/page/{n}/" for n in range(1, 7)]
BLOCKED = {"image", "media", "font"}
CONCURRENCY = 3  # contextos abertos ao mesmo tempo
ATTEMPTS = 3
# Erros em que tentar de novo não muda o resultado: primeiro corrija a configuração
FATAL = ("ERR_PROXY_CONNECTION_FAILED", "ERR_TUNNEL_CONNECTION_FAILED", "ERR_SOCKS_CONNECTION_FAILED")

async def filter_resources(route):
    if route.request.resource_type in BLOCKED:
        await route.abort()
    else:
        await route.continue_()

async def scrape(browser, url, limit):
    async with limit:
        for attempt in range(ATTEMPTS):
            context = await browser.new_context(proxy=PROXY)  # sessão limpa a cada tentativa
            try:
                page = await context.new_page()
                await page.route("**/*", filter_resources)
                response = await page.goto(url, timeout=30_000)
                if response is None or response.status >= 400:
                    raise Error(f"HTTP {response.status if response else 'sem resposta'}")
                quotes = page.locator("div.quote span.text")
                await quotes.first.wait_for(timeout=10_000)  # espera o JavaScript gerar o conteúdo
                return url, await quotes.all_inner_texts()
            except Error as exc:  # TimeoutError também deriva de Error
                if any(code in str(exc) for code in FATAL):
                    raise
                if attempt == ATTEMPTS - 1:
                    raise
                await asyncio.sleep(2**attempt + random.random())
            finally:
                await context.close()

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        limit = asyncio.Semaphore(CONCURRENCY)
        results = await asyncio.gather(
            *(scrape(browser, url, limit) for url in URLS), return_exceptions=True
        )
        await browser.close()
    for url, result in zip(URLS, results):
        if isinstance(result, Exception):
            print(url, "ERRO:", str(result).splitlines()[0])
        else:
            print(url, len(result[1]), "citações")

asyncio.run(main())
```

No nosso proxy local de teste, as seis páginas voltaram com dez citações cada; quando escrevemos a porta do proxy errada de propósito, o script parou com `ERR_PROXY_CONNECTION_FAILED` sem tentar de novo. Em um trabalho real, faça dois acréscimos. A lógica de nova tentativa que respeita o cabeçalho `Retry-After` nas respostas `429` e `503` está no exemplo de [Códigos de status HTTP no web scraping: 403, 407, 429, 503](/pt-br/blog/http-status-codes-web-scraping); não a repetimos aqui. Ajuste também a concorrência à memória: cada contexto e cada página consomem memória, então comece com um valor baixo em `CONCURRENCY` e aumente enquanto observa o seu servidor. O detalhe das estratégias de espera (por que se espera um elemento, e não `networkidle`) está no artigo sobre páginas estáticas e dinâmicas citado acima.

## Tabela de erros: ERR_PROXY_CONNECTION_FAILED, ERR_TUNNEL_CONNECTION_FAILED, 407

Provocamos de propósito cada uma das linhas abaixo no proxy local de teste.

| O que você vê | O que significa | O que fazer |
|---|---|---|
| `net::ERR_PROXY_CONNECTION_FAILED` | Não foi possível abrir a conexão TCP com o servidor proxy: endereço ou porta errados, ou um firewall está cortando a saída | Confira o valor de `server` e a porta, teste o mesmo endereço com cURL |
| `net::ERR_TUNNEL_CONNECTION_FAILED` | O proxy foi alcançado, mas a requisição `CONNECT` recebeu uma resposta diferente de `200`: a autenticação foi recusada (`407`) ou o proxy não chegou ao destino (`502`) | Confira primeiro as credenciais, depois o endereço de destino |
| Tempo esgotado no `goto` em endereço HTTPS, `407` no log do proxy | Usuário ou senha errados, ou não informados. No nosso teste, o evento `requestfailed` informou `ERR_TUNNEL_CONNECTION_FAILED`, mas o `goto` esperou até o tempo esgotar em vez de lançar um erro | Veja o erro real com `page.on("requestfailed")` e corrija os campos `username` e `password` |
| Código de resposta `407` em endereço HTTP (sem criptografia) | A mesma causa; como não há túnel, a resposta do proxy chega como resposta da página | Confira `response.status` e corrija as credenciais |
| `Browser does not support socks5 proxy authentication` | `username` foi informado junto com um endereço `socks5://` | Remova as credenciais e use a whitelist de IP, ou passe para um proxy HTTP |
| `net::ERR_SOCKS_CONNECTION_FAILED` | O servidor SOCKS5 exige autenticação ou o seu IP não está na whitelist | Adicione o seu IP de saída à lista no painel |
| A página abre, mas o IP é o seu | O objeto `proxy` não chegou a ser aplicado ou o domínio está na lista `bypass` | Confirme que você passou o objeto à chamada `launch` ou `new_context` |

A terceira linha é a que mais faz perder tempo: o script não dá erro, apenas espera trinta segundos até o tempo esgotar, e o problema é atribuído à lentidão do site de destino. Acrescentar estas duas linhas durante o desenvolvimento encurta o diagnóstico:

```python
page.on("requestfailed", lambda r: print("FALHOU:", r.url, r.failure))
page.on("response", lambda r: print(r.status, r.url) if r.status >= 400 else None)
```

O significado geral do código `407` e como ele aparece em outras bibliotecas está no nosso artigo sobre códigos de status HTTP; para erros do tipo "o servidor proxy não está respondendo" fora da automação de navegadores, consulte o nosso artigo sobre [erros de proxy e a mensagem "o servidor proxy não está respondendo"](/pt-br/blog/proxy-server-not-responding).

## Casos de uso

- **Páginas dinâmicas de lojas e catálogos:** dados de preço e estoque carregados com JavaScript. A visão geral está na nossa página de [solução de extração de dados](/pt-br/data-scraping).
- **Varredura periódica de muitas páginas:** a descoberta de páginas e o gerenciamento de filas estão na página de [solução de web crawler](/pt-br/web-crawler); os padrões de paginação, no nosso artigo sobre [paginação no web scraping](/pt-br/blog/pagination-web-scraping).
- **Testes do seu aplicativo a partir de diferentes países:** um contexto por país, cada um com o ponto de saída daquele país. Os detalhes estão na página de [testes de aplicativos](/pt-br/app-testing).
- **Monitoramento de preços da concorrência:** uma varredura diária, com bloqueio de recursos e que respeita os limites de taxa. O lado de negócio está no nosso artigo sobre [monitoramento de preços da concorrência no e-commerce](/pt-br/blog/competitor-price-tracking).

Seja qual for o trabalho, a moldura é a mesma: respeite as regras do `robots.txt` e os termos de uso do site, prefira a API oficial se ela existir e mantenha o ritmo de requisições em um nível que o site suporte. Como ler um arquivo `robots.txt` está em [O que é robots.txt e como ler o arquivo?](/pt-br/blog/robots-txt).

## Erros comuns

- **Embutir as credenciais no endereço de `server`.** O Playwright ignora essa parte; o resultado é um `407` ou tempo esgotado.
- **Tentar usuário e senha com SOCKS5.** O Chromium não oferece suporte; use a whitelist de IP ou um proxy HTTP.
- **Iniciar um navegador novo para cada página.** O navegador abre uma vez; o isolamento e a troca de proxy são feitos com contextos.
- **Passar um fluxo com sessão por um gateway rotativo.** As conexões saem por IPs diferentes e a sessão cai. Use sticky.
- **Não fechar os contextos.** Cada contexto aberto segura memória; feche-o no bloco `finally`.
- **Bloquear scripts e folhas de estilo.** A página não consegue gerar o conteúdo e o seu seletor volta vazio.
- **Atribuir ao site de destino o tempo esgotado no `goto`.** Olhe antes o evento `requestfailed` e as credenciais do proxy.
- **Aceitar uma resposta `200` sem olhar o conteúdo.** Confirme que o elemento esperado está na página; telas de verificação também podem devolver `200`.

## Guia de decisão

| Necessidade | Recomendação |
|---|---|
| Script ou teste para o qual basta um ponto de saída | `launch(proxy=...)`, proxy HTTP |
| Várias sessões independentes em um só navegador | `new_context(proxy=...)`, um proxy por contexto |
| Varredura em massa de páginas independentes | Proxy rotativo, um único endereço de gateway |
| Fluxo de várias etapas com login | Proxy sticky, um contexto, um IP |
| SOCKS5 é obrigatório | Whitelist de IP, sem `username` nem `password` |
| Tráfego cobrado por GB | Bloqueie as requisições de imagens, mídia e fontes com `route`; se possível, leia a resposta JSON |
| Dados no código-fonte da página ou em um endpoint JSON | Cliente HTTP simples em vez do Playwright |
| Fazer um agente de IA usar um navegador | Playwright MCP |

## Perguntas frequentes

### O Playwright é gratuito?

Sim. É um projeto de código aberto com licença Apache 2.0; não se paga pela biblioteca nem pelos binários de navegador que ela baixa. O custo vem dos recursos de servidor consumidos pelos navegadores e do tráfego de proxy que você usa.

### É melhor usar o Playwright com Python ou com Node.js?

A configuração do proxy e o comportamento do navegador são iguais nas duas linguagens, porque ambas falam com o mesmo driver. O que deve decidir é a linguagem da sua equipe e do seu fluxo de processamento de dados. A comparação das duas linguagens do ponto de vista do scraping está em [Extração de dados: JavaScript ou Python?](/pt-br/blog/web-scraping-javascript-vs-python).

### Posso usar um proxy diferente para cada página?

O proxy é vinculado ao contexto, não à página. Se você quer um IP diferente para cada página, abra cada página no seu próprio contexto. Se usa um gateway rotativo, nem isso é necessário; a rotação é feita pelo gateway.

### A autenticação SOCKS5 funciona com Firefox ou WebKit?

Quando um usuário é informado junto com um endereço `socks5://`, o Playwright lança o erro na sua própria etapa de validação, antes de iniciar o navegador, e essa verificação não olha o tipo de navegador. Nós testamos apenas com o Chromium; para os outros motores, considere também a whitelist de IP.

### O proxy se comporta de outra forma no modo headless?

Não. O objeto `proxy` é aplicado da mesma forma com janela e sem janela. Se quiser ver o problema com os próprios olhos, você pode abrir a janela com `launch(headless=False)` e executar o mesmo script.

### Usar um proxy faz as telas de verificação desaparecerem?

Não. O proxy muda apenas o IP pelo qual a requisição sai; o ritmo de requisições, os sinais do navegador e a coerência da sessão continuam os mesmos. Por que essas telas aparecem está explicado em [Puppeteer e CAPTCHA: por que aparece, como reduzir?](/pt-br/blog/puppeteer-captcha); o que é dito lá vale também para o Playwright. Não recomendamos extensões para burlar a detecção: o caminho duradouro é um ritmo razoável, uma sessão coerente e, se existir, a API oficial.

## Em resumo

No Playwright, o proxy é um único objeto: `server`, `username`, `password`. Se você o passa à chamada `launch()`, o navegador inteiro sai pelo proxy; se o passa a `new_context()`, apenas aquela sessão. O segundo caminho significa um IP diferente por contexto em um só navegador. As credenciais não são escritas dentro do endereço, com SOCKS5 usa-se a whitelist de IP no lugar da senha, em fluxos com sessão escolhe-se sticky e, em páginas independentes, rotativo. Se você paga o tráfego por GB, bloqueie imagens e fontes; se vir tempo esgotado, olhe primeiro o evento `requestfailed`. Os tipos de proxy adequados ao seu trabalho estão em [nossos serviços de proxy](/pt-br/proxy).
