La modalità headless di Chrome viene aggiornata con l'introduzione di --headless=new

La modalità headless di Chrome è migliorata molto.

Peter Kvitek
Peter Kvitek

La modalità headless di Chrome è migliorata molto. Questo articolo presenta una panoramica dei recenti sforzi di progettazione per rendere Headless più utile per gli sviluppatori avvicinando Headless alla modalità "headful" standard di Chrome.

Contesto

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

La modalità headless è una scelta popolare per l'automazione del browser tramite progetti come Puppeteer o ChromeDriver. Di seguito è riportato un esempio minimo della riga di comando relativo all'utilizzo della modalità headless per creare un file PDF di un determinato URL:

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

Novità di Headless

Prima di addentrarci nei recenti miglioramenti di Headless, è importante capire come funzionava il "vecchio" modello Headless. Lo snippet della riga di comando che abbiamo mostrato in precedenza utilizza il flag della riga di comando --headless, a indicare che Headless è solo una modalità di funzionamento del normale browser Chrome. Forse, sorprendentemente, questo non era vero. Tecnicamente, il vecchio Headless era un'implementazione separata del browser alternativo che veniva fornita come parte dello stesso file binario di Chrome. Il codice non condivide nessuno del codice del browser Chrome in //chrome.

Come puoi immaginare, l'implementazione e la gestione di questo browser headless separato comportava un grande sovraccarico tecnico, ma non era l'unico problema. Poiché Headless era un'implementazione separata, aveva i propri bug e le proprie funzionalità non presenti in Chrome headless. Questo creava una situazione poco chiara in cui qualsiasi test automatico del browser poteva passare in modalità headful ma non riuscire in modalità headless o viceversa, un problema grave per gli ingegneri dell'automazione. Sono inoltre esclusi i test automatici basati sull'installazione di un'estensione del browser, ad esempio. Lo stesso vale per qualsiasi altra funzionalità a livello di browser: a meno che Headless non avesse una propria implementazione separata, non era supportata.

Nel 2021, il team di Chrome ha deciso di risolvere questo problema e unificare le modalità Headless e Headful una volta per tutte.

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

Siamo lieti di annunciare che la nuova modalità headless è ora disponibile in Chrome 112. In questa modalità Chrome crea, ma non visualizza le finestre della piattaforma. Tutte le altre funzionalità, esistenti e future, sono disponibili senza limitazioni.

Prova il nuovo Headless

Per provare 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 tramite:

chrome --headless=old

Al momento, il passaggio del flag della riga di comando --headless senza un valore esplicito attiva comunque la vecchia modalità Headless, ma abbiamo in programma di cambiare questa impostazione predefinita in nuova modalità Headless nel tempo.

Prevediamo di rimuovere completamente il vecchio Headless dal programma binario di Chrome e interrompere il supporto di questa modalità in Puppeteer entro la fine dell'anno. Nell'ambito di questa rimozione, renderemo disponibile la versione precedente di Headless come file binario autonomo separato per gli utenti che non possono ancora eseguire l'upgrade.

Nuovo Headless in Puppeteer

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();

Nuovo Headless 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 di associazioni di lingue.

Flag della riga di comando specifici per headless

Per la nuova modalità headless sono disponibili i seguenti flag della riga di comando.

--dump-dom

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

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

Tieni presente che questa operazione è diversa dalla semplice stampa del codice sorgente HTML (operazione che potresti fare con curl). Per ottenere l'output di --dump-dom, Chrome analizza prima il codice HTML in un DOM, esegue qualsiasi <script> che potrebbe alterare il DOM, quindi trasforma nuovamente questo 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 corrente. È particolarmente utile in combinazione con il flag --window-size. 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 corrente. 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/

--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 indica 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

Il --virtual-time-budget consente il viaggio nel tempo. Beh, in una certa misura. Virtual Time agisce come un "avanzamento veloce" per qualsiasi codice dipendente dal tempo (ad esempio, setTimeout/setInterval). Forza il browser a eseguire il codice della pagina il più velocemente possibile, facendo credere alla pagina che il tempo passi effettivamente.

Per illustrarne l'utilizzo, prendi in considerazione questa pagina 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 salvarla in formato PDF:

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

--allow-chrome-scheme-url

Il flag --allow-chrome-scheme-url è necessario per accedere a chrome:// URL. Questo flag è disponibile a partire da Chrome 123. Esempio:

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

Debug

Poiché Chrome è effettivamente invisibile in modalità headless, potrebbe sembrare difficile capire cosa sta succedendo in caso di problemi. Fortunatamente, è possibile eseguire il debug di Chrome headless in un modo molto simile a Chrome headful. Il trucco consiste nell'avviare 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 visualizzato un URL WebSocket univoco su stdout, ad esempio:

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

In una normale istanza di Chrome headless, possiamo quindi utilizzare il debug remoto di Chrome DevTools per stabilire la connessione alla destinazione headless e ispezionarla. Per farlo, vai a chrome://inspect, fai clic sul pulsante Configura... e inserisci l'indirizzo IP e il numero di porta dall'URL di WebSocket. Nell'esempio riportato sopra, ho inserito 127.0.0.1:60926. Fai clic su Fine. Dovresti vedere un target remoto con tutte le relative schede e gli altri target elencati di seguito. Fai clic su inspect per poter accedere a Chrome DevTools che ispeziona il target headless remoto, inspect.

Chrome DevTools può esaminare una pagina di destinazione headless remota

Feedback

Non vediamo l'ora di ricevere il tuo feedback sulla nuova modalità headless. Se riscontri problemi, segnalali.