TL;DR
Chrome headless è disponibile con Chrome 59. È un modo per eseguire il browser Chrome in un ambiente headless. In pratica, la gestione Chrome senza Chrome! Offre tutte le funzionalità delle piattaforme web moderne fornite da Chromium e dal motore di rendering Blink alla riga di comando.
Perché è utile?
Un browser headless è un ottimo strumento per i test automatici e gli ambienti server in cui non necessitano di una shell UI visibile. Ad esempio, potresti voler eseguire alcuni test una pagina web reale, crearne un PDF o semplicemente controllare come il browser esegue il rendering di un URL.
Avvio di headless (CLI)
Il modo più semplice per iniziare a utilizzare la modalità headless è aprire il programma binario di Chrome
dalla riga di comando. Se hai installato Chrome 59 o versioni successive, avvia Chrome con il flag --headless
:
chrome \
--headless \ # Runs Chrome in headless mode.
--disable-gpu \ # Temporarily needed if running on Windows.
--remote-debugging-port=9222 \
https://www.chromestatus.com # URL to open. Defaults to about:blank.
chrome
deve rimandare alla tua installazione di Chrome. La posizione esatta
variano da piattaforma a piattaforma. Dal momento che sono su Mac, ho creato comodi alias
per ogni versione di Chrome installata.
Se utilizzi il canale stabile di Chrome e non riesci a scaricare la versione beta, ti consiglio
utilizzando chrome-canary
:
alias chrome="/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome"
alias chrome-canary="/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary"
alias chromium="/Applications/Chromium.app/Contents/MacOS/Chromium"
Scarica Chrome Canary qui.
Funzionalità della riga di comando
In alcuni casi potrebbe non essere necessario scrivere in modo programmatico lo script di Chrome headless. Esistono alcuni utili flag della riga di comando per eseguire attività comuni.
Stampa del DOM
La bandiera --dump-dom
stampa document.body.innerHTML
sullo stdout:
chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/
Crea un PDF
Il flag --print-to-pdf
crea un PDF della pagina:
chrome --headless --disable-gpu --print-to-pdf https://www.chromestatus.com/
Acquisizione di screenshot
Per acquisire lo screenshot di una pagina, utilizza il flag --screenshot
:
chrome --headless --disable-gpu --screenshot https://www.chromestatus.com/
# Size of a standard letterhead.
chrome --headless --disable-gpu --screenshot --window-size=1280,1696 https://www.chromestatus.com/
# Nexus 5x
chrome --headless --disable-gpu --screenshot --window-size=412,732 https://www.chromestatus.com/
L'esecuzione con --screenshot
produrrà un file denominato screenshot.png
nel
nella directory di lavoro attuale. Se ti servono screenshot a pagina intera,
sono un po' più coinvolti. Il blog è fantastico
post di David Schnurr che abbraccia l'argomento. Paga
Uso di Chrome headless come strumento automatico per gli screenshot .
Modalità REPL (loop di lettura, valutazione e stampa)
Il flag --repl
esegue headless in una modalità in cui puoi valutare le espressioni JS
nel browser, direttamente dalla riga di comando:
$ chrome --headless --disable-gpu --repl --crash-dumps-dir=./tmp https://www.chromestatus.com/
[0608/112805.245285:INFO:headless_shell.cc(278)] Type a Javascript expression to evaluate or "quit" to exit.
>>> location.href
{"result":{"type":"string","value":"https://www.chromestatus.com/features"}}
>>> quit
$
Vuoi eseguire il debug di Chrome senza un'interfaccia utente del browser?
Quando esegui Chrome con --remote-debugging-port=9222
, viene avviata un'istanza
con il protocollo DevOps abilitato. La
viene utilizzato per comunicare con Chrome e guidare headless
un'istanza del browser. È anche lo scopo dell'utilizzo di strumenti come Sublime, VS Code e Node
il debug remoto di un'applicazione. #synergy
Dato che non hai l'interfaccia utente del browser per vedere la pagina, vai a http://localhost:9222
in un altro browser per verificare che tutto funzioni. Viene visualizzato un elenco
pagine ispezionabili in cui è possibile fare clic e vedere il rendering di headless:
Da qui, puoi usare le familiari funzionalità di DevTools per ispezionare, eseguire il debug e apportare modifiche per visitare la pagina come faresti normalmente. Se utilizzi headless in modo programmatico, questo è anche un potente strumento di debug per vedere tutto il protocollo DevTools non elaborato che attraversano la rete e comunicano con il browser.
Utilizzo programmatico (nodo)
Burattinaio
Puppeteer è una libreria di nodi sviluppati dal team di Chrome. Offre un'API di alto livello per il controllo headless Chrome completo. È simile ad altre librerie di test automatizzate come Phantom e NightmareJS, ma funziona solo con le versioni più recenti di Chrome.
Tra le altre cose, Puppeteer può essere utilizzato per acquisire facilmente screenshot, creare PDF, navigare tra le pagine e recuperare informazioni su queste pagine. Consiglio la biblioteca per automatizzare rapidamente i test del browser. Nasconde le complessità del protocollo DevTools e si occupa delle attività ridondanti come l'avvio di debug dell'istanza di Chrome.
Installalo:
npm i --save puppeteer
Esempio: stampa lo user agent
const puppeteer = require('puppeteer');
(async() => {
const browser = await puppeteer.launch();
console.log(await browser.version());
await browser.close();
})();
Esempio - acquisizione di uno screenshot della pagina
const puppeteer = require('puppeteer');
(async() => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://www.chromestatus.com', {waitUntil: 'networkidle2'});
await page.pdf({path: 'page.pdf', format: 'A4'});
await browser.close();
})();
Consulta la documentazione di Puppeteer. per saperne di più sull'API completa.
La libreria CRI
chrome-remote-interface è una libreria di livello inferiore rispetto all'API Puppeteer. Lo consiglio se vuoi vicino all'hardware e utilizzare direttamente il protocollo DevTools.
Avvio di Chrome
chrome-remote-interface non avvia Chrome al posto vostro, quindi dovrete prendere te ne occupi tu.
Nella sezione interfaccia a riga di comando, abbiamo avviato Chrome manualmente utilizzando
--headless --remote-debugging-port=9222
. Tuttavia, per automatizzare completamente i test,
vuoi aprire Chrome dalla tua applicazione.
Un modo è utilizzare child_process
:
const execFile = require('child_process').execFile;
function launchHeadlessChrome(url, callback) {
// Assuming MacOSx.
const CHROME = '/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome';
execFile(CHROME, ['--headless', '--disable-gpu', '--remote-debugging-port=9222', url], callback);
}
launchHeadlessChrome('https://www.chromestatus.com', (err, stdout, stderr) => {
...
});
Ma la situazione si complica quando si desidera una soluzione portabile che funzioni su più piattaforme di terze parti. Guarda il percorso hardcoded di Chrome :(
Utilizzo di ChromeLauncher
Lighthouse è un meraviglioso
strumento per testare la qualità delle tue app web. Un modulo efficace per il lancio
Chrome è stato sviluppato all'interno di Lighthouse e ora viene estratto per l'utilizzo autonomo.
Il modulo chrome-launcher
Gestione dei partner di rete
troveremo dove
Chrome viene installato, configura un'istanza di debug, avvia il browser e termina
al termine del programma. L'aspetto migliore è che funziona su più piattaforme grazie
Nodo!
Per impostazione predefinita, chrome-launcher
proverà ad avviare Chrome Canary (se è
installato), ma puoi modificarlo per selezionare manualmente il browser Chrome da utilizzare. A
usalo, prima installazione da npm:
npm i --save chrome-launcher
Esempio: utilizzo di chrome-launcher
per avviare Headless
const chromeLauncher = require('chrome-launcher');
// Optional: set logging level of launcher to see its output.
// Install it using: npm i --save lighthouse-logger
// const log = require('lighthouse-logger');
// log.setLevel('info');
/**
* Launches a debugging instance of Chrome.
* @param {boolean=} headless True (default) launches Chrome in headless mode.
* False launches a full version of Chrome.
* @return {Promise<ChromeLauncher>}
*/
function launchChrome(headless=true) {
return chromeLauncher.launch({
// port: 9222, // Uncomment to force a specific port of your choice.
chromeFlags: [
'--window-size=412,732',
'--disable-gpu',
headless ? '--headless' : ''
]
});
}
launchChrome().then(chrome => {
console.log(`Chrome debuggable on port: ${chrome.port}`);
...
// chrome.kill();
});
L'esecuzione di questo script non è utile, ma dovresti vedere un'istanza di
Chrome viene avviato nel Task Manager che ha caricato about:blank
. Ricorda che
non sarà alcuna UI del browser. Siamo headless.
Per controllare il browser, abbiamo bisogno del protocollo DevTools.
Recupero di informazioni sulla pagina
Installa la libreria:
npm i --save chrome-remote-interface
Esempi
Esempio: stampa lo user agent
const CDP = require('chrome-remote-interface');
...
launchChrome().then(async chrome => {
const version = await CDP.Version({port: chrome.port});
console.log(version['User-Agent']);
});
Il risultato sarà simile a questo: HeadlessChrome/60.0.3082.0
Esempio. Controlla se il sito ha un file manifest dell'app web
const CDP = require('chrome-remote-interface');
...
(async function() {
const chrome = await launchChrome();
const protocol = await CDP({port: chrome.port});
// Extract the DevTools protocol domains we need and enable them.
// See API docs: https://chromedevtools.github.io/devtools-protocol/
const {Page} = protocol;
await Page.enable();
Page.navigate({url: 'https://www.chromestatus.com/'});
// Wait for window.onload before doing stuff.
Page.loadEventFired(async () => {
const manifest = await Page.getAppManifest();
if (manifest.url) {
console.log('Manifest: ' + manifest.url);
console.log(manifest.data);
} else {
console.log('Site has no app manifest');
}
protocol.close();
chrome.kill(); // Kill Chrome.
});
})();
Esempio: estrai il <title>
della pagina utilizzando le API DOM.
const CDP = require('chrome-remote-interface');
...
(async function() {
const chrome = await launchChrome();
const protocol = await CDP({port: chrome.port});
// Extract the DevTools protocol domains we need and enable them.
// See API docs: https://chromedevtools.github.io/devtools-protocol/
const {Page, Runtime} = protocol;
await Promise.all([Page.enable(), Runtime.enable()]);
Page.navigate({url: 'https://www.chromestatus.com/'});
// Wait for window.onload before doing stuff.
Page.loadEventFired(async () => {
const js = "document.querySelector('title').textContent";
// Evaluate the JS expression in the page.
const result = await Runtime.evaluate({expression: js});
console.log('Title of page: ' + result.result.value);
protocol.close();
chrome.kill(); // Kill Chrome.
});
})();
Utilizzo di Selenium, WebDriver e ChromeDriver
Al momento, Selenium apre un'istanza completa di Chrome. In altre parole, si tratta di un soluzione automatizzata ma non completamente headless. Tuttavia, il selenio può essere configurato per eseguire Chrome headless con un po' di lavoro. Consiglio Usa Selenium con Headless Chrome se desideri istruzioni complete su come configurare le cose da solo, ma ho visto di seguito sono riportati alcuni esempi per iniziare.
Utilizzo di ChromeDriver
ChromeDriver 2.32 utilizza Chrome 61 e funziona bene con Chrome headless.
Installa:
npm i --save-dev selenium-webdriver chromedriver
Esempio:
const fs = require('fs');
const webdriver = require('selenium-webdriver');
const chromedriver = require('chromedriver');
const chromeCapabilities = webdriver.Capabilities.chrome();
chromeCapabilities.set('chromeOptions', {args: ['--headless']});
const driver = new webdriver.Builder()
.forBrowser('chrome')
.withCapabilities(chromeCapabilities)
.build();
// Navigate to google.com, enter a search.
driver.get('https://www.google.com/');
driver.findElement({name: 'q'}).sendKeys('webdriver');
driver.findElement({name: 'btnG'}).click();
driver.wait(webdriver.until.titleIs('webdriver - Google Search'), 1000);
// Take screenshot of results page. Save to disk.
driver.takeScreenshot().then(base64png => {
fs.writeFileSync('screenshot.png', new Buffer(base64png, 'base64'));
});
driver.quit();
Utilizzo di WebDriverIO
WebDriverIO è un'API di livello superiore oltre a Selenium WebDriver.
Installa:
npm i --save-dev webdriverio chromedriver
Esempio: filtrare le funzionalità CSS su chromestatus.com
const webdriverio = require('webdriverio');
const chromedriver = require('chromedriver');
const PORT = 9515;
chromedriver.start([
'--url-base=wd/hub',
`--port=${PORT}`,
'--verbose'
]);
(async () => {
const opts = {
port: PORT,
desiredCapabilities: {
browserName: 'chrome',
chromeOptions: {args: ['--headless']}
}
};
const browser = webdriverio.remote(opts).init();
await browser.url('https://www.chromestatus.com/features');
const title = await browser.getTitle();
console.log(`Title: ${title}`);
await browser.waitForText('.num-features', 3000);
let numFeatures = await browser.getText('.num-features');
console.log(`Chrome has ${numFeatures} total features`);
await browser.setValue('input[type="search"]', 'CSS');
console.log('Filtering features...');
await browser.pause(1000);
numFeatures = await browser.getText('.num-features');
console.log(`Chrome has ${numFeatures} CSS features`);
const buffer = await browser.saveScreenshot('screenshot.png');
console.log('Saved screenshot...');
chromedriver.stop();
browser.end();
})();
Ulteriori risorse
Ecco alcune risorse utili per iniziare:
Documenti
- Visualizzatore protocollo DevOps - Documenti di riferimento per le API
Strumenti
- chrome-remote-interface: nodo che aggrega il protocollo DevTools
- Lighthouse: strumento automatizzato per i test qualità delle app web; fa un uso intensivo del protocollo
- chrome-launcher - modulo nodo per il lancio di Chrome, pronto per l'automazione
Demo
- "Il web headless" - Il fantastico blog di Paul Kinlan sull'utilizzo di Headless con api.ai.
Domande frequenti
Devo avere il flag --disable-gpu
?
Solo su Windows. Non sono più richieste da altre piattaforme. Il flag --disable-gpu
è un
una soluzione temporanea per alcuni bug. Questo flag non sarà più necessario nelle versioni future di
Chrome. Visita la pagina crbug.com/737678
per ulteriori informazioni.
Quindi mi serve ancora Xvfb?
No. Chrome headless non utilizza una finestra, quindi un server di visualizzazione come Xvfb è non serve più. Puoi eseguire senza problemi i tuoi test automatici.
Che cos'è Xvfb? Xvfb è un server di visualizzazione in memoria per sistemi simili a Unix che consente per eseguire applicazioni grafiche (come Chrome) senza un display fisico collegato. Molte persone usano Xvfb per eseguire versioni precedenti di Chrome con il comando "headless" test.
Come faccio a creare un container Docker che esegue Chrome headless?
Visita il sito Lighthouse-ci. Ha un
Dockerfile di esempio
che utilizza node:8-slim
come immagine di base, installa +
runs Lighthouse
su App Engine Flex.
Posso utilizzare Selenium / WebDriver / ChromeDriver?
Sì. Consulta Utilizzare Selenium, WebDriver e ChromeDriver.
Qual è la relazione con PhantomJS?
Chrome headless è simile a strumenti come PhantomJS. Entrambi può essere utilizzata per test automatici in un ambiente headless. La differenza principale tra i due è che Phantom utilizza una versione precedente di WebKit come rendering mentre Chrome headless usa l'ultima versione di Blink.
Al momento, Phantom fornisce anche un'API di livello superiore rispetto al protocollo DevTools.
Dove posso segnalare i bug?
I bug relativi a Chrome headless sono disponibili su crbug.com.
In caso di bug nel protocollo DevTools, segnalali all'indirizzo github.com/ChromeDevTools/devtools-protocol.