Por Que o Selenium Lida Tão Mal com Proxies Autenticados?
Se você já tentou passar http://user:pass@gate.proxyhat.com:8080 diretamente para webdriver.ChromeOptions(), sabe a frustração: o Chrome ignora as credenciais, exibe um pop-up de autenticação e o teste simplesmente trava. Esse é um problema arquitetural do Chromium — ele delega a autenticação proxy ao sistema operacional, não ao WebDriver.
Para engenheiros de QA e scraping que dependem do ecossistema Selenium, isso cria um gargalo real. Proxies residenciais — essenciais para contornar anti-bots e CAPTCHAs — quase sempre exigem autenticação user:pass. Sem uma estratégia sólida de Selenium proxy auth, você fica limitado a proxies datacenter sem autenticação ou a extensões de navegador frágeis.
Neste guia, vamos resolver isso de forma idiomática: middleware, profiles, stealth e rotação — tudo integrado ao fluxo do Selenium, sem gambiarras.
Chrome + selenium-wire: Autenticação Proxy Nativa
O selenium-wire estende o WebDriver do Selenium para interceptar e modificar requisições HTTP em tempo real. A principal vantagem para proxies autenticados: ele gerencia o túnel CONNECT e injeta o header Proxy-Authorization automaticamente.
Instalação e Configuração Base
pip install selenium-wire selenium
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options
PROXY_USER = "user-country-US"
PROXY_PASS = "pass"
PROXY_HOST = "gate.proxyhat.com"
PROXY_PORT = 8080
options = Options()
options.add_argument("--headless=new")
options.add_argument("--disable-blink-features=AutomationControlled")
seleniumwire_options = {
"proxy": {
"https": f"http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}",
"http": f"http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}",
},
"disable_encoding": True, # útil para inspecionar conteúdo bruto
}
driver = webdriver.Chrome(
options=options,
seleniumwire_options=seleniumwire_options,
)
driver.get("https://httpbin.org/ip")
print(driver.find_element("tag name", "body").text)
driver.quit()
Pontos críticos de produção:
- Timeouts: configure
seleniumwire_options["verify_ssl"] = Falseapenas em dev; em produção, mantenha SSL verification ativa. - Memória: selenium-wire armazena todas as requisições em memória. Em sessões longas, limpe periodicamente com
del driver.requests. - Concorrência: cada instância abre uma porta local de proxy. Em paralelo, garanta portas distintas ou use
port=0para auto-atribuição.
Geo-targeting na Prática
Com Selenium residential proxies, o geo-targeting é codificado diretamente no username — sem necessidade de endpoints diferentes:
# Proxy com geo-targeting por país e cidade
PROXY_USER = "user-country-DE-city-berlin"
PROXY_PASS = "pass"
seleniumwire_options = {
"proxy": {
"https": f"http://{PROXY_USER}:{PROXY_PASS}@gate.proxyhat.com:8080",
},
}
Firefox: Perfis de Proxy com Autenticação via Extensão
O Firefox não sofre do mesmo problema do Chrome — mas também não aceita credenciais proxy inline na URL. A abordagem idiomática é criar um profile com proxy pré-configurado e injetar autenticação via uma extensão WebExtension mínima.
import os
import tempfile
import zipfile
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
PROXY_HOST = "gate.proxyhat.com"
PROXY_PORT = 8080
PROXY_USER = "user-country-GB"
PROXY_PASS = "pass"
def create_proxy_auth_extension(host, port, user, password):
"""Cria uma WebExtension temporária que injeta credenciais proxy."""
manifest_json = """{
"version": "1.0.0",
"manifest_version": 2,
"name": "proxy-auth-helper",
"permissions": ["webRequest", "webRequestBlocking", "<all_urls>"],
"background": {"scripts": ["background.js"]}
}"""
background_js = """
browser.webRequest.onAuthRequired.addListener(
function(details) {
return {authCredentials: {username: "%s", password: "%s"}};
},
{urls: ["<all_urls>"]},
["blocking"]
);
""" % (user, password)
plugin_dir = tempfile.mkdtemp()
with open(os.path.join(plugin_dir, "manifest.json"), "w") as f:
f.write(manifest_json)
with open(os.path.join(plugin_dir, "background.js"), "w") as f:
f.write(background_js)
ext_path = os.path.join(plugin_dir, "proxy_auth.zip")
with zipfile.ZipFile(ext_path, "w") as zp:
zp.write(os.path.join(plugin_dir, "manifest.json"), "manifest.json")
zp.write(os.path.join(plugin_dir, "background.js"), "background.js")
return ext_path
ext_path = create_proxy_auth_extension(
PROXY_HOST, PROXY_PORT, PROXY_USER, PROXY_PASS
)
options = Options()
options.add_argument("--headless")
options.set_preference("network.proxy.type", 1)
options.set_preference("network.proxy.http", PROXY_HOST)
options.set_preference("network.proxy.http_port", PROXY_PORT)
options.set_preference("network.proxy.ssl", PROXY_HOST)
options.set_preference("network.proxy.ssl_port", PROXY_PORT)
options.add_argument(f"--extension={ext_path}")
driver = webdriver.Firefox(options=options)
driver.get("https://httpbin.org/ip")
print(driver.find_element("tag name", "body").text)
driver.quit()
Essa abordagem é mais robusta que Chrome extensions porque o Firefox suporta webRequest.onAuthRequired de forma estável. Para sessões paralelas, gere um profile temporário único por instância com tempfile.mkdtemp().
Selenium Stealth: Reduzindo Impressões Digitais de Automação
Mesmo com o proxy correto, sites modernos detectam Selenium via fingerprints do navegador: navigator.webdriver, ausência de plugins, canvas fingerprinting e timing de eventos. Duas bibliotecas resolvem isso de forma complementar.
selenium-stealth
O selenium-stealth aplica patches no WebDriver após a inicialização — remove flags de automação, injeta propriedades realistas e normaliza o user-agent.
from selenium import webdriver
from selenium_stealth import stealth
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--disable-blink-features=AutomationControlled")
driver = webdriver.Chrome(options=options)
stealth(
driver,
languages=["pt-BR", "en-US", "en"],
vendor="Google Inc.",
platform="Win32",
webgl_vendor="Intel Inc.",
renderer="Intel Iris OpenGL Engine",
fix_hairline=True,
)
driver.get("https://bot.sannysoft.com/")
print("Stealth check:", driver.title)
driver.quit()
selenium-driverless
Para Selenium stealth avançado, o selenium-driverless opera via Chrome DevTools Protocol (CDP) diretamente, sem criar o objeto webdriver no DOM. Isso torna a detecção significativamente mais difícil:
import asyncio
from selenium_driverless import webdriver
async def main():
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
driver = await webdriver.Chrome(options=options)
# Autenticação proxy via CDP — sem extensão
await driver.execute_cdp_cmd(
"Network.setExtraHTTPHeaders",
{"headers": {"Proxy-Authorization": "Basic <base64 user:pass>"}}
)
await driver.get("https://nowsecure.nl/")
print(await driver.title)
await driver.quit()
asyncio.run(main())
Regra prática: use selenium-stealth para compatibilidade com scripts legados. Migre para selenium-driverless quando precisar de CDP direto ou quando os sites alvo atualizarem suas heurísticas de detecção.
Padrão Rotating Proxy Pool: IP Novo por Sessão
Para scraping de SERPs ou monitoramento de preços em escala, você precisa de um IP diferente por sessão — não por requisição. O padrão rotating proxy pool atribui um IP sticky a cada instância do WebDriver, rotacionando apenas entre sessões.
import itertools
import string
import random
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options
PROXY_HOST = "gate.proxyhat.com"
PROXY_PORT = 8080
PROXY_PASS = "pass"
def generate_session_id(length=8):
"""Gera um ID de sessão único para sticky IP."""
return ''.join(random.choices(string.ascii_lowercase + string.digits, k=length))
def create_stealth_driver(country="US", city=None):
"""Cria um WebDriver com IP residencial único por sessão."""
session_id = generate_session_id()
username = f"user-country-{country}-session-{session_id}"
if city:
username = f"user-country-{country}-city-{city}-session-{session_id}"
options = Options()
options.add_argument("--headless=new")
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("--window-size=1920,1080")
seleniumwire_options = {
"proxy": {
"https": f"http://{username}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}",
"http": f"http://{username}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}",
},
}
driver = webdriver.Chrome(
options=options,
seleniumwire_options=seleniumwire_options,
)
return driver
def scrape_targets(targets, country="US"):
"""Processa uma lista de URLs, rotacionando IP a cada sessão."""
results = []
for url in targets:
driver = create_stealth_driver(country=country)
try:
driver.get(url)
# sua lógica de extração aqui
results.append(driver.page_source[:200])
except Exception as e:
print(f"Erro em {url}: {e}")
finally:
driver.quit() # libera o IP sticky
return results
urls = [
"https://httpbin.org/ip",
"https://httpbin.org/headers",
"https://httpbin.org/user-agent",
]
print(scrape_targets(urls, country="DE"))
O flag -session-{id} no username garante que o proxy atribui um IP residencial novo a cada sessão, mantendo-o estável durante toda a vida do WebDriver. Quando driver.quit() é chamado, o IP é reciclado.
Estratégias de Rotação
| Estratégia | Quando Usar | Implementação |
|---|---|---|
| Per-request | Scraping de alta frequência, APIs públicas | Sem session flag — IP muda a cada request |
| Sticky session | Fluxos multi-página, login, carrinho | Flag -session-{id} — IP fixo por ~10 min |
| Per-WebDriver | Scraping paralelo, SERP tracking | Session ID único por instância — IP novo por worker |
Selenium Grid e Containerização para Escala
Quando você precisa de 50+ browsers em paralelo, instâncias locais não escalam. O Selenium Grid 4 com Docker é a solução padrão da indústria.
Docker Compose para Grid com Proxy
# docker-compose.yml
version: '3.8'
services:
selenium-hub:
image: selenium/hub:4.18
ports:
- "4442:4442"
- "4443:4443"
- "4444:4444"
environment:
- SE_SESSION_RETRY_INTERVAL=2
- SE_NODE_SESSION_TIMEOUT=300
chrome-node:
image: selenium/node-chrome:4.18
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
- SE_NODE_MAX_SESSIONS=4
- SE_NODE_OVERRIDE_MAX_SESSIONS=true
deploy:
replicas: 5
worker:
build: ./scraper
depends_on:
- selenium-hub
environment:
- HUB_URL=http://selenium-hub:4444/wd/hub
- PROXY_HOST=gate.proxyhat.com
- PROXY_PORT=8080
deploy:
replicas: 10
Worker com Rotação de IP por Sessão
import os
import uuid
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from seleniumwire import webdriver as sw_webdriver
HUB_URL = os.environ["HUB_URL"]
PROXY_HOST = os.environ["PROXY_HOST"]
PROXY_PORT = os.environ["PROXY_PORT"]
PROXY_USER = f"user-country-US-session-{uuid.uuid4().hex[:8]}"
PROXY_PASS = "pass"
def create_remote_driver():
options = Options()
options.add_argument("--headless=new")
options.add_argument("--disable-blink-features=AutomationControlled")
seleniumwire_options = {
"proxy": {
"https": f"http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}",
},
}
driver = sw_webdriver.Remote(
command_executor=HUB_URL,
options=options,
seleniumwire_options=seleniumwire_options,
)
return driver
# Cada worker obtém um IP residencial único
with create_remote_driver() as driver:
driver.get("https://httpbin.org/ip")
print(driver.find_element("tag name", "body").text)
Dimensionamento prático: com 5 nodes Chrome (4 sessões cada) = 20 browsers simultâneos. Com Selenium residential proxies, isso significa 20 IPs residenciais distintos processando em paralelo. Para 100+ sessões, adicione mais nodes ou use Kubernetes com HPA (Horizontal Pod Autoscaler).
Kubernetes: Escalabilidade Elástica
Em produção, o padrão recomendado é:
- Deployment para o hub (1 réplica com anti-affinity)
- Deployment para nodes Chrome com
replicasdinâmico via HPA baseado em CPU - Job ou Deployment para workers, cada um com session ID único
- ConfigMap para credenciais proxy (nunca hardcode no image)
- Resource limits: cada node Chrome precisa de ~1 vCPU e 2GB RAM por sessão
Selenium vs Playwright: Quando Migrar?
O Playwright se tornou a alternativa mais popular ao Selenium para scraping moderno. Mas a decisão não é binária — depende do contexto.
| Dimensão | Selenium | Playwright |
|---|---|---|
| Proxy autenticado | Requer selenium-wire ou extensão | Nativo: proxy={username, password} |
| Stealth | Requer selenium-stealth / driverless | Melhor baseline, mas não é invisível |
| Ecossistema | 12+ anos, bindings em 8+ linguagens | 5 anos, JS/TS/Python/Java/.NET |
| Grid paralelo | Maduro (Selenium Grid 4) | Nativo com browser.newContext() |
| CDP Access | Limitado sem hacks | Primeiro-class via CDPSession |
| Legado / QA | Compatível com Selenium IDE, Grid, Cloud | Sem compatibilidade com testes existentes |
| Auto-wait | Requer explicit waits | Auto-wait embutido em todas as ações |
| Mobile emulation | Requer Chrome mobile emulation flags | Device descriptors nativos |
Quando Ficar com Selenium
- Sua suíte de testes QA já usa Selenium IDE / Grid / Selenese — migração é cara.
- Você precisa de bindings em linguagens que o Playwright não suporta (Ruby, Perl, PHP).
- Cloud providers (BrowserStack, Sauce Labs, LambdaTest) oferecem infraestrutura Selenium-first.
- Equipe já domina o ecossistema e o custo de re-treinamento não se justifica.
Quando Migrar para Playwright
- Novos projetos de scraping onde Selenium proxy auth é um bloqueador recorrente.
- Você precisa de CDP direto para interceptação avançada ou stealth profundo.
- Paralelismo nativo sem Grid é prioridade —
browser.newContext()é mais leve que um novo WebDriver. - Auto-wait e debug tools (Trace Viewer, Codegen) aceleram desenvolvimento.
Decisão pragmática: se você está escrevendo um scraper novo hoje, comece com Playwright. Se está mantendo uma suíte Selenium existente, invista em selenium-wire + stealth — o custo de migração raramente compensa para projetos em produção.
Melhores Práticas para Produção
Gerenciamento de Sessões
- Always quit: chame
driver.quit()nofinally— não confie em garbage collection. - Session timeout: configure timeouts no Grid (
SE_NODE_SESSION_TIMEOUT) para evitar zombies. - Retry com IP novo: em caso de CAPTCHA ou block, gere novo session ID e recrie o driver.
Ética e Compliance
- Respeite
robots.txte os Termos de Serviço do site alvo. - Implemente rate limiting — mesmo com rotação de IPs, requests excessivos podem sobrecarregar o servidor.
- Para dados pessoais, esteja em conformidade com GDPR e CCPA.
- Considere APIs oficiais antes de scraping — muitas vezes são mais estáveis e legais.
Observabilidade
- Log o IP do proxy atribuído (via
httpbin.org/ipantes do scraping real) para rastrear qual IP foi bloqueado. - Monitore success rate por país e por site — proxies residenciais têm taxas diferentes por região.
- Alerte quando success rate cair abaixo de 85% — pode indicar bloqueio de range ou fingerprint detection.
Pontos-chave
- Selenium proxy auth não funciona nativamente no Chrome — use selenium-wire para injetar credenciais no túnel CONNECT.
- No Firefox, crie uma WebExtension mínima com
webRequest.onAuthRequiredpara autenticação proxy. - Selenium stealth com selenium-stealth ou selenium-driverless é essencial para contornar anti-bots modernos.
- O padrão rotating proxy pool usa session IDs no username para garantir IP único por WebDriver — não por request.
- Selenium Grid 4 + Docker é o caminho para 20-100+ browsers em paralelo com IPs residenciais distintos.
- Para novos projetos, Playwright oferece proxy auth nativo e melhor stealth — mas Selenium mantém vantagem em ecossistema e legado.
Pronto para escalar seu scraping com proxies residenciais de alta confiabilidade? Confira os planos do ProxyHat e as localizações disponíveis para geo-targeting preciso. Para aprofundar em padrões de scraping, veja nosso guia de web scraping em produção.






