原文: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' ]複製代碼
讓咱們愉快的抓取吧!