.
Kurzfassung
Headless Chrome ist in Chrome 59 verfügbar. Damit kann der Chrome-Browser in einer monitorlosen Umgebung ausgeführt werden. Im Grunde wird Chrome ohne Chrome ausgeführt. Es bietet alle modernen Webplattformfunktionen, die von Chromium und der Blink-Rendering-Engine bereitgestellt werden, in der Befehlszeile.
Warum ist das hilfreich?
Ein headless Browser ist ein hervorragendes Tool für automatisierte Tests und Serverumgebungen, in denen keine sichtbare UI-Shell erforderlich ist. Sie können beispielsweise einige Tests auf einer echten Webseite ausführen, eine PDF-Datei davon erstellen oder einfach prüfen, wie der Browser eine URL rendert.
Headless starten (Befehlszeile)
Am einfachsten starten Sie den headless-Modus, indem Sie die Chrome-Binärdatei über die Befehlszeile öffnen. Wenn Sie Chrome 59 oder höher installiert haben, starten Sie Chrome mit dem 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
sollte auf Ihre Chrome-Installation verweisen. Die genaue Position variiert je nach Plattform. Da ich einen Mac verwende, habe ich für jede installierte Chrome-Version praktische Aliasse erstellt.
Wenn Sie die stabile Version von Chrome verwenden und die Betaversion nicht erhalten können, empfehlen wir die Verwendung von 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"
Hier können Sie Chrome Canary herunterladen.
Befehlszeilenfunktionen
In einigen Fällen müssen Sie Headless Chrome möglicherweise nicht programmgesteuert scripten. Es gibt einige nützliche Befehlszeilen-Flags, um gängige Aufgaben auszuführen.
DOM drucken
Das Flag --dump-dom
gibt document.body.innerHTML
in stdout aus:
chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/
PDF erstellen
Das Flag --print-to-pdf
erstellt eine PDF-Datei der Seite:
chrome --headless --disable-gpu --print-to-pdf https://www.chromestatus.com/
Screenshots erstellen
Verwenden Sie das Flag --screenshot
, um einen Screenshot einer Seite aufzunehmen:
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/
Wenn Sie das Tool mit --screenshot
ausführen, wird im aktuellen Arbeitsverzeichnis eine Datei namens screenshot.png
erstellt. Wenn ihr nach ganzseitigen Screenshots sucht, ist die Sache etwas komplizierter. David Schnurr hat dazu einen sehr guten Blogpost verfasst. Weitere Informationen finden Sie unter Headless Chrome als automatisiertes Screenshot-Tool verwenden .
REPL-Modus (Read-Eval-Print-Loop)
Mit dem Flag --repl
wird Headless in einem Modus ausgeführt, in dem Sie JS-Ausdrücke direkt über die Befehlszeile im Browser auswerten können:
$ 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
$
Sie beheben Chrome ohne Browser-UI?
Wenn Sie Chrome mit --remote-debugging-port=9222
ausführen, wird eine Instanz mit aktiviertem DevTools-Protokoll gestartet. Das Protokoll wird verwendet, um mit Chrome zu kommunizieren und die Headless-Browserinstanz zu steuern. Außerdem wird es von Tools wie Sublime, VS Code und Node für das Remote-Debuggen einer Anwendung verwendet. #synergy
Da Sie keine Browseroberfläche haben, um die Seite zu sehen, rufen Sie http://localhost:9222
in einem anderen Browser auf, um zu prüfen, ob alles funktioniert. Es wird eine Liste der zu prüfenden Seiten angezeigt, durch die Sie sich klicken können, um zu sehen, was mit Headless gerendert wird:
Hier können Sie die bekannten DevTools-Funktionen verwenden, um die Seite wie gewohnt zu prüfen, zu debuggen und zu optimieren. Wenn Sie Headless programmatisch verwenden, ist diese Seite auch ein leistungsstarkes Debugging-Tool, mit dem alle unformatierten Entwicklertools-Protokollbefehle angezeigt werden, die mit dem Browser kommunizieren.
Programmatische Verwendung (Node)
Puppeteer
Puppeteer ist eine Node-Bibliothek, die vom Chrome-Team entwickelt wurde. Sie bietet eine High-Level-API zur Steuerung von headless (oder vollständigem) Chrome. Sie ähnelt anderen Bibliotheken für automatisierte Tests wie Phantom und NightmareJS, funktioniert aber nur mit den neuesten Versionen von Chrome.
Mit Puppeteer können Sie unter anderem ganz einfach Screenshots erstellen, PDFs erstellen, Seiten aufrufen und Informationen zu diesen Seiten abrufen. Ich empfehle die Bibliothek, wenn Sie Browsertests schnell automatisieren möchten. Es verbirgt die Komplexität des DevTools-Protokolls und übernimmt redundante Aufgaben wie das Starten einer Debug-Instanz von Chrome.
Installieren:
npm i --save puppeteer
Beispiel: User-Agent drucken
const puppeteer = require('puppeteer');
(async() => {
const browser = await puppeteer.launch();
console.log(await browser.version());
await browser.close();
})();
Beispiel: Screenshot der Seite erstellen
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();
})();
Weitere Informationen zur vollständigen API finden Sie in der Dokumentation zu Puppeteer.
CRI-Bibliothek
chrome-remote-interface ist eine Bibliothek auf niedrigerer Ebene als die API von Puppeteer. Ich empfehle es, wenn Sie direkt auf die Hardware zugreifen und das DevTools-Protokoll verwenden möchten.
Chrome starten
„chrome-remote-interface“ startet Chrome nicht für Sie, Sie müssen sich also selbst darum kümmern.
Im Abschnitt zur Befehlszeile haben wir Chrome manuell mit --headless --remote-debugging-port=9222
gestartet. Wenn Sie Tests jedoch vollständig automatisieren möchten, sollten Sie Chrome über Ihre Anwendung starten.
Eine Möglichkeit ist die Verwendung von 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) => {
...
});
Es wird jedoch schwierig, wenn Sie eine tragbare Lösung benötigen, die auf mehreren Plattformen funktioniert. Sehen Sie sich nur diesen hartcodierten Pfad zu Chrome an :(
ChromeLauncher verwenden
Lighthouse ist ein hervorragendes Tool zum Testen der Qualität Ihrer Webanwendungen. In Lighthouse wurde ein robustes Modul zum Starten von Chrome entwickelt, das jetzt für die eigenständige Verwendung extrahiert wird.
Das chrome-launcher
NPM-Modul ermittelt, wo Chrome installiert ist, richtet eine Debug-Instanz ein, startet den Browser und beendet ihn, wenn das Programm fertig ist. Das Beste daran ist, dass es dank Node!
plattformübergreifend funktioniert.
Standardmäßig versucht chrome-launcher
, Chrome Canary zu starten, sofern es installiert ist. Sie können dies jedoch ändern und manuell auswählen, welche Chrome-Version verwendet werden soll. Installieren Sie zuerst aus npm, um sie zu verwenden:
npm i --save chrome-launcher
Beispiel: Headless-Anwendung mit chrome-launcher
starten
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();
});
Das Ausführen dieses Scripts bewirkt nicht viel, aber im Task-Manager sollte eine Chrome-Instanz gestartet werden, die about:blank
geladen hat. Denken Sie daran, dass es keine Browseroberfläche gibt. Wir sind monitorlos.
Um den Browser zu steuern, benötigen wir das DevTools-Protokoll.
Informationen zur Seite abrufen
Installieren Sie die Bibliothek:
npm i --save chrome-remote-interface
Beispiele
Beispiel: User-Agent drucken
const CDP = require('chrome-remote-interface');
...
launchChrome().then(async chrome => {
const version = await CDP.Version({port: chrome.port});
console.log(version['User-Agent']);
});
Ergebnisse in etwa: HeadlessChrome/60.0.3082.0
Beispiel – Überprüfen Sie, ob die Website ein Web-App-Manifest hat.
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.
});
})();
Beispiel: <title>
der Seite mithilfe von DOM-APIs extrahieren
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 und ChromeDriver verwenden
Derzeit öffnet Selenium eine vollständige Instanz von Chrome. Mit anderen Worten: Es handelt sich um eine automatisierte Lösung, die aber nicht vollständig ohne Benutzeroberfläche auskommt. Selenium kann jedoch mit etwas Aufwand so konfiguriert werden, dass Chrome ohne Benutzeroberfläche ausgeführt wird. Ich empfehle Selenium mit monitorlosem Chrome ausführen, wenn Sie eine vollständige Anleitung zur Einrichtung selbst benötigen. Für den Einstieg finden Sie unten einige Beispiele.
ChromeDriver verwenden
ChromeDriver 2.32 verwendet Chrome 61 und funktioniert gut mit headless Chrome.
Installieren:
npm i --save-dev selenium-webdriver chromedriver
Beispiel:
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 verwenden
WebDriverIO ist eine API auf höherer Ebene, die auf Selenium WebDriver basiert.
Installieren:
npm i --save-dev webdriverio chromedriver
Beispiel: CSS-Funktionen auf chromestatus.com filtern
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();
})();
Weitere Ressourcen
Hier finden Sie einige hilfreiche Ressourcen für den Einstieg:
Docs
- DevTools Protocol Viewer – API-Referenzdokumentation
Tools
- chrome-remote-interface: Node-Modul, das das DevTools-Protokoll umschließt
- Lighthouse: automatisiertes Tool zum Testen der Qualität von Webanwendungen; verwendet das Protokoll intensiv
- chrome-launcher: Node-Modul zum Starten von Chrome, für Automatisierung geeignet
Demos
- The Headless Web: Paul Kinlans großer Blogpost zur Verwendung von Headless mit api.ai
FAQ
Benötige ich das Flag --disable-gpu
?
Nur unter Windows. Auf anderen Plattformen ist das nicht mehr erforderlich. Das Flag --disable-gpu
ist eine vorübergehende Problemumgehung für einige Programmfehler. In zukünftigen Versionen von Chrome ist dieses Flag nicht mehr erforderlich. Weitere Informationen finden Sie unter crbug.com/737678.
Benötige ich also weiterhin Xvfb?
Nein. Headless Chrome verwendet kein Fenster, sodass ein Displayserver wie Xvfb nicht mehr erforderlich ist. Sie können Ihre automatisierten Tests auch ohne diese Funktion ausführen.
Was ist Xvfb? Xvfb ist ein In-Memory-Displayserver für Unix-ähnliche Systeme, mit dem Sie grafische Anwendungen wie Chrome ohne angeschlossenes physisches Display ausführen können. Viele Nutzer verwenden Xvfb, um frühere Versionen von Chrome für "monitorlose" Tests auszuführen.
Wie erstelle ich einen Docker-Container, in dem Headless Chrome ausgeführt wird?
Dann sehen Sie sich lighthouse-ci an. Es enthält ein Beispiel-Dockerfile, das node:8-slim
als Basis-Image verwendet, Lighthouse in App Engine Flex installiert und ausführt.
Kann ich das mit Selenium, WebDriver oder ChromeDriver verwenden?
Ja. Weitere Informationen finden Sie unter Selenium, WebDriver und ChromeDriver verwenden.
Was hat das mit PhantomJS zu tun?
Headless Chrome ähnelt Tools wie PhantomJS. Beide können für automatisierte Tests in einer headless-Umgebung verwendet werden. Der Hauptunterschied zwischen den beiden besteht darin, dass Phantom eine ältere Version von WebKit als Rendering-Engine verwendet, während Headless Chrome die neueste Version von Blink verwendet.
Derzeit bietet Phantom auch eine API auf höherer Ebene als das DevTools-Protokoll.
Wo kann ich Fehler melden?
Melden Sie Fehler in Headless Chrome unter crbug.com.
Fehler im Entwicklertools-Protokoll können Sie unter github.com/ChromeDevTools/devtools-protocol melden.