Texto longo, leia o resumo
O Chrome Headless está sendo enviado no Chrome 59. É uma maneira de executar o navegador Chrome em um ambiente sem servidor. Basicamente, executar o Chrome sem o Chrome! Ele traz todos os recursos modernos da plataforma da Web fornecidos pelo Chromium e pelo mecanismo de renderização Blink para a linha de comando.
Por que isso é útil?
Um navegador sem cabeça é uma ótima ferramenta para testes automatizados e ambientes de servidor em que você não precisa de um shell de interface visível. Por exemplo, você pode executar alguns testes em uma página da Web real, criar um PDF dela ou apenas inspecionar como o navegador renderiza um URL.
Como iniciar o modo headless (CLI)
A maneira mais fácil de começar a usar o modo sem cabeça é abrir o binário do Chrome
na linha de comando. Se você tiver o Chrome 59 ou mais recente instalado, inicie o Chrome com a 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.
O chrome
precisa apontar para a instalação do Chrome. O local exato vai
variar de acordo com a plataforma. Como estou usando um Mac, criei aliases convenientes
para cada versão do Chrome que instalei.
Se você estiver no canal estável do Chrome e não conseguir usar a versão Beta, recomendamos
usar 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"
Faça o download do Chrome Canary aqui.
Recursos da linha de comando
Em alguns casos, talvez não seja necessário criar um script de forma programática para o Chrome Headless. Há algumas flags de linha de comando úteis para realizar tarefas comuns.
Como imprimir o DOM
A flag --dump-dom
imprime document.body.innerHTML
no stdout:
chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/
Criar um PDF
A flag --print-to-pdf
cria um PDF da página:
chrome --headless --disable-gpu --print-to-pdf https://www.chromestatus.com/
Como fazer capturas de tela
Para fazer uma captura de tela de uma página, use a 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/
A execução com --screenshot
vai produzir um arquivo chamado screenshot.png
no
diretório de trabalho atual. Se você estiver procurando capturas de tela de página inteira, as coisas
são um pouco mais complicadas. Há uma ótima postagem
de blog de David Schnurr que pode ajudar. Confira
Como usar o Chrome sem cabeça como uma ferramenta de captura de tela automatizada .
Modo REPL (loop de leitura-avaliação-impressão)
A flag --repl
executa o modo Headless em um modo em que é possível avaliar expressões JS
no navegador, diretamente na linha de 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
$
Como depurar o Chrome sem uma interface do navegador?
Quando você executa o Chrome com --remote-debugging-port=9222
, ele inicia uma instância
com o protocolo DevTools ativado. O
protocolo é usado para se comunicar com o Chrome e direcionar a instância
do navegador sem cabeça. É também o que ferramentas como Sublime, VS Code e Node usam para
depurar remotamente um aplicativo. #synergy
Como você não tem a interface do navegador para ver a página, navegue até http://localhost:9222
em outro navegador para verificar se tudo está funcionando. Você vai encontrar uma lista de
páginas inspecionáveis em que é possível clicar e conferir o que o Headless está renderizando:
A partir daqui, você pode usar os recursos conhecidos do DevTools para inspecionar, depurar e ajustar a página normalmente. Se você estiver usando o Headless de forma programática, essa página também é uma ferramenta de depuração poderosa para conferir todos os comandos brutos do protocolo do DevTools que passam pela rede, se comunicando com o navegador.
Como usar de forma programática (Node)
Animador de fantoches
O Puppeteer (em inglês) é uma biblioteca do Node.js desenvolvida pela equipe do Chrome. Ele fornece uma API de alto nível para controlar o Chrome (ou completo) sem cabeça. Ela é semelhante a outras bibliotecas de testes automatizados, como Phantom e NightmareJS, mas só funciona com as versões mais recentes do Chrome.
Entre outras coisas, o Puppeteer pode ser usado para fazer capturas de tela, criar PDFs, navegar por páginas e buscar informações sobre elas. Recomendo a biblioteca se você quiser automatizar rapidamente os testes do navegador. Ele oculta as complexidades do protocolo do DevTools e cuida de tarefas redundantes, como iniciar uma instância de depuração do Chrome.
Instale:
npm i --save puppeteer
Exemplo: imprimir o user agent
const puppeteer = require('puppeteer');
(async() => {
const browser = await puppeteer.launch();
console.log(await browser.version());
await browser.close();
})();
Exemplo: fazer uma captura de tela da 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();
})();
Confira a documentação do Puppeteer para saber mais sobre a API completa.
Biblioteca CRI
chrome-remote-interface é uma biblioteca de nível inferior à API do Puppeteer. Eu recomendo isso se você quiser estar perto do metal e usar o protocolo do DevTools diretamente.
Como iniciar o Chrome
A chrome-remote-interface não inicia o Chrome para você. Portanto, você precisa fazer isso por conta própria.
Na seção da CLI, iniciamos o Chrome manualmente usando
--headless --remote-debugging-port=9222
. No entanto, para automatizar totalmente os testes, é recomendável
gerar o Chrome do seu aplicativo.
Uma maneira é 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) => {
...
});
Mas as coisas ficam complicadas se você quer uma solução portátil que funcione em várias plataformas. Olhe esse caminho codificado para o Chrome :(
Como usar o ChromeLauncher
O Lighthouse é uma ferramenta
maravilhosa para testar a qualidade dos seus apps da Web. Um módulo robusto para iniciar
o Chrome foi desenvolvido no Lighthouse e agora é extraído para uso independente.
O módulo NPM chrome-launcher
vai encontrar onde
o Chrome está instalado, configurar uma instância de depuração, iniciar o navegador e encerrar
quando o programa terminar. A melhor parte é que ele funciona em várias plataformas, graças ao
Node.
Por padrão, o chrome-launcher
tenta iniciar o Chrome Canary (se ele estiver
instalado), mas você pode mudar isso para selecionar manualmente qual Chrome usar. Para
usá-lo, primeiro instale pelo npm:
npm i --save chrome-launcher
Exemplo: como usar chrome-launcher
para iniciar o 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();
});
Executar esse script não faz muito, mas você verá uma instância do
Chrome sendo iniciada no gerenciador de tarefas que carregou about:blank
. Não haverá
interface do navegador. Não temos cabeça.
Para controlar o navegador, precisamos do protocolo do DevTools.
Como recuperar informações sobre a página
Vamos instalar a biblioteca:
npm i --save chrome-remote-interface
Exemplos
Exemplo: imprimir o 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']);
});
O resultado é algo como: HeadlessChrome/60.0.3082.0
Exemplo: verifique se o site tem um manifesto do app da 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.
});
})();
Exemplo: extraia o <title>
da página usando APIs 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.
});
})();
Como usar o Selenium, o WebDriver e o ChromeDriver
No momento, o Selenium abre uma instância completa do Chrome. Em outras palavras, é uma solução automatizada, mas não totalmente sem servidor. No entanto, o Selenium pode ser configurado para executar o Chrome sem cabeça com um pouco de trabalho. Recomendamos Como executar o Selenium com o Chrome sem cabeça se você quiser instruções completas sobre como configurar tudo por conta própria. No entanto, incluímos alguns exemplos abaixo para você começar.
Como usar o ChromeDriver
O ChromeDriver 2.32 usa o Chrome 61 e funciona bem com o Chrome headless.
Instalar:
npm i --save-dev selenium-webdriver chromedriver
Exemplo:
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();
Como usar o WebDriverIO
O WebDriverIO é uma API de nível mais alto em cima do Selenium WebDriver.
Instalar:
npm i --save-dev webdriverio chromedriver
Exemplo: filtrar recursos de CSS no 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();
})();
Outros recursos
Confira alguns recursos úteis para começar:
Documentos
- Visualizador de protocolo do DevTools: documentos de referência da API
Ferramentas
- chrome-remote-interface: módulo de nó que envolve o protocolo do DevTools.
- Lighthouse: ferramenta automatizada para testar a qualidade do app da Web; faz uso intenso do protocolo
- chrome-launcher: módulo de nó para iniciar o Chrome, pronto para automação.
Demonstrações
- The Headless Web: ótimo post de Paul Kinlan sobre como usar o Headless com a api.ai.
Perguntas frequentes
Preciso da flag --disable-gpu
?
Somente no Windows. Outras plataformas não precisam mais disso. A flag --disable-gpu
é uma
solução temporária para alguns bugs. Você não vai precisar dessa flag em versões futuras do
Chrome. Consulte crbug.com/737678
para mais informações.
Então, ainda preciso do Xvfb?
Não. O Chrome sem cabeça não usa uma janela, então um servidor de exibição como Xvfb não é mais necessário. Você pode executar seus testes automatizados sem ele.
O que é Xvfb? O Xvfb é um servidor de exibição em memória para sistemas do tipo Unix que permite executar aplicativos gráficos (como o Chrome) sem uma tela física anexada. Muitas pessoas usam o Xvfb para executar versões anteriores do Chrome e fazer testes "headless".
Como faço para criar um contêiner do Docker que execute o Chrome sem cabeça?
Confira o lighthouse-ci. Ele tem um
exemplo de Dockerfile
que usa node:8-slim
como uma imagem de base, instala e
executa o Lighthouse
no App Engine Flex.
Posso usar isso com o Selenium / WebDriver / ChromeDriver?
Sim. Consulte Como usar o Selenium, o WebDriver e o ChromeDriver.
Como isso se relaciona com o PhantomJS?
O Chrome Headless é semelhante a ferramentas como o PhantomJS. Ambos podem ser usados para testes automatizados em um ambiente sem cabeça. A principal diferença entre os dois é que o Phantom usa uma versão mais antiga do WebKit como mecanismo de renderização, enquanto o Chrome Headless usa a versão mais recente do Blink.
No momento, o Phantom também oferece uma API de nível mais alto do que o protocolo DevTools.
Onde informo bugs?
Para bugs no Chrome Headless, envie-os em crbug.com.
Para bugs no protocolo do DevTools, registre-os em github.com/ChromeDevTools/devtools-protocol.