A modo de resumen
Chrome sin interfaz gráfica se envía en Chrome 59. Es una forma de ejecutar el navegador Chrome en un entorno sin interfaz gráfica. Básicamente, ejecuta Chrome sin Chrome. Ofrece todas las funciones modernas de la plataforma web que proporciona Chromium y el motor de renderización Blink a la línea de comandos.
¿Por qué es útil?
Un navegador sin interfaz gráfica es una excelente herramienta para pruebas automatizadas y entornos de servidor en los que no necesitas un shell de IU visible. Por ejemplo, es posible que desees ejecutar algunas pruebas en una página web real, crear un PDF de ella o simplemente inspeccionar cómo el navegador renderiza una URL.
Cómo iniciar sin interfaz gráfica (CLI)
La forma más fácil de comenzar a usar el modo sin interfaz gráfica es abrir el objeto binario de Chrome desde la línea de comandos. Si tienes instalado Chrome 59 o versiones posteriores, inícialo con la marca --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
debería apuntar a tu instalación de Chrome. La ubicación exacta variará de una plataforma a otra. Como uso una Mac, creé alias convenientes para cada versión de Chrome que instalé.
Si usas el canal estable de Chrome y no puedes obtener la versión beta, te recomiendo que uses 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"
Descarga Chrome Canary aquí.
Funciones de la línea de comandos
En algunos casos, es posible que no debas escribir una secuencia de comandos de forma programática para Chrome sin cabeza. Hay algunas marcas de línea de comandos útiles para realizar tareas comunes.
Cómo imprimir el DOM
La marca --dump-dom
imprime document.body.innerHTML
en stdout:
chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/
Cómo crear un PDF
La marca --print-to-pdf
crea un PDF de la página:
chrome --headless --disable-gpu --print-to-pdf https://www.chromestatus.com/
Toma capturas de pantalla
Para capturar una captura de pantalla de una página, usa la marca --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/
Si se ejecuta con --screenshot
, se generará un archivo llamado screenshot.png
en el directorio de trabajo actual. Si buscas capturas de pantalla de página completa, el proceso es un poco más complejo. David Schnurr escribió una gran entrada de blog que te ayudará. Consulta Cómo usar Chrome sin cabeza como herramienta de captura de pantalla automatizada .
Modo REPL (bucle de lectura, evaluación e impresión)
La marca --repl
ejecuta Headless en un modo en el que puedes evaluar expresiones JS en el navegador, directamente desde la línea de comandos:
$ 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
$
¿Quieres depurar Chrome sin una IU del navegador?
Cuando ejecutas Chrome con --remote-debugging-port=9222
, se inicia una instancia con el protocolo de DevTools habilitado. El protocolo se usa para comunicarse con Chrome y controlar la instancia del navegador sin interfaz gráfica. También es lo que usan herramientas como Sublime, VS Code y Node para la depuración remota de una aplicación. #synergy
Como no tienes la IU del navegador para ver la página, navega a http://localhost:9222
en otro navegador para verificar que todo funcione. Verás una lista de páginas inspeccionables en las que puedes hacer clic para ver qué renderiza Headless:
Desde aquí, puedes usar las funciones conocidas de DevTools para inspeccionar, depurar y ajustar la página como lo harías normalmente. Si usas Headless de forma programática, esta página también es una herramienta de depuración potente para ver todos los comandos sin procesar del protocolo de DevTools que se transmiten y se comunican con el navegador.
Uso programático (Node)
Titiritero
Puppeteer es una biblioteca de Node que desarrolló el equipo de Chrome. Proporciona una API de alto nivel para controlar Chrome sin interfaz gráfica (o completa). Es similar a otras bibliotecas de pruebas automatizadas, como Phantom y NightmareJS, pero solo funciona con las versiones más recientes de Chrome.
Entre otras cosas, Puppeteer se puede usar para tomar capturas de pantalla fácilmente, crear archivos PDF, navegar por páginas y recuperar información sobre ellas. Te recomiendo la biblioteca si quieres automatizar rápidamente las pruebas del navegador. Oculta las complejidades del protocolo de DevTools y se encarga de las tareas redundantes, como iniciar una instancia de depuración de Chrome.
Instálalo:
npm i --save puppeteer
Ejemplo: Imprime el usuario-agente.
const puppeteer = require('puppeteer');
(async() => {
const browser = await puppeteer.launch();
console.log(await browser.version());
await browser.close();
})();
Ejemplo: Tomar una captura de pantalla de la página
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 documentación de Puppeteer para obtener más información sobre la API completa.
La biblioteca de CRI
chrome-remote-interface es una biblioteca de nivel inferior que la API de Puppeteer. Te lo recomiendo si quieres estar más cerca del metal y usar el protocolo de DevTools directamente.
Cómo iniciar Chrome
chrome-remote-interface no inicia Chrome por ti, por lo que deberás hacerlo tú mismo.
En la sección de la CLI, iniciamos Chrome de forma manual con --headless --remote-debugging-port=9222
. Sin embargo, para automatizar las pruebas por completo, es probable que desees crear Chrome desde tu aplicación.
Una forma es usar 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) => {
...
});
Sin embargo, las cosas se complican si quieres una solución portátil que funcione en varias plataformas. Mira esa ruta de acceso fija a Chrome :(
Cómo usar ChromeLauncher
Lighthouse es una herramienta maravillosa para probar la calidad de tus apps web. Se desarrolló un módulo sólido para iniciar Chrome en Lighthouse y ahora se extrae para uso independiente.
El módulo NPM chrome-launcher
encontrará dónde está instalado Chrome, configurará una instancia de depuración, iniciará el navegador y lo finalizará cuando termine tu programa. La mejor parte es que funciona en varias plataformas gracias a Node.
De forma predeterminada, chrome-launcher
intentará iniciar Chrome Canary (si está instalado), pero puedes cambiarlo para seleccionar manualmente qué Chrome usar. Para usarlo, primero instálalo desde npm:
npm i --save chrome-launcher
Ejemplo: Usa chrome-launcher
para iniciar 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();
});
Ejecutar esta secuencia de comandos no hace mucho, pero deberías ver que se inicia una instancia de Chrome en el Administrador de tareas que cargó about:blank
. Recuerda que no
habrá ninguna IU del navegador. No tenemos interfaz gráfica.
Para controlar el navegador, necesitamos el protocolo de DevTools.
Cómo recuperar información sobre la página
Instalemos la biblioteca:
npm i --save chrome-remote-interface
Ejemplos
Ejemplo: Imprime el usuario-agente.
const CDP = require('chrome-remote-interface');
...
launchChrome().then(async chrome => {
const version = await CDP.Version({port: chrome.port});
console.log(version['User-Agent']);
});
Da un resultado similar al siguiente: HeadlessChrome/60.0.3082.0
Ejemplo: Verifica si el sitio tiene un manifiesto de 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.
});
})();
Ejemplo: Extrae el <title>
de la página con las APIs de 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.
});
})();
Cómo usar Selenium, WebDriver y ChromeDriver
En este momento, Selenium abre una instancia completa de Chrome. En otras palabras, es una solución automatizada, pero no completamente sin interfaz gráfica. Sin embargo, Selenium se puede configurar para ejecutar Chrome sin cabeza con un poco de trabajo. Te recomiendo que ejecutes Selenium con Chrome sin cabeza si quieres obtener instrucciones completas para configurarlo por tu cuenta, pero aquí tienes algunos ejemplos para comenzar.
Cómo usar ChromeDriver
ChromeDriver 2.32 usa Chrome 61 y funciona bien con Chrome sin interfaz gráfica.
Instala:
npm i --save-dev selenium-webdriver chromedriver
Ejemplo:
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();
Cómo usar WebDriverIO
WebDriverIO es una API de nivel superior basada en Selenium WebDriver.
Instala:
npm i --save-dev webdriverio chromedriver
Ejemplo: Filtra funciones de CSS en 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();
})();
Más recursos
Estos son algunos recursos útiles para comenzar:
Documentos
- Visualizador de protocolos de DevTools: Documentos de referencia de la API
Herramientas
- chrome-remote-interface: Es un módulo de nodo que une el protocolo de DevTools.
- Lighthouse: Herramienta automatizada para probar la calidad de las apps web; hace un uso intensivo del protocolo.
- chrome-launcher: módulo de nodo para iniciar Chrome, listo para la automatización
Demostraciones
- "The Headless Web": Una excelente entrada de blog de Paul Kinlan sobre el uso de Headless con api.ai.
Preguntas frecuentes
¿Necesito la marca --disable-gpu
?
Solo en Windows. Otras plataformas ya no lo requieren. La marca --disable-gpu
es una solución temporal para algunos errores. No necesitarás esta marca en versiones futuras de Chrome. Consulta crbug.com/737678 para obtener más información.
¿Debo seguir usando Xvfb?
No. Chrome sin cabeza no usa una ventana, por lo que ya no se necesita un servidor de visualización como Xvfb. Puedes ejecutar tus pruebas automatizadas sin él.
¿Qué es Xvfb? Xvfb es un servidor de pantalla en memoria para sistemas similares a Unix que te permite ejecutar aplicaciones gráficas (como Chrome) sin una pantalla física conectada. Muchas personas usan Xvfb para ejecutar versiones anteriores de Chrome y realizar pruebas "sin interfaz gráfica".
¿Cómo creo un contenedor de Docker que ejecute Chrome sin interfaz gráfica?
Consulta lighthouse-ci. Tiene un Dockerfile de ejemplo que usa node:8-slim
como imagen base, instala y ejecuta Lighthouse en App Engine Flex.
¿Puedo usar esto con Selenium, WebDriver o ChromeDriver?
Sí. Consulta Cómo usar Selenium, WebDriver y ChromeDriver.
¿Cómo se relaciona esto con PhantomJS?
Chrome sin interfaz gráfica es similar a herramientas como PhantomJS. Ambos se pueden usar para pruebas automatizadas en un entorno sin cabeza. La principal diferencia entre ambos es que Phantom usa una versión anterior de WebKit como motor de renderización, mientras que Chrome sin interfaz gráfica usa la versión más reciente de Blink.
Por el momento, Phantom también proporciona una API de nivel superior que el protocolo de DevTools.
¿Dónde puedo informar errores?
Si se trata de errores relacionados con Chrome sin interfaz gráfica, envíalos a crbug.com.
Si encuentras errores en el protocolo de DevTools, envíalos a github.com/ChromeDevTools/devtools-protocol.