ТЛ;ДР
Безголовый Chrome поставляется в Chrome 59. Это способ запуска браузера Chrome в автономной среде. По сути, запуск Chrome без Chrome! Он переносит все современные функции веб-платформы, предоставляемые Chromium и механизмом рендеринга Blink, в командную строку.
Почему это полезно?
Безголовый браузер — отличный инструмент для автоматического тестирования и серверных сред, где вам не нужна видимая оболочка пользовательского интерфейса. Например, вы можете провести несколько тестов на реальной веб-странице, создать ее PDF-файл или просто проверить, как браузер отображает URL-адрес.
Запуск без головы (CLI)
Самый простой способ начать работу с безгласным режимом — открыть двоичный файл Chrome из командной строки. Если у вас установлен Chrome 59+, запустите Chrome с флагом --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
должен указывать на вашу установку Chrome. Точное местоположение будет варьироваться от платформы к платформе. Поскольку я использую Mac, я создал удобные псевдонимы для каждой установленной версии Chrome.
Если вы используете стабильную версию Chrome и не можете получить бета-версию, я рекомендую использовать 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"
Загрузите Chrome Canary здесь .
Возможности командной строки
В некоторых случаях вам может не потребоваться программное создание сценария Headless Chrome. Есть несколько полезных флагов командной строки для выполнения распространенных задач.
Печать DOM
Флаг --dump-dom
выводит document.body.innerHTML
на стандартный вывод:
chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/
Создать PDF-файл
Флаг --print-to-pdf
создает PDF-файл страницы:
chrome --headless --disable-gpu --print-to-pdf https://www.chromestatus.com/
Делаем скриншоты
Чтобы сделать снимок экрана страницы, используйте флаг --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/
Запуск с --screenshot
создаст файл с именем screenshot.png
в текущем рабочем каталоге. Если вам нужны скриншоты всей страницы, все немного сложнее. Есть отличная запись в блоге Дэвида Шнурра, в которой вы охвачены. Ознакомьтесь со статьей Использование Headless Chrome в качестве автоматического инструмента для создания снимков экрана .
Режим REPL (цикл чтения-оценки-печати)
Флаг --repl
запускает Headless в режиме, в котором вы можете оценивать выражения JS в браузере прямо из командной строки:
$ 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
$
Отладка Chrome без пользовательского интерфейса браузера?
Когда вы запускаете Chrome с --remote-debugging-port=9222
, он запускает экземпляр с включенным протоколом DevTools . Протокол используется для связи с Chrome и управления экземпляром автономного браузера. Это также то, что такие инструменты, как Sublime, VS Code и Node, используют для удаленной отладки приложения. #синергия
Поскольку у вас нет пользовательского интерфейса браузера для просмотра страницы, перейдите по адресу http://localhost:9222
в другом браузере, чтобы убедиться, что все работает. Вы увидите список доступных для проверки страниц, по которым вы можете щелкнуть и посмотреть, что визуализирует Headless:
Отсюда вы можете использовать знакомые функции DevTools для проверки, отладки и настройки страницы, как обычно. Если вы используете Headless программно, эта страница также является мощным инструментом отладки, позволяющим просматривать все необработанные команды протокола DevTools, передаваемые по сети и взаимодействующие с браузером.
Программное использование (Node)
Кукловод
Puppeteer — это библиотека Node, разработанная командой Chrome. Он предоставляет высокоуровневый API для управления безголовым (или полным) Chrome. Он похож на другие библиотеки автоматического тестирования, такие как Phantom и NightmareJS, но работает только с последними версиями Chrome.
Помимо прочего, Puppeteer можно использовать для легкого создания снимков экрана, создания PDF-файлов, навигации по страницам и получения информации об этих страницах. Рекомендую библиотеку, если вы хотите быстро автоматизировать тестирование браузера. Он скрывает сложности протокола DevTools и берет на себя выполнение избыточных задач, таких как запуск отладочного экземпляра Chrome.
Установите его:
npm i --save puppeteer
Пример — распечатать пользовательский агент
const puppeteer = require('puppeteer');
(async() => {
const browser = await puppeteer.launch();
console.log(await browser.version());
await browser.close();
})();
Пример — создание скриншота страницы
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();
})();
Ознакомьтесь с документацией Puppeteer, чтобы узнать больше о полном API.
Библиотека ЦНИИ
chrome-remote-interface — это библиотека более низкого уровня, чем API Puppeteer. Я рекомендую его, если вы хотите быть ближе к железу и напрямую использовать протокол DevTools .
Запуск Chrome
chrome-remote-interface не запускает Chrome автоматически, поэтому вам придется позаботиться об этом самостоятельно.
В разделе CLI мы запускали Chrome вручную, используя --headless --remote-debugging-port=9222
. Однако для полной автоматизации тестов вам, вероятно, захочется запустить Chrome из вашего приложения.
Один из способов — использовать 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) => {
...
});
Но все становится сложнее, если вам нужно портативное решение, работающее на нескольких платформах. Просто посмотрите на этот жестко запрограммированный путь к Chrome :(
Использование ChromeLauncher
Lighthouse — замечательный инструмент для тестирования качества ваших веб-приложений. В Lighthouse был разработан надежный модуль для запуска Chrome, который теперь извлечен для автономного использования. Модуль NPM chrome-launcher
найдет, где установлен Chrome, настроит экземпляр отладки, запустит браузер и закроет его, когда ваша программа будет завершена. Самое приятное то, что он работает кроссплатформенно благодаря Node!
По умолчанию chrome-launcher
попытается запустить Chrome Canary (если он установлен), но вы можете изменить это, чтобы вручную выбирать, какой Chrome использовать. Чтобы использовать его, сначала установите из npm:
npm i --save chrome-launcher
Пример – использование chrome-launcher
для запуска 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();
});
Запуск этого сценария мало что дает, но вы должны увидеть, как экземпляр Chrome запускается в диспетчере задач, который загружает about:blank
. Помните, что пользовательского интерфейса браузера не будет. Мы безголовые.
Для управления браузером нам понадобится протокол DevTools!
Получение информации о странице
Давайте установим библиотеку:
npm i --save chrome-remote-interface
Примеры
Пример — распечатать пользовательский агент
const CDP = require('chrome-remote-interface');
...
launchChrome().then(async chrome => {
const version = await CDP.Version({port: chrome.port});
console.log(version['User-Agent']);
});
Результат примерно такой: HeadlessChrome/60.0.3082.0
Пример : проверьте, есть ли на сайте манифест веб-приложения.
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.
});
})();
Пример : извлеките <title>
страницы с помощью 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.
});
})();
Использование Selenium, WebDriver и ChromeDriver
Прямо сейчас Selenium открывает полную версию Chrome. Другими словами, это автоматизированное решение, но не полностью безголовое. Однако Selenium можно настроить для запуска безголового Chrome, приложив немного усилий. Я рекомендую запустить Selenium с Headless Chrome, если вам нужны полные инструкции о том, как настроить все самостоятельно, но ниже я привел несколько примеров, чтобы вы могли начать.
Использование ChromeDriver
ChromeDriver 2.32 использует Chrome 61 и хорошо работает с Headless Chrome.
Установить:
npm i --save-dev selenium-webdriver chromedriver
Пример:
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();
Использование ВебДрайверИО
WebDriverIO — это API более высокого уровня поверх Selenium WebDriver.
Установить:
npm i --save-dev webdriverio chromedriver
Пример: фильтрация функций CSS на 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();
})();
Дополнительные ресурсы
Вот несколько полезных ресурсов, которые помогут вам начать:
Документы
- Средство просмотра протоколов DevTools — справочная документация по API
Инструменты
- chrome-remote-interface — модуль узла, который обертывает протокол DevTools
- Lighthouse — автоматизированный инструмент для тестирования качества веб-приложений; активно использует протокол
- chrome-launcher — нодовый модуль для запуска Chrome, готовый к автоматизации
Демо
- « The Headless Web » — отличная запись в блоге Пола Кинлана об использовании Headless с api.ai.
Часто задаваемые вопросы
Нужен ли мне флаг --disable-gpu
?
Только в Windows. Другие платформы больше не требуют этого. Флаг --disable-gpu
— это временное решение некоторых ошибок. Этот флаг вам не понадобится в будущих версиях Chrome. См. crbug.com/737678 для получения дополнительной информации.
Значит, мне все еще нужен Xvfb?
Нет. Безголовый Chrome не использует окна, поэтому сервер отображения, такой как Xvfb, больше не нужен. Вы можете с радостью запускать автоматизированные тесты и без него.
Что такое Xvfb? Xvfb — это сервер отображения в памяти для Unix-подобных систем, который позволяет запускать графические приложения (например, Chrome) без подключенного физического дисплея. Многие люди используют Xvfb для запуска более ранних версий Chrome и проведения «безголового» тестирования.
Как создать контейнер Docker, на котором будет работать Headless Chrome?
Проверьте маяк-ci . В нем есть пример Dockerfile , который использует node:8-slim
в качестве базового образа, устанавливает и запускает Lighthouse на App Engine Flex.
Могу ли я использовать это с Selenium/WebDriver/ChromeDriver ?
Да. См. Использование Selenium, WebDriver и ChromeDriver .
Как это связано с PhantomJS?
Headless Chrome похож на такие инструменты, как PhantomJS . Оба могут использоваться для автоматического тестирования в автономной среде. Основное различие между ними заключается в том, что Phantom использует более старую версию WebKit в качестве механизма рендеринга, а Headless Chrome использует последнюю версию Blink.
На данный момент Phantom также предоставляет API более высокого уровня, чем протокол DevTools .
Куда сообщать об ошибках?
Об ошибках в Headless Chrome сообщайте на crbug.com .
Об ошибках в протоколе DevTools сообщайте по адресу github.com/ChromeDevTools/devtools-protocol .