Configuração de Proxy no Puppeteer: Flags, Autenticação, Rotação e Realidade

A flag de inicialização é fácil; o 407 que se segue é onde a maioria das configurações de proxy do Puppeteer falha. Aqui está o padrão completo — page.authenticate, rotação de contexto, proxy-chain — e a verdade sobre proxies por página e detecção de modo headless.

A configuração de proxy no Puppeteer começa com uma flag de inicialização e, para a maioria das pessoas, para um passo depois em uma barreira: o proxy responde 407 Proxy Authentication Required, porque --proxy-server não tem como carregar credenciais. A solução está embutida — page.authenticate() — mas ao redor dela há um campo minado de conselhos parcialmente funcionais: pacotes npm que silenciosamente redirecionam seu tráfego através do Node.js, esquemas SOCKS que o Chromium não autenticará, e um bypass localhost que faz proxies funcionais parecerem mortos. Este guia percorre a configuração que se mantém em produção: flags, autenticação, rotação com contextos de navegador, proxy-chain para os casos complicados, e uma seção honesta sobre detecção de modo headless.

Configuração de proxy no Puppeteer: o padrão base

O proxy é um argumento de inicialização do Chromium, então se aplica a todo o navegador. As credenciais passam por page.authenticate(), que responde ao desafio 407 do proxy via o protocolo DevTools — chame antes de qualquer navegação:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    args: ['--proxy-server=http://gate.quantumproxies.io:PORT'],
  });
  const page = await browser.newPage();
  await page.authenticate({ username: 'USER', password: 'PASS' });

  await page.goto('https://httpbin.org/ip', { waitUntil: 'domcontentloaded' });
  console.log(await page.evaluate(() => document.body.innerText)); // exit IP
  await browser.close();
})();

Quatro detalhes que economizam horas de depuração:

Diagrama de fluxo da autenticação de proxy no Puppeteer: flag de inicialização, page.authenticate registra credenciais, desafio 407 do proxy respondido, página carrega do IP de saída residencial
page.authenticate registra credenciais com o protocolo DevTools; quando o gateway envia seu 407, o Chromium responde sem nunca mostrar um diálogo.

Rotação de proxies com contextos de navegador

Reiniciar o Chrome por IP custa segundos e centenas de MB cada vez. Os contextos de navegador resolvem isso: desde o Puppeteer v22 a API é browser.createBrowserContext() (substituindo a antiga variante de navegação anônima), aceita uma opção proxyServer, e um contexto é criado em milissegundos com seus próprios cookies e armazenamento:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const jobs = ['https://example.com/a', 'https://example.com/b'];

  for (const url of jobs) {
    const context = await browser.createBrowserContext({
      proxyServer: 'http://gate.quantumproxies.io:PORT',
    });
    const page = await context.newPage();
    await page.authenticate({ username: 'USER', password: 'PASS' });
    try {
      await page.goto(url, { timeout: 30000 });
      // ...extract...
    } finally {
      await context.close();
    }
  }
  await browser.close();
})();

Contra um gateway rotativo, cada contexto naturalmente sai de um endereço diferente no pool — com proxies residenciais rotativos isso é mais de 90M de IPs em mais de 200 países atrás de um único hostname, e um parâmetro de nome de usuário de sessão fixa fixa uma saída quando um fluxo de múltiplas páginas precisa de continuidade. Esta é a mesma arquitetura de contexto por tarefa que recomendamos para Playwright; o Puppeteer apenas especifica explicitamente o passo de autenticação.

Dois hábitos mantêm a rotação honesta. Registre o IP de saída por contexto durante o desenvolvimento — acesse um endpoint de eco de IP no início do contexto e armazene-o com suas linhas raspadas, para que quando um alvo começar a bloquear suavemente você possa dizer se uma saída ou uma impressão digital é a culpada. E limite sua concorrência: cada contexto é barato, mas cada página aberta ainda mantém memória do renderizador, então um semáforo em torno da criação de contexto supera um loop ilimitado na primeira vez que uma lista de tarefas cresce para milhares de URLs.

proxy-chain: a ponte local para autenticação complicada

Dois casos quebram o padrão flag-mais-autenticação: SOCKS5 autenticado (o Chromium não tem suporte para credenciais SOCKS) e ferramentas que só aceitam uma URL de proxy simples sem etapa de autenticação. O pacote npm proxy-chain resolve ambos iniciando um proxy local, sem credenciais, que encaminha para seu upstream autenticado:

const puppeteer = require('puppeteer');
const proxyChain = require('proxy-chain');

(async () => {
  const upstream = 'http://USER:PASS@gate.quantumproxies.io:PORT';
  const localUrl = await proxyChain.anonymizeProxy(upstream);
  // localUrl is something like http://127.0.0.1:54321 — no credentials needed

  const browser = await puppeteer.launch({
    args: ['--proxy-server=' + localUrl],
  });
  const page = await browser.newPage();
  await page.goto('https://httpbin.org/ip');

  await browser.close();
  await proxyChain.closeAnonymizedProxy(localUrl, true);
})();

Crucialmente, as requests da página ainda saem do próprio Chrome — proxy-chain apenas retransmite bytes, então sua impressão digital TLS permanece a de um navegador real. Essa distinção é a próxima seção.

Proxies por página: a resposta honesta

O Puppeteer não tem proxy nativo por página, e as soluções populares — puppeteer-page-proxy, puppeteer-proxy — interceptam cada request e a reemitem do Node.js com uma biblioteca HTTP, depois alimentam a resposta de volta ao navegador. Três consequências: o alvo agora vê um handshake TLS do Node em vez do Chrome, o que impressões digitais JA3/JA4 sinalizam instantaneamente em sites protegidos; cada request paga uma viagem de ida e volta através do Node; e ambos os pacotes estão efetivamente sem manutenção, com instalação quebrada fora da caixa conforme seus próprios rastreadores de issues. Se você precisar de IPs diferentes para páginas diferentes, use um contexto por proxy como acima — mesmo efeito, tráfego real do Chrome, API suportada.

Comparação de abordagens de rotação de proxy no Puppeteer: reiniciar navegadores, contextos de navegador com proxyServer, e pacotes de redirecionamento do Node que quebram impressões digitais TLS
Contextos oferecem rotação com tráfego genuíno do Chrome. Pacotes de redirecionamento do Node trocam sua impressão digital TLS por uma de bot — o oposto do que um proxy é para.

Realidade da detecção de modo headless

Um proxy corrige a camada de rede; ele não pode tornar o Chrome em modo headless invisível. O antigo modo headless se anunciava com um token User-Agent HeadlessChrome; o novo modo headless (padrão do Puppeteer desde v22) compartilha a arquitetura do navegador real e fecha muito dessa lacuna, mas detectores ainda sondam navigator.webdriver, efeitos colaterais do CDP e peculiaridades de renderização — e plugins stealth corrigem verificações de ontem, não as de amanhã. Ordene suas correções pelo retorno do esforço: um IP residencial limpo primeiro, porque a reputação é o filtro mais barato para sites executarem e aquele que seu código não pode falsificar; cabeçalhos e ritmo sensatos em segundo lugar (nosso guia sobre evitar CAPTCHAs cobre os sinais de gatilho); e quando um alvo endurecido ainda vence, encaminhe esse domínio através de uma Scraper API que lida com renderização, impressões digitais e tentativas novamente e retorna HTML, markdown ou JSON limpos — uma chamada HTTP em vez de uma frota de navegadores corrigidos.

Perguntas frequentes

Como faço para autenticar um proxy no Puppeteer?

Defina o endereço com args: ['--proxy-server=http://host:port'] na inicialização, depois chame await page.authenticate({ username, password }) em cada página antes de navegar. Credenciais incorporadas na URL da flag são ignoradas pelo Chromium. Para SOCKS5 com autenticação, faça a ponte através do proxy-chain, já que o Chromium não pode enviar credenciais SOCKS.

O Puppeteer pode usar um proxy diferente por página?

Não nativamente — a flag de inicialização é para todo o navegador. O equivalente suportado é um contexto de navegador por proxy via browser.createBrowserContext({ proxyServer }), com páginas dentro de cada contexto. Pacotes que prometem proxies verdadeiros por página redirecionam requests através do Node.js, mudando sua impressão digital TLS e sendo sinalizados por sistemas anti-bot sérios.

O Puppeteer suporta proxies SOCKS5?

Sim para endpoints não autenticados: passe --proxy-server=socks5://host:port. SOCKS5 autenticado falha porque o Chromium não tem mecanismo de credenciais SOCKS e page.authenticate() apenas responde a desafios HTTP 407. Soluções alternativas: use a porta HTTP do gateway com autenticação, coloque seu IP na lista de permissões, ou execute proxy-chain como uma ponte local.

Como faço para rodar proxies no Puppeteer?

Crie um contexto de navegador fresco por tarefa com createBrowserContext({ proxyServer }) e aponte para um gateway rotativo — cada contexto então sai de um novo IP automaticamente, sem lista de proxies para gerenciar. Reiniciar todo o navegador por IP também funciona, mas custa segundos e centenas de MB de RAM por rotação.

Por que meu proxy Puppeteer não funciona para localhost?

O Chromium ignora proxies para endereços de loopback por design, então requests para localhost ou 127.0.0.1 vão direto — comportamento que surpreendeu tantas pessoas que se tornou uma issue numerada do Puppeteer. Adicione --proxy-bypass-list=<-loopback> para forçar o uso do proxy, ou simplesmente verifique seu proxy contra um endpoint de eco de IP externo.

O padrão durável é pequeno: flag para o endereço, page.authenticate() para as credenciais, contextos para rotação, proxy-chain para os casos excepcionais — e ceticismo para qualquer pacote que mova suas requests para fora do navegador. Dê a essa pilha saídas residenciais limpas e o Puppeteer permanece entediante, que é o maior elogio que a infraestrutura pode receber.

Execute o Puppeteer em proxies residenciais