摘要:確切位置因平臺(tái)而異。如果以編程方式使用,這個(gè)頁(yè)面也是一個(gè)強(qiáng)大的調(diào)試工具,能看到所有原始的協(xié)議命令通過(guò)連線,於瀏覽器進(jìn)行通信。警告協(xié)議可以做很多有趣的事,但作為入門選項(xiàng)他令人沮喪。目前,提供了比協(xié)議高級(jí)別的。
本文翻譯自:Getting Started with Headless Chrome
原文更新時(shí)間:July 28,2017
作者:Eric Bidelman(Engineer @ Google. Working on Chrome & the web.)
譯者:Pandorym
Headless Chrome由 Chrome 59 帶來(lái)。這是一種在無(wú)界面環(huán)境中運(yùn)行 Chrome 瀏覽器的方法。本質(zhì)上,就是運(yùn)行無(wú)界面的的 Chrome !他為命令行帶來(lái)了 Chromium 和 Blink 渲染引擎提供的所有現(xiàn)代的 Web 平臺(tái)特性。
他有什麼用呢?
用於對(duì)於自動(dòng)化測(cè)試和不需要能看到UI外殼的服務(wù)器環(huán)境,Headless 瀏覽器是一個(gè)極好的工具。舉個(gè)例子,你可能要對(duì)一個(gè)真實(shí)的 Web 頁(yè)面進(jìn)行一些測(cè)試,為它創(chuàng)建一個(gè) PDF ,或者就是檢查噶瀏覽器如何渲染一個(gè) URL 。
開(kāi)啟 Headless(CLI)提示:Headless模式在Mac和Linux上是Chrome 59可用。Windows的支持將在Chrome 60到來(lái)。你可以打開(kāi)chrome://version檢查當(dāng)前版本。
啟動(dòng) Headless 模式最簡(jiǎn)單的方式四在命令行中打開(kāi) Chrome 二進(jìn)制文件。如果你已經(jīng)安裝Chrome 59+,攜帶--headless標(biāo)識(shí)啟動(dòng)Chrome:
chrome --headless # 使用 headless 模式. --disable-gpu # 現(xiàn)在暫時(shí)還需要. --remote-debugging-port=9222 https://www.chromestatus.com # 將打開(kāi)的 URL. 默認(rèn)打開(kāi) about:blank.
注意:現(xiàn)在,你需要包含--disable-gpu參數(shù)。不過(guò)這個(gè)參數(shù)最終會(huì)被丟棄。
chrome需要指向你安裝的 Chrome。確切位置因平臺(tái)而異。由於我在 Mac 上,我為我安裝的每個(gè)版本的 Chrome 都創(chuàng)建了方便的別名。
如果你在Chrome的穩(wěn)定版頻道不能進(jìn)行這個(gè)測(cè)試,我推薦使用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。這是一些對(duì)執(zhí)行普通任務(wù)有用的命令行標(biāo)識(shí)。
打印 DOM--dump-dom標(biāo)識(shí),打印document.body.innerHTML到標(biāo)準(zhǔn)輸出:
chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/創(chuàng)建 PDF
--print-to-pdf標(biāo)識(shí),為頁(yè)面創(chuàng)建一個(gè)PDF文件:
chrome --headless --disable-gpu --print-to-pdf https://www.chromestatus.com/取得截屏
要捕獲一個(gè)頁(yè)面的屏幕截圖,使用--screenshot標(biāo)識(shí):
# 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標(biāo)識(shí)運(yùn)行,將在當(dāng)前工作目錄產(chǎn)生一個(gè)命名為screenshot.png的文件。如果你正在尋找完整的頁(yè)面截圖,事情會(huì)更複雜一些。這有一個(gè) Davil Schnurr 發(fā)佈的優(yōu)秀的Blog,包含你需要的大部分內(nèi)容。查看:使用 Headless Chrome 作為自動(dòng)截屏工具。
REPL 模式(read-eval-print loop)--repl標(biāo)識(shí)使 Headless 運(yùn)行砸地一個(gè)特定的模式。你可以通過(guò)命令行,要求在瀏覽器中執(zhí)行JS表達(dá)式:
$ chrome --headless --disable-gpu --repl 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 $脫離瀏覽器界面調(diào)試Chrome
當(dāng)你使用--remote-debug-port=9222運(yùn)行 Chrome 時(shí),他將啟動(dòng)一個(gè)實(shí)例,并激活 DevTools 協(xié)議。這個(gè)協(xié)議用於連接 Chrome ,和驅(qū)動(dòng) Headless 瀏覽器實(shí)例。他也用於使用 Sublime,VS Code 和 Node 等工具遠(yuǎn)程調(diào)試應(yīng)用程序。#協(xié)同
由於你沒(méi)有瀏覽器 UI 查看頁(yè)面,在另一個(gè)瀏覽器進(jìn)入http://localhost:9222以檢查他正在工作。你將在視察頁(yè)面看到一個(gè)列表,在這你可以通過(guò)點(diǎn)擊來(lái)查看 Headless 的渲染。
在這,你可以使用熟悉的 DevTools 特性像通常那樣去檢查、調(diào)試和調(diào)整頁(yè)面。如果以編程方式使用 Headless,這個(gè)頁(yè)面也是一個(gè)強(qiáng)大的調(diào)試工具,能看到所有原始的 DevTools 協(xié)議命令通過(guò)連線,於瀏覽器進(jìn)行通信。
使用編程方式(Node) 啟動(dòng) Chrome在之前的章節(jié),我們使用--headless --remote-debugging-port=9222手動(dòng)啟動(dòng)Chrome。然後,為了完全自動(dòng)化測(cè)試,你可能想在你的應(yīng)用程序中生成Chrome。
一個(gè)方法是使用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) => { ... });
但你想要一個(gè)跨多平臺(tái)的解決方案時(shí),事情就變得棘手了。就看看這硬編碼的 Chrome 路徑吧 :(
使用 ChromeLauncherLighthouse 是一個(gè)用於測(cè)試Web應(yīng)用程序質(zhì)量的極好的工具。有一個(gè)用於啟動(dòng) Chrome 的強(qiáng)大的模塊,之前被包含在 Lightouse 內(nèi)部,但現(xiàn)在可以獨(dú)立使用了。chrome-launcher NPM 模塊將尋找 Chrome 的安裝位置、設(shè)置一個(gè)調(diào)試實(shí)例、啟動(dòng)瀏覽器,并在你的應(yīng)用程序完成時(shí)結(jié)束他。最優(yōu)秀的是它跨多平臺(tái)工作,感謝 Node !
默認(rèn)的,chrome-launcher將啟動(dòng) Chrome Canary (如果安裝了),但你能手動(dòng)更改選擇使用哪一個(gè) Chrome。要使用他,先從 npm 安裝:
yarn add chrome-launcher
Example - 使用chrome-launcher啟動(dòng) Headless
const chromeLauncher = require("chrome-launcher"); // Optional: set logging level of launcher to see its output. // Install it using: yarn add 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} */ 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(); });
運(yùn)行這個(gè)腳本并不會(huì)做什麼事,但你應(yīng)該在任務(wù)管理器中看到一個(gè) Chrome 實(shí)例啟動(dòng),他載入了about:blank。記著,這不會(huì)有任何瀏覽器界面,We"re headless.
要控制瀏覽器,我們需要 DevTools 協(xié)議!
檢索關(guān)於界面的信息chrome-remote-interface是一個(gè)很好的 Node 包,他提供了 DevTools 協(xié)議可用的 APIs。你可以使用他操作 Headless Chrome,跳轉(zhuǎn)到頁(yè)面,獲取關(guān)於頁(yè)面的相關(guān)信息。
警告:DevTools 協(xié)議可以做很多有趣的事,但作為入門選項(xiàng)他令人沮喪。我建議先花費(fèi)一點(diǎn)時(shí)間瀏覽 DevTools Protocol Viewer,然後移步到chrome-remote-interface的API文檔,看看他是如何包裝原始協(xié)議的。
讓我們安裝這個(gè)庫(kù):
yarn add chrome-remote-interfaceExamples
Example - 打印 user agent
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
Example - 檢查這個(gè)網(wǎng)站是否存在 web app manifest
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. }); })();
Example - 使用 DOM APIs 取得頁(yè)面的
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
現(xiàn)在,Selenium打開(kāi)了一個(gè)完整的 Chrome 實(shí)例。換句話說(shuō),這是一個(gè)自動(dòng)化的解決方案,但不是完全 Headless。但是Selenium可以配置運(yùn)行 Headless Chrome,只需少量配置即可。如果你想要配置的完全指南,我推薦 Running Selenium with Headless Chrome,但我已經(jīng)在列出了一些例子,讓你可以快速開(kāi)始。
使用 ChromeDriverChromeDriver 2.3.0 支持 Chrome 59 及之後的版本,並且工作於 Headless Chrome。在某些情況下,你可能需要 Chrome 60 來(lái)避免 Bugs。舉個(gè)例子,我們已經(jīng)知道 Chrome 59 的獲取截圖存在問(wèn)題。
安裝:
yarn add selenium-webdriver chromedriver
Example:
const fs = require("fs"); const webdriver = require("selenium-webdriver"); const chromedriver = require("chromedriver"); // This should be the path to your Canary installation. // I"m assuming Mac for the example. const PATH_TO_CANARY = "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"; const chromeCapabilities = webdriver.Capabilities.chrome(); chromeCapabilities.set("chromeOptions", { binary: PATH_TO_CANARY // Screenshots require Chrome 60. Force Canary. "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
WebDriverIO 是一個(gè) Selenium WebDirver 上的的高級(jí)別 API。
安裝:
yarn add webdriverio chromedriver
Example - 過(guò)濾 chromestatus.com 上的 CSS 特性
const webdriverio = require("webdriverio"); const chromedriver = require("chromedriver"); // This should be the path to your Canary installation. // I"m assuming Mac for the example. const PATH_TO_CANARY = "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"; const PORT = 9515; chromedriver.start([ "--url-base=wd/hub", `--port=${PORT}`, "--verbose" ]); (async () => { const opts = { port: PORT, desiredCapabilities: { browserName: "chrome", chromeOptions: { binary: PATH_TO_CANARY // Screenshots require Chrome 60. Force Canary. 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 Protocol Viewer - API 參考文檔
工具
chrome-remote-interface - node 模塊,封裝了 DevTools 協(xié)議
Lighthouse - Web app 質(zhì)量自動(dòng)化測(cè)試工具; 大量用於協(xié)議
chrome-launcher - node 模塊, 啟動(dòng) Chrome, 準(zhǔn)備自動(dòng)化
演示
The Headless Web - Paul Kinlan 發(fā)佈的優(yōu)秀的博客,關(guān)於使用 Headless。api.ai 也是域名。
FAQ我需要--disable-gpu標(biāo)識(shí)嗎?
是的,現(xiàn)在需要。--disable-gpu標(biāo)識(shí)是暫時(shí)處理一些 Bug 的必要條件。在未來(lái)的 Chrome 版本中不需要這個(gè)標(biāo)識(shí)???https://crbug.com/546953#c152 和 https://crbug.com/695212 獲得更多信息。
所以我仍然需要 Xvfb?
不需要。Headless Chrome 不使用窗口,所以不再需要像 Xvfb 這樣的展示服務(wù)。你可以拋開(kāi)它,開(kāi)心地運(yùn)行自動(dòng)化測(cè)試。
什麼是 Xvfb? Xvfb 是一個(gè)類 Unix 系統(tǒng)的內(nèi)存顯示服務(wù)器,可以讓你運(yùn)行圖形應(yīng)用程序(如 Chrome),無(wú)需附加物理顯示器。許多人使用 Xvfb 運(yùn)行早期版本的 Chrome 進(jìn)行 「Headless」測(cè)試。
我要如何創(chuàng)建一個(gè) Docker 容器運(yùn)行 Headless Chrome?
查看 lighthouse-ci。他有一個(gè)例子 Dockerfile,它使用 Ubuntu 為基本映像,並在 APP Engine Flexible 容器中安裝、運(yùn)行 Lightouse。
我可以和 Selenium / WebDriver / ChromeDriver 一起使用嗎?
可以,看上文「使用 Selenium,WebDriver,和ChromeDriver」。
他和 PhantomJS 有什麼關(guān)係?
Headless Chrome 是一個(gè)於 PhantomJS 相似的工具。兩者都可用於 Headless 環(huán)境下的自動(dòng)化測(cè)試。兩者主要的區(qū)別在於,Phantom 使用舊版本的 WebKit 作為渲染引擎,Headless Chrome 使用最新版本的 Blink。
目前,Phantom 提供了比 DevTools 協(xié)議 高級(jí)別的 API。
在哪提交 bugs?
對(duì)於 Headless Chrome 的 Bugs,crbug.com。
對(duì)於 DevTools 協(xié)議的 Bugs,github.com/ChromeDevTools/devtools-protocol。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/84457.html
摘要:該支持下列事件當(dāng)?shù)降倪B接已建立時(shí)觸發(fā)。取得該調(diào)試協(xié)議描述符。在關(guān)閉請(qǐng)求收到響應(yīng)后執(zhí)行,他將獲得下列參數(shù)一個(gè)對(duì)象,指明成功狀態(tài)當(dāng)缺省時(shí),將返回一個(gè)對(duì)象。當(dāng)缺省時(shí),將返回一個(gè)對(duì)象,並且狀態(tài)取決于屬性。 本文翻譯自:chrome-remote-interface原文更新時(shí)間:July 21,2017譯者:Pandorym Chrome 調(diào)試協(xié)議 的接口,他提供一個(gè)使用 JavaScript ...
摘要:本文翻譯自原文更新時(shí)間譯者從輕鬆啟動(dòng)。禁用了許多服務(wù),他們對(duì)於自動(dòng)化情景是無(wú)用的。自動(dòng)定位二進(jìn)制文件的位置進(jìn)行啟動(dòng)。每次啟動(dòng)都使用一個(gè)新的,並在中清除它。對(duì)於可配置性的細(xì)節(jié),提供一些設(shè)置選項(xiàng)。然後在中,像這樣使用它 本文翻譯自:Chrome Launcher原文更新時(shí)間:July 21,2017譯者:Pandorym 從 Node 輕鬆啟動(dòng) Google Chrome。 禁用了許多 ...
摘要:目錄許多開(kāi)發(fā)者會(huì)把的目錄命名為但這並不強(qiáng)迫。所有的檔案都會(huì)使用從被編譯成。同時(shí)有個(gè)小小的重點(diǎn)那就是我們可已觀察編譯後的檔案大小。在專案目錄下執(zhí)行可以觀察截至目前為止的結(jié)果。我們的目標(biāo)是要把編譯封裝到我們的中。 在今時(shí)今日,webpack 已經(jīng)成為前端開(kāi)發(fā)非常重要的工具之一。本質(zhì)上它是一個(gè) Javascript 模組封裝工具,但透過(guò) loaders 和 plugins 它也可以轉(zhuǎn)換封裝其...
摘要:載入流程被限制在兩個(gè)階段根據(jù)上面的模式,內(nèi)嵌透過(guò)隱藏尚未套用樣式的內(nèi)容,然後非同步得載入之後呈現(xiàn)內(nèi)容。樣式表本身的載入機(jī)制是平行的,但是套用樣式卻是要照順序的。我們需要一點(diǎn)小技巧來(lái)避免。 這週閱讀到這篇有意思的文章,於是便動(dòng)手寫下簡(jiǎn)單的翻譯,如果有理解錯(cuò)誤的地方歡迎指教。 Chrome 正在試圖改變當(dāng) 寫在 的行為,從blink-dev 的文章並不能很清楚的知道其優(yōu)點(diǎn)。所以這篇文章...
摘要:前端每周清單第期現(xiàn)狀分析與優(yōu)化策略單元測(cè)試爬蟲作者王下邀月熊編輯徐川前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開(kāi)發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開(kāi)發(fā)教程工程實(shí)踐深度閱讀開(kāi)源項(xiàng)目巔峰人生等欄目。 showImg(https://segmentfault.com/img/remote/1460000011008022); 前端每周清單第 29 期:Web 現(xiàn)狀分析與優(yōu)化策略...
閱讀 3219·2021-11-23 09:51
閱讀 3681·2021-09-22 15:35
閱讀 3658·2021-09-22 10:02
閱讀 2969·2021-08-30 09:49
閱讀 526·2021-08-05 10:01
閱讀 3392·2019-08-30 15:54
閱讀 1641·2019-08-30 15:53
閱讀 3569·2019-08-29 16:27