原文:How to install and use Headless Chrome on OSXjavascript
这个教程会用详细的步骤教你在 macOS 上怎么去获取和运行 Headless Chrome 和怎么去使用 Chrome 团队提供的示例代码。css
Chrome 的 Headless 模式是一个和网站交互的新方式,可是没有一个实际的界面显示在屏幕上。这看起来像是一个微不足道的改进,但对于从 Web 上抓取内容来讲是一个巨大的飞跃。如今有一些稳定的非正式的解决方案去抓取,好比 PhantomJS 和 Nightmare(构建在 Electron 之上)。这些方案都尚未消失(编辑:PhantomJS 仅有的维护者已经辞职),它们仍然是抓取 Web 很是棒的解决方案。若是你已经在本身的系统中运用了这些工具,你能够继续使它们。html
可是也有这样的说法,一些用户在使用 PhantomJS 和 Nightmare 的时候遇到了麻烦。这两个工具都有警告,当它们运行在 shell-only 系统(没有实际的屏幕或者窗口管理) 时。举个例子,当你在使用 Nightmare (一个 Electron 应用)时,为了运行这个应用你须要安装一个虚拟的显示管理。另外,自从 Nightmare 使用 Electron 构建以后,它与 Chrome 有着不用的安全模式,在生产环境测试的时候可能会没法捕获一些安全问题。java
Headless Chrome 已经在 Chrome 59 中发布。截止 2017 年 4 月 13 日,Chrome Canary 是惟一包含 Chrome 59 的频道。这意味着如今,若是你想要使用 Headless 你须要安装 Chrome Canary。未来 Chrome 的开发团队会把 Chrome 59 放到主要的 Chrome 版本中,你就不须要安装 Chrome Canary 了。
安装 Chrome Canary ,你能够下载或者用 homebrew 安装:node
brew install Caskroom/versions/google-chrome-canary复制代码
不少例子在使用 Headless Chrome 时,只用了一个简单的 chrome
命令。这能够在 Linux 下很好的工做,可是在 macOS 上不行,由于命令没有被安装在你的 PATH
中。
因此你须要找到 Chrome 的路径,让咱们启动咱们的终端去找 Chrome Canary 安装在咱们系统的哪里。git
sudo find / -type d -name "*Chrome Canary.app"复制代码
你可能会获得一些权限错误,可是你仍是会获得一个路径长得像这样:github
/Applications/Google Chrome Canary.app复制代码
咱们找到了 Chrome Canary 的路径,咱们可使用它启动 Chrome 并使它运行在 Headless 模式。chrome
咱们获得 Chrome Canary 的路径之后,咱们须要用一个命令启动 Chrome 做为一个 Headless 服务。shell
/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --headless --remote-debugging-port=9222 --disable-gpu https://chromium.org复制代码
特别须要注意的是咱们转义了文件名中空格,深刻到 Mac .app 文件中去找到实际的 Chrome 二进制文件。而后咱们经过启动参数去启动了一个 Headless 浏览器,给它一个初始化的连接 https://chromium.org
。这个浏览器会监听 9222
端口等待接下来的指令。保持这个标签和服务运行。 打开另外一个标签,咱们将会链接到这个浏览器的这个标签,而后给一些指令。npm
我将要使用 Node.js 去链接咱们运行中的 Chrome Canary 实例。你须要确保你已经安装了 Node,才能够继续这个步骤。
让咱们生成一个普通的 Node 项目,只有一个依赖那就是 Chrome Remote Interface 包,它能够帮助咱们与 Chrome 沟通。而后咱们建立一个空白的 index.js
文件。
mkdir my-headless-chrome && cd my-headless-chrome
npm init --yes
npm install --save chrome-remote-interface
touch index.js复制代码
如今咱们将要放一些代码到index.js
。这个模板例子是由 Chrome 团队提供的。它指示这个浏览器导航到github.com
,而后经过 client
里的 Network
属性捕获这个页面上全部的网络请求。
const CDP = require("chrome-remote-interface");
CDP(client => {
// extract domains
const { Network, Page } = client;
// setup handlers
Network.requestWillBeSent(params => {
console.log(params.request.url);
});
Page.loadEventFired(() => {
client.close();
});
// enable events then start!
Promise.all([Network.enable(), Page.enable()])
.then(() => {
return Page.navigate({ url: "https://github.com" });
})
.catch(err => {
console.error(err);
client.close();
});
}).on("error", err => {
// cannot connect to the remote endpoint
console.error(err);
});复制代码
最后启动咱们的 Node 应用。
node index.js复制代码
咱们能够看到 Chrome 发出的全部的网络请求,然而并无一个实际的浏览器窗口。
https://github.com/
https://assets-cdn.github.com/assets/frameworks-12d63ce1986bd7fdb5a3f4d944c920cfb75982c70bc7f75672f75dc7b0a5d7c3.css
https://assets-cdn.github.com/assets/github-2826bd4c6eb7572d3a3e9774d7efe010d8de09ea7e2a559fa4019baeacf43f83.css
https://assets-cdn.github.com/assets/site-f4fa6ace91e5f0fabb47e8405e5ecf6a9815949cd3958338f6578e626cd443d7.css
https://assets-cdn.github.com/images/modules/site/home-illo-conversation.svg
https://assets-cdn.github.com/images/modules/site/home-illo-chaos.svg
https://assets-cdn.github.com/images/modules/site/home-illo-business.svg
https://assets-cdn.github.com/images/modules/site/integrators/slackhq.png
https://assets-cdn.github.com/images/modules/site/integrators/zenhubio.png
https://assets-cdn.github.com/images/modules/site/integrators/travis-ci.png
https://assets-cdn.github.com/images/modules/site/integrators/atom.png
https://assets-cdn.github.com/images/modules/site/integrators/circleci.png
https://assets-cdn.github.com/images/modules/site/integrators/codeship.png
https://assets-cdn.github.com/images/modules/site/integrators/codeclimate.png
https://assets-cdn.github.com/images/modules/site/integrators/gitterhq.png
https://assets-cdn.github.com/images/modules/site/integrators/waffleio.png
https://assets-cdn.github.com/images/modules/site/integrators/heroku.png
https://assets-cdn.github.com/images/modules/site/logos/airbnb-logo.png
https://assets-cdn.github.com/images/modules/site/logos/sap-logo.png
https://assets-cdn.github.com/images/modules/site/logos/ibm-logo.png
https://assets-cdn.github.com/images/modules/site/logos/google-logo.png
https://assets-cdn.github.com/images/modules/site/logos/paypal-logo.png
https://assets-cdn.github.com/images/modules/site/logos/bloomberg-logo.png
https://assets-cdn.github.com/images/modules/site/logos/spotify-logo.png
https://assets-cdn.github.com/images/modules/site/logos/swift-logo.png
https://assets-cdn.github.com/images/modules/site/logos/facebook-logo.png
https://assets-cdn.github.com/images/modules/site/logos/node-logo.png
https://assets-cdn.github.com/images/modules/site/logos/nasa-logo.png
https://assets-cdn.github.com/images/modules/site/logos/walmart-logo.png
https://assets-cdn.github.com/assets/compat-8a4318ffea09a0cdb8214b76cf2926b9f6a0ced318a317bed419db19214c690d.js
https://assets-cdn.github.com/assets/frameworks-6d109e75ad8471ba415082726c00c35fb929ceab975082492835f11eca8c07d9.js
https://assets-cdn.github.com/assets/github-5d29649478f4a2b05588bbd0d25cd56ff5445b21df31b4cccca942ad8687e1e8.js
https://assets-cdn.github.com/images/modules/site/heroes/home-code-bg-alt-01.svg
https://assets-cdn.github.com/static/fonts/roboto/roboto-light.woff
https://assets-cdn.github.com/static/fonts/roboto/roboto-regular.woff
https://assets-cdn.github.com/static/fonts/roboto/roboto-medium.woff复制代码
这是一个很是棒的方式去查看加载了那些资源,可是若是我想要操做页面上的 DOM 元素呢?咱们用能够像这样的一个脚本拉取github.com
上全部的img
标签。
const CDP = require("chrome-remote-interface");
CDP(chrome => {
chrome.Page
.enable()
.then(() => {
return chrome.Page.navigate({ url: "https://github.com" });
})
.then(() => {
chrome.DOM.getDocument((error, params) => {
if (error) {
console.error(params);
return;
}
const options = {
nodeId: params.root.nodeId,
selector: "img"
};
chrome.DOM.querySelectorAll(options, (error, params) => {
if (error) {
console.error(params);
return;
}
params.nodeIds.forEach(nodeId => {
const options = {
nodeId: nodeId
};
chrome.DOM.getAttributes(options, (error, params) => {
if (error) {
console.error(params);
return;
}
console.log(params.attributes);
});
});
});
});
});
}).on("error", err => {
console.error(err);
});复制代码
咱们能够获得如下的数据结构展示了页面上标签包含全部图片的连接。
[ 'src',
'https://assets-cdn.github.com/images/modules/site/home-illo-conversation.svg',
'alt',
'',
'width',
'360',
'class',
'd-block width-fit mx-auto' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/home-illo-chaos.svg',
'alt',
'',
'class',
'd-block width-fit mx-auto' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/home-illo-business.svg',
'alt',
'',
'class',
'd-block width-fit mx-auto mb-4' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/integrators/slackhq.png',
'alt',
'',
'class',
'd-block integrations-collage-img width-fit mx-auto' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/integrators/zenhubio.png',
'alt',
'',
'class',
'd-block integrations-collage-img width-fit mx-auto' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/integrators/travis-ci.png',
'alt',
'',
'class',
'd-block integrations-collage-img width-fit mx-auto' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/integrators/atom.png',
'alt',
'',
'class',
'd-block integrations-collage-img width-fit mx-auto' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/integrators/circleci.png',
'alt',
'',
'class',
'd-block integrations-collage-img width-fit mx-auto' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/integrators/codeship.png',
'alt',
'',
'class',
'd-block integrations-collage-img width-fit mx-auto' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/integrators/codeclimate.png',
'alt',
'',
'class',
'd-block integrations-collage-img width-fit mx-auto' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/integrators/gitterhq.png',
'alt',
'',
'class',
'd-block integrations-collage-img width-fit mx-auto' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/integrators/waffleio.png',
'alt',
'',
'class',
'd-block integrations-collage-img width-fit mx-auto' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/integrators/heroku.png',
'alt',
'',
'class',
'd-block integrations-collage-img width-fit mx-auto' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/logos/airbnb-logo.png',
'alt',
'Airbnb',
'class',
'logo-img px-2 px-sm-4 px-md-5 px-lg-0' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/logos/sap-logo.png',
'alt',
'SAP',
'class',
'logo-img px-2 px-sm-4 px-md-5 px-lg-0' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/logos/ibm-logo.png',
'alt',
'IBM',
'class',
'logo-img px-2 px-sm-4 px-md-5 px-lg-0' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/logos/google-logo.png',
'alt',
'Google',
'class',
'logo-img px-2 px-sm-4 px-md-5 px-lg-0' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/logos/paypal-logo.png',
'alt',
'PayPal',
'class',
'logo-img px-2 px-sm-4 px-md-5 px-lg-0' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/logos/bloomberg-logo.png',
'alt',
'Bloomberg',
'class',
'logo-img px-2 px-sm-4 px-md-5 px-lg-0' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/logos/spotify-logo.png',
'alt',
'Spotify',
'class',
'logo-img px-2 px-sm-4 px-md-5 px-lg-0' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/logos/swift-logo.png',
'alt',
'Swift',
'class',
'logo-img px-2 px-sm-4 px-md-5 px-lg-0' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/logos/facebook-logo.png',
'alt',
'Rails',
'class',
'logo-img px-2 px-sm-4 px-md-5 px-lg-0' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/logos/node-logo.png',
'alt',
'Node',
'class',
'logo-img px-2 px-sm-4 px-md-5 px-lg-0' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/logos/nasa-logo.png',
'alt',
'Nasa',
'class',
'logo-img px-2 px-sm-4 px-md-5 px-lg-0' ]
[ 'src',
'https://assets-cdn.github.com/images/modules/site/logos/walmart-logo.png',
'alt',
'Walmart',
'class',
'logo-img px-2 px-sm-4 px-md-5 px-lg-0' ]复制代码
让咱们愉快的抓取吧!