What is Headless Chrome

Headless Chrome is a feature-free version of the Chrome browser that allows you to run applications using all of Chrome’s supported features without opening the browser. Compared to modern browsers, Headless Chrome makes it easier to test web applications, take screenshots of websites, and crawl information. Compared to PhantomJS and SlimerJS, Headless Chrome is much closer to the browser environment.

How to get Headless Chrome

Headless is now available in Chrome 59 Beta for Mac and Chrome 57+ for Linux. Chrome Canary 60 is not currently supported on Windows, but you can use Chrome Canary 60 to develop.

How to use it in terminal

You are advised to bind the Chrome alias before using it on a Mac

alias google-chrome="/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome"
Copy the code

In Linux, you do not need to bind an alias. Download the latest version of Chrome from the official website and run the following command.

google-chrome --headless --disable-gpu --remote-debugging-port=9222  https://github.com
Copy the code

The — disable-GPU was added mainly to block errors that might trigger at this stage.

http://localhost:9222

In the terminal, we can also do the following operations:

Get screen shots:

Google-chrome --headless --disable -- gpu --screenshot --window-size=1280,1696 https://github.comCopy the code

Obtain the page as PDF:

google-chrome --headless --disable-gpu --print-to-pdf https://github.com
Copy the code

Print page DOM:

google-chrome --headless --disable-gpu --dump-dom https://github.com/
Copy the code

The remote control

Start Headless Chrome with a terminal command as described above. Here is an example of how to control Headless Chrome in an application.

Install dependencies

npm install lighthouse chrome-remote-interface --save
Copy the code

chrome-remote-interface

const { ChromeLauncher } = require('lighthouse/lighthouse-cli/chrome-launcher') const chrome = require('chrome-remote-interface') const fs = require('fs') const deviceMetrics = { width: 1200, height: 800, deviceScaleFactor: 0, mobile: false, fitWindow: false } const screenshotMetrics = { width: deviceMetrics.width, height: deviceMetrics.height } let protocol let launcher function launchChrome () { const launcher = new ChromeLauncher({ port: 9222, autoSelectChrome: true, additionalFlags: [' -- window - size = 412732 ', '- disable - the gpu, '--headless'] }) return launcher.run().then(() => launcher) } function getScreenShot () { const { Page, Emulation} = protocol return Page. The enable (), then (() = > {Emulation. SetDeviceMetricsOverride (deviceMetrics)/size/browser configuration SetVisibleSize (screenshotMetrics) // Set screen size Page. Navigate ({url: 'https://github.com/' }) return new Promise((resolve, reject) => { Page.loadEventFired(() => { resolve(Page.captureScreenshot({ format: 'jpeg', fromSurface: true })) }) }) }) .then(image => { const buffer = new Buffer(image.data, 'base64') return new Promise((resolve, reject) => { fs.writeFile('output.jpeg', buffer, 'base64', err => { if (err) return reject(err) resolve() }) }) }) } launchChrome() .then(Launcher => { launcher = Launcher return new Promise((resolve, reject) =>{ chrome(Protocol => { protocol = Protocol resolve() }).on('error', err => { reject(err) }) }) }) .then(getScreenShot) .then(() => { protocol.close() launcher.kill() }) .catch(console.error)Copy the code

You use the ChromeLauncher module provided by Lighthouse to call Chrome, and if you have Chrome Canary installed on your computer, Lighthouse will start Chrome Canary by default, You can set autoSelectChrome to false and choose which version to use.


We can do even more with Chrome-remote-Interface with Headless Chrome.

Using CSS and DOM modules, you can get and set DOM node content and CSS styles in a page.

function getStyle () {
  const { Page, CSS, DOM } = protocol
  return Promise.all([
      DOM.enable(),
      CSS.enable(),
      Page.enable()
    ])
    .then(() => {
      Page.navigate({ url: 'https://github.com/' })
      return new Promise((resolve, _) => {
        Page.loadEventFired(() => { resolve(DOM.getDocument()) })
      })
    })
    .then(res => res.root.nodeId)
    .then(nodeId => DOM.querySelector({ selector: '.btn-primary', nodeId }))
    .then(({ nodeId }) => CSS.getComputedStyleForNode({ nodeId }))
    .then(style => { console.log(style) })
}
Copy the code

Using the Runtime module, you can execute JS scripts while the page is running.

function search () { const { Page, Runtime } = protocol return Promise.all([ Page.enable() ]) .then(() => { Page.navigate({ url: 'https://www.baidu.com/' }) return new Promise((resolve, _) => { Page.loadEventFired(() => { resolve() }) }) }) .then(() => { const code = [ 'var input = document.querySelector(\'.s_ipt\')', 'var btn = document.querySelector(\'#su\')', 'input.value=\'123\'' ].join('; ') return Runtime.evaluate({ expression: code }) }) .then(() => { return new Promise((resolve, _) => { setTimeout(() => { resolve(Page.captureScreenshot({ format: 'jpeg', fromSurface: true })) }, 3000) }) }) .then(image => { const buffer = new Buffer(image.data, 'base64') return new Promise((resolve, reject) => { fs.writeFile('output.jpeg', buffer, 'base64', err => { if (err) return reject(err) resolve() }) }) }) }Copy the code

Using the Network module, you can read and set information such as UserAgent and Cookie.

function setUAandCookie () { const { Page, Network } = protocol return Promise.all([ Network.enable(), Page. The enable () "). Then (() = > {const userAgent = Network. SetUserAgentOverride ({userAgent, "Mozilla / 5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, Like Gecko) Chrome/59.0.3071.71 Safari/537.36"}) net.setcookie ({url: 'https://github.com', name: 'test', value: '123', domain: '.github.com', path: '/', httpOnly: true }) Page.navigate({ url: 'https://github.com/' }) return new Promise((resolve, _) => { Page.loadEventFired(() => { resolve() }) }) }) .then(() => { return Network.getCookies() }) .then(console.log) }Copy the code

Use Headless Chrome for unit testing in Karma

Unit testing with Headless Chrome is much closer to the browser development environment than, say, PhantomJS. Meanwhile, the PhantomJS author has retired from the project. After Chrome released Headless mode, the release notice no longer maintains the PhantomJS project.

Install dependencies

npm install jasmine-core karma karma-chrome-launcher karma-jasmine -D
Copy the code


// karma.conf.js
module.exports = function (config) {
  config.set({
    frameworks: ['jasmine'],
    files: ['./test.js'],
    browsers: ["Chrome_Beta_Headless"],
    customLaunchers: {
      Chrome_Beta_Headless: {
        base: 'Chrome',
        flags: [
          '--headless',
          '--disable-gpu',
          '--remote-debugging-port=9222'
        ]
      }
    },
    browserConsoleLogOptions: {
      level: 'log',
      terminal: true
    },
    reporters: ['progress'],
    autoWatch: false,
    singleRun: true
  })
}
Copy the code


// test.js
describe('test', function() {
  it('should be true', function() {
    console.log(window.navigator.userAgent)
    expect(true).toEqual(true);
  });
});
Copy the code

Configuration of NPM script

// package.json
...
scripts: {
  test: "karma start"
}
...
Copy the code


npm test
Copy the code

You can see from the returned results that the test is running in the Headless Chrome environment.

summary

This article briefly introduces the usage of Headless Chrome in terminal, and how to use Headless Chrome to get screenshots, get CSS and DOM in the page, set UA and cookies, run JS scripts, and conduct unit tests with Karma. Find out more about the use of Headless Chrome…

Reference:

Developers.google.com/web/updates…



How to install and use Headless Chrome on OSX