Modalità headless di Chrome

Peter Kvitek
Peter Kvitek

Nel 2017, in Chrome 59 è stata introdotta la modalità headless, che consente di eseguire il browser in un ambiente inattivo, senza UI visibile. Essenzialmente, potresti eseguire Chrome senza Chrome.

La modalità headless è una scelta molto diffusa per l'automazione del browser, tramite progetti come Puppeteer o ChromeDriver. Ecco un esempio minimo della riga di comando in cui viene utilizzata la modalità headless per creare un file PDF di un determinato URL:

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

Come funziona headless

Prima di vedere come funziona ora Headless, è importante capire come funzionava il "vecchio" Headless. Il precedente snippet della riga di comando utilizza il flag della riga di comando --headless, il che suggerisce che Headless è solo una modalità operativa del normale browser Chrome. Forse non era vero in realtà. Infatti, il vecchio Headless era un'implementazione separata e alternativa del browser che veniva spedita come parte dello stesso programma binario di Chrome. Non condivide nessuno del codice del browser Chrome in //chrome.

L'implementazione e il mantenimento di un browser headless separato comportavano una notevole attività di progettazione. Inoltre, poiché Headless era un'implementazione separata, aveva dei bug e delle funzionalità che non erano presenti in Chrome headful. Questo ha creato confusione per i test automatici del browser, che potrebbero non riuscire in modalità headful ma non in modalità headless o viceversa.

Inoltre, Headless ha escluso tutti i test automatici basati sull'installazione delle estensioni del browser. Lo stesso vale per qualsiasi altra funzione a livello di browser; a meno che Headless non avesse una propria implementazione separata, non era supportata.

Il team di Chrome ha ora unificato le modalità headless e headful.

Il nuovo Chrome headless non è più un'implementazione separata del browser e ora condivide il codice con Chrome.

La nuova modalità headless è disponibile in Chrome 112. In questa modalità, Chrome crea, ma non mostra, finestre della piattaforma. Tutte le altre funzioni, esistenti e future, sono disponibili senza limitazioni.

Usa la modalità headless

Per utilizzare la nuova modalità headless, passa il flag della riga di comando --headless=new:

chrome --headless=new

Per il momento, la vecchia modalità headless è ancora disponibile con:

chrome --headless=old

In un burattinaio

Per attivare la nuova modalità headless in Puppeteer:

import puppeteer from 'puppeteer';

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

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

// …

await browser.close();

In Selenium-WebDriver

Per utilizzare la nuova modalità headless in Selenium-WebDriver:

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

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

// …

await driver.quit();

Consulta il post del blog del team di Selenium per ulteriori informazioni, inclusi esempi che utilizzano associazioni di altre lingue.

Flag della riga di comando

I seguenti flag della riga di comando sono disponibili nella nuova modalità headless.

--dump-dom

Il flag --dump-dom stampa il DOM serializzato della pagina di destinazione su stdout. Ad esempio:

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

Questa operazione è diversa dalla stampa del codice sorgente HTML, che potresti eseguire con curl. Per fornirti l'output di --dump-dom, Chrome prima analizza il codice HTML in un DOM, esegue qualsiasi elemento <script> che potrebbe modificare il DOM, quindi trasforma quel DOM in una stringa serializzata di HTML.

--screenshot

Il flag --screenshot acquisisce uno screenshot della pagina di destinazione e lo salva come screenshot.png nella directory di lavoro attuale. Ciò è particolarmente utile in combinazione con il flag --window-size.

Ad esempio:

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

--print-to-pdf

Il flag --print-to-pdf salva la pagina di destinazione come PDF denominato output.pdf nella directory di lavoro attuale. Ad esempio:

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

Se vuoi, puoi aggiungere il flag --no-pdf-header-footer per omettere l'intestazione di stampa (con la data e l'ora correnti) e il piè di pagina (con l'URL e il numero di pagina).

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

No: la funzionalità dietro il flag --no-pdf-header-footer era precedentemente disponibile con il flag --print-to-pdf-no-header. Se usi una versione precedente, potrebbe essere necessario utilizzare il nome del flag precedente.

--timeout

Il flag --timeout definisce il tempo di attesa massimo (in millisecondi) dopo il quale i contenuti della pagina vengono acquisiti da --dump-dom, --screenshot e --print-to-pdf anche se la pagina è ancora in fase di caricamento.

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

Il flag --timeout=5000 comunica a Chrome di attendere fino a 5 secondi prima di stampare il PDF. Pertanto, l'esecuzione di questo processo richiede al massimo 5 secondi.

--virtual-time-budget

L'elemento --virtual-time-budget agisce da"avanzamento veloce" per qualsiasi codice dipendente dal tempo (ad esempio, setTimeout/setInterval). Forza il browser a eseguire qualsiasi codice della pagina il più velocemente possibile, facendo credere alla pagina che il tempo effettivamente passi.

Per illustrarne l'uso, consideriamo questa demo, che incrementa, registra e visualizza un contatore ogni secondo utilizzando setTimeout(fn, 1000). Ecco il codice pertinente:

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

Dopo un secondo, la pagina contiene "1"; dopo due secondi, "2" e così via. Ecco come acquisire lo stato della pagina dopo 42 secondi e salvarlo come PDF:

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

--allow-chrome-scheme-url

Per accedere agli URL chrome:// è necessario il flag --allow-chrome-scheme-url. Questo flag è disponibile nella versione 123 di Chrome. Esempio:

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

esegui il debug

Poiché Chrome è effettivamente invisibile in modalità headless, potrebbe sembrare difficile risolvere un problema. È possibile eseguire il debug di Chrome headless in un modo molto simile a quello di Chrome headful.

Avvia Chrome in modalità headless con il flag della riga di comando --remote-debugging-port.

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

Viene stampato un URL WebSocket univoco allo stdout, ad esempio:

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

In un'istanza di Chrome headless, possiamo quindi utilizzare il debug remoto di Chrome DevTools per connetterci alla destinazione headless ed esaminarla.

  1. Vai a chrome://inspect e fai clic sul pulsante Configura....
  2. Inserisci l'indirizzo IP e il numero di porta dall'URL WebSocket.
    • Nell'esempio precedente, ho inserito 127.0.0.1:60926.
  3. Fai clic su Fine. Dovresti vedere un oggetto target remoto con tutte le relative schede e gli altri target elencati.
  4. Fai clic su Ispeziona per accedere a Chrome DevTools e ispezionare il target headless remoto, inclusa una visualizzazione in tempo reale della pagina.

Chrome DevTools può esaminare una pagina di destinazione headless remota

Feedback

Non vediamo l'ora di ricevere il tuo feedback sulla nuova modalità headless. In caso di problemi, segnala un bug.