Modo headless do Chrome

Peter Kvitek
Peter Kvitek

Com o modo headless do Chrome, é possível executar o navegador em um ambiente desacompanhado, sem nenhuma interface visível. Basicamente, é possível executar o Chrome sem o Chrome.

O modo headless é uma escolha popular para a automação de navegadores, com projetos como Puppeteer ou ChromeDriver.

Usar o modo headless

Para usar o modo sem cabeça, transmita a flag de linha de comando --headless:

chrome --headless

Usar o modo headless antigo

Anteriormente, o modo headless era uma implementação separada e alternativa do navegador que foi enviada como parte do mesmo binário do Chrome. Ele não compartilha nenhum código do navegador Chrome em //chrome.

O Chrome agora tem modos Headless e headful unificados.

O modo headless compartilha o código com o Chrome.

Por enquanto, o antigo modo headless ainda está disponível com:

chrome --headless=old

No Puppeteer

Para usar o modo headless no Puppeteer:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({
  headless: 'true', // (default) enables Headless
  // `headless: 'old'` enables old Headless
  // `headless: false` enables "headful" mode
});

const page = await browser.newPage();
await page.goto('https://developer.chrome.com/');

// …

await browser.close();

No Selenium-WebDriver

Para usar o modo headless no Selenium-WebDriver:

const driver = await env
  .builder()
  .setChromeOptions(options.addArguments('--headless'))
  .build();

await driver.get('https://developer.chrome.com/');

// …

await driver.quit();

Consulte a postagem do blog da equipe do Selenium para mais informações, incluindo exemplos que usam outras vinculações de linguagem.

Flags de linha de comando

As flags de linha de comando a seguir estão disponíveis no modo sem cabeça.

--dump-dom

A flag --dump-dom imprime o DOM serializado da página de destino no stdout. Exemplo:

chrome --headless --dump-dom https://developer.chrome.com/

Isso é diferente de imprimir o código-fonte HTML, o que pode ser feito com curl. Para gerar a saída de --dump-dom, o Chrome primeiro analisa o código HTML em um DOM, executa qualquer <script> que possa alterar o DOM e, em seguida, transforma esse DOM em uma string serializada de HTML.

--screenshot

A flag --screenshot faz uma captura de tela da página de destino e a salva como screenshot.png no diretório de trabalho atual. Isso é especialmente útil em combinação com a flag --window-size.

Exemplo:

chrome --headless --screenshot --window-size=412,892 https://developer.chrome.com/

--print-to-pdf

A flag --print-to-pdf salva a página de destino como um PDF chamado output.pdf no diretório de trabalho atual. Exemplo:

chrome --headless --print-to-pdf https://developer.chrome.com/

Opcionalmente, é possível adicionar a flag --no-pdf-header-footer para omitir o cabeçalho de impressão (com a data e a hora atuais) e o rodapé (com o URL e o número da página).

chrome --headless --print-to-pdf --no-pdf-header-footer https://developer.chrome.com/

Não: a funcionalidade por trás da flag --no-pdf-header-footer já estava disponível com a flag --print-to-pdf-no-header. Talvez seja necessário usar o nome da flag antiga, se você estiver usando uma versão anterior.

--timeout

A flag --timeout define o tempo máximo de espera (em milissegundos) após o qual o conteúdo da página é capturado por --dump-dom, --screenshot e --print-to-pdf, mesmo que a página ainda esteja carregando.

chrome --headless --print-to-pdf --timeout=5000 https://developer.chrome.com/

A flag --timeout=5000 informa ao Chrome para aguardar até 5 segundos antes de imprimir o PDF. Portanto, esse processo leva no máximo 5 segundos para ser executado.

--virtual-time-budget

O --virtual-time-budget age como um "avanço rápido" para qualquer código dependente de tempo (por exemplo, setTimeout/setInterval). Ele força o navegador a executar qualquer código da página o mais rápido possível, fazendo com que a página acredite que o tempo realmente passa.

Para ilustrar o uso, considere esta demonstração, que incrementa, registra e mostra um contador a cada segundo usando setTimeout(fn, 1000). Confira o código relevante:

<output>0</output>
<script>
  const element = document.querySelector('output');
  let counter = 0;
  setInterval(() => {
    counter++;
    console.log(counter);
    element.textContent = counter;
  }, 1_000);
</script>

Após um segundo, a página contém "1"; após dois segundos, "2" e assim por diante. Confira como capturar o estado da página após 42 segundos e salvar como PDF:

chrome --headless --print-to-pdf --virtual-time-budget=42000 https://mathiasbynens.be/demo/time

--allow-chrome-scheme-url

A flag --allow-chrome-scheme-url é necessária para acessar URLs chrome://. Essa flag está disponível no Chrome 123. Veja um exemplo:

chrome --headless --print-to-pdf --allow-chrome-scheme-url chrome://gpu

Depurar

Como o Chrome fica invisível no modo Headless, pode parecer difícil resolver um problema. É possível depurar o Headless Chrome de uma forma muito semelhante ao Chrome com cabeça.

Inicie o Chrome no modo headless com a flag de linha de comando --remote-debugging-port.

chrome --headless --remote-debugging-port=0 https://developer.chrome.com/

Isso imprime um URL WebSocket exclusivo no stdout, por exemplo:

DevTools listening on ws://127.0.0.1:60926/devtools/browser/b4bd6eaa-b7c8-4319-8212-225097472fd9

Em uma instância do Chrome com cabeça, podemos usar a depuração remota do Chrome DevTools para conectar e inspecionar o destino sem cabeça.

  1. Acesse chrome://inspect e clique no botão Configurar.
  2. Insira o endereço IP e o número da porta do URL do WebSocket.
    • No exemplo anterior, digitei 127.0.0.1:60926.
  3. Clique em Concluído. Um destino remoto vai aparecer com todas as guias e outros destinos listados.
  4. Clique em Inspecionar para acessar o Chrome DevTools e inspecionar o destino Headless remoto, incluindo uma visualização em tempo real da página.

O Chrome DevTools pode inspecionar uma página de destino remota do Headless

Feedback

Aguardamos seu feedback sobre o modo sem cabeça. Se você encontrar algum problema, informe um bug.