Texto longo, leia o resumo
Chrome sem comando está disponível no Chrome 59. É uma forma de executar o navegador Chrome em um ambiente headless. Essencialmente, executar Chrome sem o Chrome! Ele oferece todos os recursos modernos da plataforma da Web, pelo Chromium e pelo mecanismo de renderização Blink à linha de comando.
Por que isso é útil?
Um navegador sem comando é uma ótima ferramenta para testes automatizados e ambientes de servidor não precisam de um shell de interface visível. Por exemplo, talvez você queira executar alguns testes no uma página da Web real, criar um PDF ou simplesmente analisar como o navegador renderiza um URL.
Como iniciar sem comando (CLI)
A maneira mais fácil de começar a usar o modo headless é abrir o binário do Chrome
na linha de comando. Se você tiver o Chrome 59 ou superior instalado, inicie-o com a sinalização --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 apontar para sua instalação do Chrome. O local exato
de plataforma para plataforma. Como estou no Mac, criei aliases convenientes
para cada versão do Chrome que instalei.
Se você estiver no Canal Stable do Chrome e não conseguir a versão Beta, recomendamos
usando 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 de linha de comando
Em alguns casos, pode não ser necessário criar um script de programação headless do Chrome. Há algumas sinalizações de linha de comando úteis para realizar tarefas comuns.
Como imprimir o DOM
A flag --dump-dom
imprime document.body.innerHTML
em stdout:
chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/
Criar um PDF
A sinalização --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 sinalização --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
produzirá um arquivo chamado screenshot.png
no
diretório de trabalho atual. Se você está procurando capturas de tela de página inteira,
estão um pouco mais envolvidos. Temos um ótimo blog
de David Schnurr que explica tudo. Finalizar compra
Usar a versão headless do Chrome como uma ferramenta automatizada de captura de tela .
Modo REPL (loop de leitura-avaliação-impressão)
A flag --repl
é executada sem comando 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
$
Depurando o Chrome sem uma interface de usuário do navegador?
Quando você executa o Chrome com o --remote-debugging-port=9222
, ele inicia uma instância
com o protocolo DevTools ativado. A
é usado para se comunicar com o Chrome e conduzir a conexão
do navegador. Ele também é usado por ferramentas como Sublime, VS Code e Node
a depuração remota de um aplicativo. #synergy
Como você não tem a interface do navegador para acessar a página, acesse http://localhost:9222
em outro navegador para verificar se está tudo funcionando. Você verá uma lista de
páginas inspecionáveis, onde você pode clicar e ver o que o headless está renderizando:
A partir daqui, você pode usar os recursos conhecidos do DevTools para inspecionar, depurar e ajustar na página como faria normalmente. Se você usar o Headless programaticamente, ele também é uma ferramenta de depuração poderosa para ver todo o protocolo bruto do DevTools que passam pela rede, comunicando-se com o navegador.
Como usar programaticamente (Node)
Animador de fantoches
Puppeteer é uma biblioteca de nós. desenvolvida pela equipe do Chrome. Ele fornece uma API de alto nível para controlar (ou versão completa) do Chrome. É semelhante a outras bibliotecas de teste automatizadas, como a Phantom e NightmareJS, mas só funciona com as versões mais recentes do Chrome.
Entre outras coisas, o Puppeteer pode ser usado para facilmente fazer capturas de tela, criar PDFs, navegar pelas páginas e buscar informações sobre elas. Recomendo a biblioteca se quiser automatizar rapidamente o teste do navegador. Ele esconde as complexidades do protocolo 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 (em inglês) para saber mais sobre a API completa.
Biblioteca CRI
chrome-remote-interface é uma biblioteca de nível inferior à API do Puppeteer. Eu recomendo se você quiser ser perto do metal e usar o protocolo DevTools diretamente.
Iniciando o Chrome
O Chrome-remote-interface não inicia o Chrome para você, então você terá que e cuidar disso sozinho.
Na seção da CLI, iniciamos o Chrome manualmente usando
--headless --remote-debugging-port=9222
No entanto, para automatizar totalmente os testes, você provavelmente
querem gerar o Chrome a partir 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ários plataformas. Veja o caminho codificado para o Chrome :(
Como usar o ChromeLauncher
O Lighthouse é um ambiente maravilhoso
para testar a qualidade dos seus apps da Web. Um módulo avançado para lançamento
O Chrome foi desenvolvido no Lighthouse e agora é extraído para uso independente.
O módulo chrome-launcher
do NPM
vai encontrar onde
O Chrome está instalado. Configure uma instância de depuração, inicie o navegador e elimine-o
quando o programa for concluído. A melhor parte é que ele funciona em várias plataformas, graças à
Nó!
Por padrão, chrome-launcher
tentará iniciar o Chrome Canary (se for
instalado), mas você pode mudar isso para selecionar manualmente qual Chrome usar. Para
Use-o. Primeiro, instale pelo npm:
npm i --save chrome-launcher
Exemplo: como usar chrome-launcher
para iniciar a versã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();
});
A execução desse script não adianta muitas coisas, mas você verá uma instância do
O Chrome foi iniciado no gerenciador de tarefas que carregou about:blank
. Lembre-se, há
não haverá nenhuma interface de navegador. Não temos cabeça.
Para controlar o navegador, precisamos do protocolo DevTools!
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 será algo como: HeadlessChrome/60.0.3082.0
Exemplo: verificar se o site tem um manifesto de 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 as 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, WebDriver e ChromeDriver
No momento, o Selenium abre uma instância completa do Chrome. Em outras palavras, é um automatizada, mas não completamente headless. No entanto, o selênio pode ser configurado para executar a versão headless do Chrome com um pouco de trabalho. Eu recomendo Como executar o Selenium com o Headless Chrome se você quiser que instruções completas sobre como fazer a configuração por conta própria, mas também mostrei algumas abaixo para você começar.
Como usar o ChromeDriver
ChromeDriver 2.32 usa o Chrome 61 e funciona bem com a versão headless do Chrome.
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
A WebDriverIO é uma API de nível superior, além do Selenium WebDriver.
Instalar:
npm i --save-dev webdriverio chromedriver
Exemplo: filtrar recursos CSS em 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
Aqui estão alguns recursos úteis para você começar:
Documentos
- Leitor do protocolo do DevTools: documentos de referência da API
Ferramentas
- chrome-remote-interface: nó que encapsula o protocolo DevTools
- Lighthouse: ferramenta automatizada para testes. qualidade de apps 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 (link em inglês) - Excelente blog de Paul Kinlan publicarmos sobre o uso do Headless com o api.ai.
Perguntas frequentes
A flag --disable-gpu
é necessária?
Só no Windows. Ele não é mais necessário em outras plataformas. A sinalização --disable-gpu
é uma
uma solução temporária para alguns bugs. Essa flag não será necessária em versões futuras do
Chrome. Consulte crbug.com/737678
para mais informações.
Ainda preciso do Xvfb?
Não. O Headless Chrome não usa uma janela, então um servidor de exibição como o Xvfb é não são mais necessários. Você pode executar seus testes automatizados sem ele.
O que é Xvfb? O Xvfb é um servidor de exibição na memória para sistemas do tipo Unix que permite para executar aplicativos gráficos (como o Chrome) sem uma tela física conectada. Muitas pessoas usam o Xvfb para executar versões anteriores do Chrome para fazer a verificação sem comando testes.
Como faço para criar um contêiner do Docker que execute o Headless Chrome?
Confira o relatório Lighthouse-ci. Ele tem um
exemplo de Dockerfile
que usa node:8-slim
como imagem de base, as instalações +
executa o Lighthouse
no App Engine Flex.
Posso usá-lo com Selenium / WebDriver / ChromeDriver?
Sim. Consulte Como usar o Selenium, WebDriver e ChromeDriver.
Qual é a relação com o PhantomJS?
A headless Chrome é semelhante a ferramentas como o PhantomJS. Ambos podem ser usadas para testes automatizados em um ambiente sem comando. A principal diferença entre os dois é que o Phantom usa uma versão mais antiga do WebKit como sua renderização Engine, enquanto o Headless Chrome usa a versão mais recente do Blink.
No momento, o Phantom também oferece uma API de nível superior ao protocolo DevTools.
Onde informo bugs?
Informe bugs do Headless Chrome em crbug.com (link em inglês).
Registre bugs no protocolo DevTools em github.com/ChromeDevTools/devtools-protocol (link em inglês).