Headless Browser(无头的浏览器)是什么鬼?

简而言之,Headless Browser是没有图形用户界面(GUI)的web浏览器,通常是通过编程或命令行界面来控制的。

Headless Browser的许多用处之一是自动化可用性测试或测试浏览器交互。如果您正在尝试检查页面在不同的浏览器中呈现的方式,或者确认页面元素在用户启动某个工作流之后出现,那么使用Headless Browser可以提供大量的帮助。除此之外,如果内容是动态呈现的(比如通过Javascript),web抓取等传统的面向web的任务就很难做了。使用Headless Browser可以方便地访问这些内容,因为内容的呈现方式与完全浏览器中的内容完全相同。

基于不同的浏览器,有不同的浏览器引擎。(http://www.cnblogs.com/wangjunqiao/p/5212561.html)

主流浏览器所使用的内核分类

Trident内核:IE,MaxThon,TT,The World,360,搜狗浏览器等
Gecko内核:Netscape6及以上版本,FF,MozillaSuite/SeaMonkey等
Presto内核:Opera7及以上
Webkit内核:Safari,Chrome等

先让我们看看浏览器处理过程中的每一个步骤:

1.处理HTML脚本,生成DOM树
2.处理CSS脚本,生成CSSOM树 (DOM和CSSOM是独立的数据结构)
3.将DOM树和CSSOM树合并为渲染树
4.对渲染树中的内容进行布局,计算每个节点的几何外观
5.将渲染树中的每个节点绘制到屏幕中

Headless Browser实际就是节约了第4,5步的时间。

3年前,无头浏览器 PhantomJS 已经如火如荼出现了,紧跟着 NightmareJS 也成为一名巨星。无头浏览器带来巨大便利性:页面爬虫、自动化测试、WebAutomation...用过PhantomJS的都知道,它的环境是运行在一个封闭的沙盒里面,在环境内外完全不可通信,包括API、变量、全局方法调用等。

Headless Chrome和Python
在发布Headless Chrome之前,当你需要自动化浏览器的时候随时都有可能涉及多个窗口或标签,你必须担心CPU和/或内存的使用。这两种方式都与必须从被请求的URL中显示显示的图形的浏览器相关联。

当使用一个无头的浏览器时,我们不用担心这个。因此,我们可以预期我们编写的脚本的内存开销会降低,执行速度也会更快。
而Chrome从59版本开始 推出了 headless mode(当时仅支持Mac和Linux),而目前最新的Chrome63版已经开始在windows上支持headless mode。

安装Headless Chrome 在windows
Selenium操作chrome浏览器需要有ChromeDriver驱动来协助。
什么是ChromeDriver?

ChromeDriver是Chromium team开发维护的,它是实现WebDriver有线协议的一个单独的服务。ChromeDriver通过chrome的自动代理框架控制浏览器,建议从以下地址直接下载最新的版本:ChromeDriver 2.34
它才可以支持Chrome v61-63。
可以将此driver放置于:C:\Program Files\Google\Chrome\Application\ (对应的Chrome安装目录下)

安装Selenium 在windows
cmd命令里面运行:
$pip install selenium

编写对应的脚本
编写一个对应的百度搜索的脚本

import os
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
import timechrome_options = Options()
chrome_options.add_argument("--headless")base_url = "http://www.baidu.com/"
#对应的chromedriver的放置目录
driver = webdriver.Chrome(executable_path=(r'C:\Program Files\Google\Chrome\Application\chromedriver.exe'), chrome_options=chrome_options)driver.get(base_url + "/")start_time=time.time()
print('this is start_time ',start_time)driver.find_element_by_id("kw").send_keys("selenium webdriver")
driver.find_element_by_id("su").click()
driver.save_screenshot('screen.png')driver.close()end_time=time.time()
print('this is end_time ',end_time)
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')

以上的脚本运行完成后,你会在你的当前目录看到一个类似于下面画面的screen.png.

可以看出上面的写法和直接使用Selenium调用Chrome浏览器的时候极其类似,只是多添加了对chrome_options的重写。

据运行的试验表明,Headelss 的确比Headed的浏览器在内存消耗,运行时间,CPU占用上面都有一定的优势。

headless对比.png

使用Headless Chrome也许能让你的自动化测试运行更快,而且在视觉测试上面也有一定的优势。感兴趣的朋友可以上手试试。

链接:https://www.jianshu.com/p/11d519e2d0cb

Headless Chrome 入门

reflink:https://linux.cn/article-8850-1.html

在 Chrome 59 中开始搭载 Headless Chrome。这是一种在无需显示headless的环境下运行 Chrome 浏览器的方式。从本质上来说,就是不用 chrome 浏览器来运行 Chrome 的功能!它将 Chromium 和 Blink 渲染引擎提供的所有现代 Web 平台的功能都带入了命令行。

它有什么用?

无需显示headless的浏览器对于自动化测试和不需要可视化 UI 界面的服务器环境是一个很好的工具。例如,你可能需要对真实的网页运行一些测试,创建一个 PDF,或者只是检查浏览器如何呈现 URL。

注意: Mac 和 Linux 上的 Chrome 59 都可以运行无需显示模式。对 Windows 的支持将在 Chrome 60 中提供。要检查你使用的 Chrome 版本,请在浏览器中打开 chrome://version。

开启无需显示headless模式(命令行界面)

开启无需显示headless模式最简单的方法是从命令行打开 Chrome 二进制文件。如果你已经安装了 Chrome 59 以上的版本,请使用 --headless 标志启动 Chrome:

chrome \--headless \                   # Runs Chrome in headless mode.--disable-gpu \                # Temporarily needed for now.--remote-debugging-port=9222 \https://www.chromestatus.com   # URL to open. Defaults to about:blank.

注意:目前你仍然需要使用 --disable-gpu 标志。但它最终会不需要的。

chrome 二进制文件应该指向你安装 Chrome 的位置。确切的位置会因平台差异而不同。当前我在 Mac 上操作,所以我为安装的每个版本的 Chrome 都创建了方便使用的别名。

如果您使用 Chrome 的稳定版,并且无法获得测试版,我建议您使用 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 Cannary。

命令行的功能

在某些情况下,你可能不需要以脚本编程的方式操作 Headless Chrome。可以使用一些有用的命令行标志来执行常见的任务。

打印 DOM

--dump-dom 标志将打印 document.body.innerHTML 到标准输出:

chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/

创建一个 PDF

--print-to-pdf 标志将页面转出为 PDF 文件:

chrome --headless --disable-gpu --print-to-pdf https://www.chromestatus.com/

截图

要捕获页面的屏幕截图,请使用 --screenshot 标志:

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 5xchrome --headless --disable-gpu --screenshot --window-size=412,732 https://www.chromestatus.com/

使用 --screenshot 标志运行 Headless Chrome 将在当前工作目录中生成一个名为 screenshot.png 的文件。如果你正在寻求整个页面的截图,那么会涉及到很多事情。来自 David Schnurr 的一篇很棒的博文已经介绍了这一内容。请查看 使用 headless Chrome 作为自动截屏工具。

REPL 模式 (read-eval-print loop)

--repl 标志可以使 Headless Chrome 运行在一个你可以使用浏览器评估 JS 表达式的模式下。执行下面的命令:

$ 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

在没有浏览器界面的情况下调试 Chrome

当你使用 --remote-debugging-port=9222 运行 Chrome 时,它会启动一个支持 DevTools 协议的实例。该协议用于与 Chrome 进行通信,并且驱动 Headless Chrome 浏览器实例。它也是一个类似 Sublime、VS Code 和 Node 的工具,可用于应用程序的远程调试。#协同效应

由于你没有浏览器用户界面可用来查看网页,请在另一个浏览器中输入 http://localhost:9222,以检查一切是否正常。你将会看到一个可检查的inspectable页面的列表,可以点击它们来查看 Headless Chrome 正在呈现的内容:

DevTools 远程调试界面

从这里,你就可以像往常一样使用熟悉的 DevTools 来检查、调试和调整页面了。如果你以编程方式使用 Headless Chrome,这个页面也是一个功能强大的调试工具,用于查看所有通过网络与浏览器交互的原始 DevTools 协议命令。

使用编程模式 (Node)

Puppeteer 库 API

Puppeteer 是一个由 Chrome 团队开发的 Node 库。它提供了一个高层次的 API 来控制无需显示版(或 完全版)的 Chrome。它与其他自动化测试库,如 Phantom 和 NightmareJS 相类似,但是只适用于最新版本的 Chrome。

除此之外,Puppeteer 还可用于轻松截取屏幕截图,创建 PDF,页面间导航以及获取有关这些页面的信息。如果你想快速地自动化进行浏览器测试,我建议使用该库。它隐藏了 DevTools 协议的复杂性,并可以处理诸如启动 Chrome 调试实例等繁冗的任务。

安装:

yarn add puppeteer

例子 - 打印用户代理:

const puppeteer = require('puppeteer');

(async() => {

const browser = await puppeteer.launch();

console.log(await browser.version());

browser.close();

})();

例子 - 获取页面的屏幕截图:

const puppeteer = require('puppeteer');

(async() => {

const browser = await puppeteer.launch();

const page = await browser.newPage();

await page.goto('https://www.chromestatus.com', {waitUntil: 'networkidle'});

await page.pdf({path: 'page.pdf', format: 'A4'});

browser.close();

})();

查看 Puppeteer 的文档,了解完整 API 的更多信息。

CRI 库

chrome-remote-interface 是一个比 Puppeteer API 更低层次的库。如果你想要更接近原始信息和更直接地使用 DevTools 协议的话,我推荐使用它。

启动 Chrome

chrome-remote-interface 不会为你启动 Chrome,所以你要自己启动它。

在前面的 CLI 章节中,我们使用 --headless --remote-debugging-port=9222 手动启动了 Chrome。但是,要想做到完全自动化测试,你可能希望从你的应用程序中启动 Chrome。

其中一种方法是使用 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) => {

...

});

但是如果你想要在多个平台上运行可移植的解决方案,事情会变得很棘手。请注意 Chrome 的硬编码路径:

使用 ChromeLauncher

Lighthouse 是一个令人称奇的网络应用的质量测试工具。Lighthouse 内部开发了一个强大的用于启动 Chrome 的模块,现在已经被提取出来单独使用。chrome-launcher NPM 模块 可以找到 Chrome 的安装位置,设置调试实例,启动浏览器和在程序运行完之后将其杀死。它最好的一点是可以跨平台工作,感谢 Node!

默认情况下,chrome-launcher 会尝试启动 Chrome Canary(如果已经安装),但是你也可以更改它,手动选择使用的 Chrome 版本。要想使用它,首先从 npm 安装:

yarn add chrome-launcher

例子 - 使用 chrome-launcher 启动 Headless Chrome:

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<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();

});

运行这个脚本没有做太多的事情,但你应该能在任务管理器中看到启动了一个 Chrome 的实例,它加载了页面 about:blank。记住,它不会有任何的浏览器界面,我们是无需显示的。

为了控制浏览器,我们需要 DevTools 协议!

检索有关页面的信息

警告: DevTools 协议可以做一些有趣的事情,但是起初可能有点令人生畏。我建议先花点时间浏览 DevTools 协议查看器。然后,转到 chrome-remote-interface 的 API 文档,看看它是如何包装原始协议的。

我们来安装该库:

yarn add chrome-remote-interface

例子 - 打印用户代理:

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。

例子 - 检查网站是否有 Web 应用程序清单:

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. 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.

});

})();

例子 - 使用 DOM API 提取页面的 <title>:

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. 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

现在,Selenium 开启了 Chrome 的完整实例。换句话说,这是一个自动化的解决方案,但不是完全无需显示的。但是,Selenium 只需要进行小小的配置即可运行 Headless Chrome。如果你想要关于如何自己设置的完整说明,我建议你阅读“使用 Headless Chrome 来运行 Selenium”,不过你可以从下面的一些示例开始。

使用 ChromeDriver

ChromeDriver 2.3.0 支持 Chrome 59 及更新版本,可与 Headless Chrome 配合使用。在某些情况下,你可能需要等到 Chrome 60 以解决 bug。例如,Chrome 59 中屏幕截图已知存在问题。

安装:

yarn add selenium-webdriver chromedriver

例子:

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 是一个在 Selenium WebDrive 上构建的更高层次的 API。

安装:

yarn add webdriverio chromedriver

例子:过滤 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 - 基于 DevTools 协议的 node 模块

Lighthouse - 测试 Web 应用程序质量的自动化工具;大量使用了协议

chrome-launcher - 用于启动 Chrome 的 node 模块,可以自动化

样例

"The Headless Web" - Paul Kinlan 发布的使用了 Headless 和 api.ai 的精彩博客

常见问题

我需要 --disable-gpu 标志吗?

目前是需要的。--disable-gpu 标志在处理一些 bug 时是需要的。在未来版本的 Chrome 中就不需要了。查看 https://crbug.com/546953#c152 和 https://crbug.com/695212 获取更多信息。

所以我仍然需要 Xvfb 吗?

不。Headless Chrome 不使用窗口,所以不需要像 Xvfb 这样的显示服务器。没有它你也可以愉快地运行你的自动化测试。

什么是 Xvfb?Xvfb 是一个用于类 Unix 系统的运行于内存之内的显示服务器,可以让你运行图形应用程序(如 Chrome),而无需附加的物理显示器。许多人使用 Xvfb 运行早期版本的 Chrome 进行 “headless” 测试。

如何创建一个运行 Headless Chrome 的 Docker 容器?

查看 lighthouse-ci。它有一个使用 Ubuntu 作为基础镜像的 Dockerfile 示例,并且在 App Engine Flexible 容器中安装和运行了 Lighthouse。

我可以把它和 Selenium / WebDriver / ChromeDriver 一起使用吗?

是的。查看 Using Selenium, WebDrive, or ChromeDriver。

它和 PhantomJS 有什么关系?

Headless Chrome 和 PhantomJS 是类似的工具。它们都可以用来在无需显示的环境中进行自动化测试。两者的主要不同在于 Phantom 使用了一个较老版本的 WebKit 作为它的渲染引擎,而 Headless Chrome 使用了最新版本的 Blink。

目前,Phantom 提供了比 DevTools protocol 更高层次的 API。

我在哪儿提交 bug?

对于 Headless Chrome 的 bug,请提交到 crbug.com。

对于 DevTools 协议的 bug,请提交到 github.com/ChromeDevTools/devtools-protocol。

编译自:https://developers.google.com/web/updates/2017/04/headless-chrome作者: Eric Bidelman
原创:LCTT https://linux.cn/article-8850-1.html译者: Firmy Yang

链接:http://www.imooc.com/article/81012

selenium+headless chrome安装使用

pip install selenium

因为phantomJS将停止维护,所以建议使用headless chrome
ChromeDriver is a separate executable that WebDriver uses to control Chrome.

1、确保谷歌浏览器安装在可以找到的位置(默认位置或自己指定的位置)。
如果不是默认位置,则需要用下面的代码来指定谷歌浏览器的安装位置:
ChromeOptions options = new ChromeOptions();
options.setBinary("/path/to/other/chrome/binary");

2、下载你系统上所需要的ChromeDriver文件,windows所需下载地址为:
https://chromedriver.storage.googleapis.com/index.html?path=2.35/

3、帮助WebDriver找到你下载的ChromeDriver文件:
将ChromeDriver文件存放在PATH目录下或

from selenium import webdriver
driver = webdriver.Chrome('/path/to/chromedriver')

4、(可选)启动和退出ChromeDriver server需要一些时间,所以提供了两种方法来
解决这个问题:
1、使用ChromeDriverService
2、作为一个服务器单独启动ChromeDriver server,然后用Remote WebDriver连接它。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.get("https://www.baidu.com")
print(driver.title)
driver.quit()

参考链接:
https://sites.google.com/a/chromium.org/chromedriver/home 介绍地址
https://sites.google.com/a/chromium.org/chromedriver/getting-started 入门地址

puppeteer,新款headless chrome!

puppeteer

puppeteer是一种谷歌开发的Headless Chrome,因为puppeteer的出现,业内许多自动化测试库停止维护,比如PhantomJS,Selenium IDE for Firefox 。

puppeteer是干啥用的?

官方给了一些功能:

  • 页面生成pdf
  • 爬spa/ssr类的网站
  • 自动提交表单,模拟用户操作,ui测试等等
  • 提供自动化测试环境
  • 分析网页性能问题,基于chrome timeline

其实对于这么一个浏览器,我们能做的还有很多,比如前端监控,定期查询页面异常。这种思想产生的page-monitor。主要的功能其实就是基于它是一个浏览器,它可以模拟用户输入。能做什么依赖你的想象。

用code介绍一下puppeteer

页面生成pdf

const puppeteer = require('puppeteer');(async () => {const browser = await puppeteer.launch();const page = await browser.newPage();await page.goto('http://open.toutiao.com', {waitUntil: 'networkidle2'});await page.pdf({path: 'hn.pdf', format: 'A4'});await browser.close();
})();

puppeteer是基于node v6.4.0,但是await/async的语法需要node v7.6.0以上才支持。

可以npm i puppeteer然后在命令行看一下效果。
代码都是api没有什么可以讲的。需要说的一点就是open.toutiao.com下面的文章内容都是异步接口请求,puppeteer是怎么获取内容的?

page.goto的配置项waitUntil:networkidle2, 等待一直到500ms内的请求数不超过2个。其实不保证准确获得内容,那把等待时间写长一点就可以了。
await page.waitFor(2000);

调试

  • puppeteer并不是只有headless模式,打开puppeteer的ui界面:puppeteer.launch({headless: false),再放慢puppeteer执行的动作puppeteer.launch({headless: false, slowMo: 250}),就可以轻松调试。
  • ‘打call?’ page.on('console', msg => console.log('PAGE LOG:', msg.text())); 事件监听轻松打出页面的log。

爬虫

这里爬一下头条的新闻标题:

(async () => {const browser = await puppeteer.launch({headless: false, slowMo: 250});const page = (await browser.pages())[0];page.on('console', msg => console.log('PAGE LOG:', msg.text()));await page.goto('https://open.toutiao.com');await page.evaluate(() => console.log(`url is ${location.href}`));const newsTitle = await page.evaluate((sel) => {const $els = document.querySelectorAll(sel);return Array.from($els).map((v) => {console.log(v.innerText); // 会被page.on 'console' 监听到return v.innerText})}, 'section h3');console.log(newsTitle) // 可以处理新闻标题。await page.screenshot({path: 'toutiao.png'}); // 屏幕快照await browser.close();
})();

模拟用户操作

这个功能用途挺多的,比如自动登陆,e2e测试,刷赞,抢票什么的,当然如果能跳过验证码的话。

github 登陆

模拟输入用户名和密码。

    await page.goto('https://github.com/login');await page.click('#login_field');await page.type('username');await page.click('#password');await page.type('password');await page.click('#login > form > div.auth-form-body.mt-3 > input.btn.btn-primary.btn-block');await page.waitForNavigation();

puppetter提供了page.focus,page.click,page.type,page.$eval(获取dom属性)等等api,鼠标位置,按键按下,tap,页面跳转众多用户可操作的api,都可以通过程序来模拟。

对这种模拟登陆,puppeteer还贴心的提供了这种api - -!page.type('#mytextarea', 'World', {delay: 100}); // Types slower, like a user

ui测试

之前分享过的testcafe,跟puppeteer的api非常像,testcafe是一个自动化测试框架,他与puppeteer不同的一点就是他集成了mocha断言库。
puppeteer和testcafe都提供了一套自动化测试的环境。puppeteer做e2e的测试需要自己选一个断言库,不过无伤大雅。

请求拦截/模拟请求

puppeteer比testcafe好的一点就是支持请求拦截,记得当初用testcafe测试请求是否被发出用了很多黑科技,提过issue。。

const puppeteer = require('puppeteer');puppeteer.launch({headless: false, slowMo: 250}).then(async browser => {const page = await browser.newPage();await page.setRequestInterception(true);page.on('console', msg => console.log('PAGE LOG:', msg.text()));page.on('request', interceptedRequest => {if (interceptedRequest.url().endsWith('.png') || interceptedRequest.url().endsWith('.jpg'))interceptedRequest.abort();elseinterceptedRequest.continue();});await page.goto('https://open.toutiao.com');
//   await browser.close();
});

提供了request,response事件,可以拦截请求,首先需要打开这个开关await page.setRequestInterception(true);
这里的例子就是停掉所有的png和jpg请求。
拦截能做的东西有很多,比如一些爬虫可以通过拦截请求捕获一些数据,来处理一些东西。

修改环境

puppeteer可以通过page.setViewport,page.setUserAgent来修改访问的环境。

await page.setViewport({width: 1920,height: 1080
});await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36');

puppeteer/DeviceDescriptors还给我们封装好了一些环境,比如:

const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhone = devices['iPhone 6'];puppeteer.launch().then(async browser => {const page = await browser.newPage();await page.emulate(iPhone); // emulate的配置有Viewport,UserAgent等等。之前的setUserAgent等方法是它的语法糖。await page.goto('https://www.google.com');// other actions...await browser.close();
});

性能测试

可以生成一个trace.json的文件,供chrome控制台解析,await page.metrics()还可以给出一些性能测试的数据。

const puppeteer = require('puppeteer');
(async () => {const browser = await puppeteer.launch();const page = await browser.newPage();await page.tracing.start({path: 'trace.json'})await page.goto('https://open.toutiao.com')await page.tracing.stop()const metrics = await page.metrics()console.log(metrics)await browser.close();
})();
// output
{ Timestamp: 27888.820538,Documents: 2,Frames: 1,JSEventListeners: 58,Nodes: 171,LayoutCount: 20,RecalcStyleCount: 26,LayoutDuration: 0.042335,RecalcStyleDuration: 0.010091,ScriptDuration: 0.124838,TaskDuration: 0.000039,JSHeapUsedSize: 6388448,JSHeapTotalSize: 10334208 }

https://www.cnblogs.com/dh-dh/p/8490047.html

linux 安装 Headless Chrome

https://chromedriver.storage.googleapis.com/index.html?path=2.34/

http://chromedriver.storage.googleapis.com/index.html

看到网上基本没有最新的chromedriver与chrome的对应关系表,便兴起整理了一份如下,希望对大家有用:

chromedriver版本 支持的Chrome版本
v2.35 v62-64
v2.34 v61-63
v2.33 v60-62
v2.32 v59-61
v2.31 v58-60
v2.30 v58-60
v2.29 v56-58
v2.28 v55-57
v2.27 v54-56
v2.26 v53-55
v2.25 v53-55
v2.24 v52-54
v2.23 v51-53
v2.22 v49-52
v2.21 v46-50
v2.20 v43-48
v2.19 v43-47
v2.18 v43-46
v2.17 v42-43
v2.13 v42-45
v2.15 v40-43
v2.14 v39-42
v2.13 v38-41
v2.12 v36-40
v2.11 v36-40
v2.10 v33-36
v2.9 v31-34
v2.8 v30-33
v2.7 v30-33
v2.6 v29-32
v2.5 v29-32
v2.4 v29-32

综合上面的表格,我们下载chrome可以到这里选择

https://dl.lancdn.com/landian/software/chrome/m/

chromedriver可以到这里下载

https://chromedriver.storage.googleapis.com/index.html

下面是一片chrome和phantomjs的文章

http://insights.thoughtworks.cn/phantomjs-and-chrome-headless/

附:
所有chromedriver均可在下面链接中下载到:

http://chromedriver.storage.googleapis.com/index.html

现在有一点好的是出了按照chrome版本对应的driver,直接按照浏览器版本去找对应的driver(只对应大版本就行),不用再费心去对应了,大家可以尝试一下:

有些同学说下不了,到taobao下也是可以的:

http://npm.taobao.org/mirrors/chromedriver/

前言

公司的爬虫项目使用了selenium+phantomjs,这个做过爬虫的应该都用过,但是缺点也很明显,慢,占用资源等,本身还有很多小坑就不一一列举了

后来无意中发现了headless,
参考这篇文章:https://intoli.com/blog/making-chrome-headless-undetectable/

经过安装测试,效果确实比phantomjs好很多,目前已有的资料都是使用nodejs,python相关的资料不多,只能等大佬们整理了。

这里记录一下安装的过程

安装chrome
需要V59以上版本
下载地址:https://www.landiannews.com/archives/36966.html

下载driver
selenium调用需要使用到
下载地址:https://sites.google.com/a/chromium.org/chromedriver/downloads

安装调试
下载安装chromedriver

mkdir chrome
cd chrome
wget https://chromedriver.storage.googleapis.com/2.31/chromedriver_linux64.zip
unzip chromedriver_linux64.zip
cd
vi .bashrc #添加环境变量
export PATH=/home/username/chrome:$PATH #在最后一行添加后保存退出
source ~/.bashrc #立即生效

下载安装chrome

wget https://dl.lancdn.com/landian/software/chrome/m/60.0.3112.90_amd64.debsudo apt -f -y install
sudo dpkg -i 60.0.3112.90_amd64.deb

调试安装结果
新建一个.py文件

# coding=utf-8
from selenium import webdriver
from selenium.webdriver.chrome.options import Optionsurl="http://news.163.com/"
chrome_options = Options()
# specify headless mode
chrome_options.add_argument("--headless")
browser = webdriver.Chrome(chrome_options=chrome_options)
browser.set_page_load_timeout(300)
browser.set_script_timeout(300)
browser.get(url)
title=browser.find_elements_by_xpath('//div[@id="js_top_news"]/h2/a')
print title[0].get_attribute('innerHTML')
browser.quit()

原文链接:https://blog.csdn.net/goodzyw/article/details/77269875

phantomJs之殇,chrome-headless之生

技术雷达快讯:自2017年中以来,Chrome用户可以选择以headless模式运行浏览器。此功能非常适合运行前端浏览器测试,而无需在屏幕上显示操作过程。在此之前,这主要是PhantomJS的领地,但Headless Chrome正在迅速取代这个由JavaScript驱动的WebKit方法。Headless Chrome浏览器的测试运行速度要快得多,而且行为上更像一个真正的浏览器,虽然我们的团队发现它比PhantomJS使用更多的内存。有了这些优势,用于前端测试的Headless Chrome很可能成为事实上的标准。

随着Google在Chrome 59版本放出了headless模式,Ariya Hidayat决定放弃对Phantom.js的维护,这也标示着Phantom.js 统治fully functional headless browser的时代将被chrome-headless代替。

Headless Browser

也许很多人对无头浏览器还是很陌生,我们先来看看维基百科的解释:

A headless browser is a web browser without a graphical user interface.

Headless browsers provide automated control of a web page in an environment similar to popular web browsers, but are executed via a command-line interface or using network communication.

对,就是没有页面的浏览器。多用于测试web、截图、图像对比、测试前端代码、爬虫(虽然很慢)、监控网站性能等。

为什么要使用headless测试?

headless broswer可以给测试带来显著好处:

  1. 对于UI自动化测试,少了真实浏览器加载css,js以及渲染页面的工作。无头测试要比真实浏览器快的多。
  2. 可以在无界面的服务器或CI上运行测试,减少了外界的干扰,使自动化测试更稳定。
  3. 在一台机器上可以模拟运行多个无头浏览器,方便进行并发测试。

headless browser有什么缺陷?

以phantomjs为例

  1. 虽然Phantom.js 是fully functional headless browser,但是它和真正的浏览器还是有很大的差别,并不能完全模拟真实的用户操作。很多时候,我们在Phantom.js发现一些问题,但是调试了半天发现是Phantom.js自己的问题。
  2. 将近2k的issue,仍然需要人去修复。
  3. Javascript天生单线程的弱点,需要用异步方式来模拟多线程,随之而来的callback地狱,对于新手而言非常痛苦,不过随着es6的广泛应用,我们可以用promise来解决多重嵌套回调函数的问题。
  4. 虽然webdriver支持htmlunit与phantomjs,但由于没有任何界面,当我们需要进行调试或复现问题时,就非常麻烦。

那么Headless Chrome与上面提到fully functional headless browser又有什么不同呢?

什么是Headless Chrome?

Headless Chrome 是 Chrome 浏览器的无界面形态,可以在不打开浏览器的前提下,使用所有Chrome支持的特性,在命令行中运行你的脚本。相比于其他浏览器,Headless Chrome 能够更加便捷的运行web自动化测试、编写爬虫、截取图等功能。

有的人肯定会问:看起来它的作用和phantomjs没什么具体的差别?

对,是的,Headless Chrome 发布就是来代替phantomjs。

我们凭什么换用Headless Chrome?

  1. 我爸是Google,那么就意味不会出现phantomjs近2k问题没人维护的尴尬局面。 比phantomjs有更快更好的性能。
  2. 有人已经做过实验,同一任务,Headless Chrome要比现phantomjs更加快速的完成任务,且占用内存更少。(https://hackernoon.com/benchmark-headless-chrome-vs-phantomjs-e7f44c6956c)
  3. chrome对ECMAScript 2017 (ES8)支持,同样headless随着chrome更新,意味着我们也可以使用最新的js语法来编写的脚本,例如async,await等。
  4. 完全真实的浏览器操作,chrome headless支持所有chrome特性。
  5. 更加便利的调试,我们只需要在命令行中加入–remote-debugging-port=9222,再打开浏览器输入localhost:9222(ip为实际运行命令的ip地址)就能进入调试界面。

能带给QA以及项目什么好处?

前端测试改进

以目前的项目来说,之前的前端单元测试以及组件测试是用karma在phantomjs运行的,非常不稳定,在远端CI上运行时经常会莫名其妙的挂掉,也找不出来具体的原因,自从Headless Chrome推出后,我们将phantomjs切换成Headless Chrome,再也没有出现过异常情况,切换也非常简单,只需要把karma.conf.js文件中的配置改下就OK了。如下

customLaunchers: { myChrome: { base: 'ChromeHeadless', flags: ['--no-sandbox', '--disable-gpu', '--remote-debugging-port=9222'] } },browsers: ['myChrome'],

UI功能测试改进

原因一,Chrome-headless能够完全像真实浏览器一样完成用户所有操作,再也不用担心跑测试时,浏览器受到干扰,造成测试失败

原因二,之前如果我们像要在CI上运行UI自动化测试,非常麻烦。必须使用Xvfb帮助才能在无界面的Linux上 运行UI自动化测试。(Xvfb是一个实现了X11显示服务协议的显示服务器。 不同于其他显示服务器,Xvfb在内存中执行所有的图形操作,不需要借助任何显示设备。)现在也只需要在webdriver启动时,设置一下chrome option即可,以capybara为例:

Capybara.register_driver :selenium_chrome do |app|
Capybara::Selenium::Driver.new(app, browser: :chrome,desired_capabilities: {"chromeOptions" => {"args" => [ "--incognito","--allow-running-insecure-content","--headless","--disable-gpu"]}})
end

无缝切换,只需更改下配置,就可以提高运行速度与稳定性,何乐而不为。

Google终极大招

Google 最近放出了终极大招——Puppeteer(Puppeteer is a Node library which provides a high-level API to control headless Chrome over the DevTools Protocol. It can also be configured to use full (non-headless) Chrome.)

类似于webdriver的高级别的api,去帮助我们通过DevTools协议控制无界面Chrome。

在puppteteer之前,我们要控制chrome headless需要使用chrome-remote-interface来实现,但是它比 Puppeteer API 更接近低层次实现,无论是阅读还是编写都要比puppteteer更复杂。也没有具体的dom操作,尤其是我们要模拟一下click事件,input事件等,就显得力不从心了。

我们用同样2段代码来对比一下2个库的区别。

首先来看看 chrome-remote-interface

const chromeLauncher = require('chrome-launcher');
const CDP = require('chrome-remote-interface');
const fs = require('fs');
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' : ''
]
});
}
(async function() {const chrome = await launchChrome();const protocol = await CDP({port: chrome.port});const {Page, Runtime} = protocol;await Promise.all([Page.enable(), Runtime.enable()]);Page.navigate({url: 'https://www.github.com/'});await Page.loadEventFired(console.log("start"));const {data} = await Page.captureScreenshot();fs.writeFileSync('example.png', Buffer.from(data, 'base64'));// Wait for window.onload before doing stuff.  protocol.close();chrome.kill(); // Kill Chrome.

再来看看 puppeteer

const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://www.github.com');
await page.screenshot({path: 'example.png'});
await browser.close();
})();

对,就是这么简短明了,更接近自然语言。没有callback,几行代码就能搞定我们所需的一切。

总结

目前Headless Chrome仍然存在一些问题,还需要不断完善,我们应该拥抱变化,适应它,让它给我们的工作带来更多帮助。

用Python驱动Headless Chrome相关推荐

  1. python chrome headless_使用Python控制Headless Chrome

    首先要解释一下 Headless Chrome,通俗的讲就是运行一个没有GUI的Chrome,在 Headless Chrome 出现以前有 PhantomJS ,但是自从 Headless Chro ...

  2. python selenium headless chrome chromedriver 等安装

    python selenium 略 chrome: https://blog.csdn.net/zhuyiquan/article/details/79537623 6及以下版本不适用 6及以下版本不 ...

  3. 在Docker中使用Python Selenium和Headless Chrome进行网站自动化测试的方法

    by Joyz 通过乔伊斯 在Docker中使用Python Selenium和Headless Chrome进行网站自动化测试的方法 (A recipe for website automated ...

  4. Python+selenium 自动化-chrome驱动的下载安装

    chrome驱动下载 chrome驱动获取: chromedriver.storage.googleapis.com 如何查看对应浏览器版本的驱动: 不同的版本的驱动支持不同版本的浏览器,所以版本一定 ...

  5. Web自动化之Headless Chrome概览

    Web自动化 这里所说的Web自动化是所有跟页面相关的自动化,比如页面爬取,数据抓取,页面内容检测,页面功能测试,页面加载性能测试,页面回归测试等等,当前主要由如下几种解决方式: 文本数据获取 这就是 ...

  6. 初探 Headless Chrome

    2019独角兽企业重金招聘Python工程师标准>>> 什么是 Headless Chrome Headless Chrome 是 Chrome 浏览器的无界面形态,可以在不打开浏览 ...

  7. centos安装使用puppeteer和headless chrome

    Google推出了无图形界面的headless Chrome之后,可以直接在远程服务器上直接跑一些测试脚本或者爬虫脚本了,猴开心!Google还附送了Puppeteer用于驱动没头的Chome. 阿里 ...

  8. 探索Headless Chrome

    作者:陈宁,就职于饿了么先后从事电商.CRM开发,经历前端从蛮荒到现代的过程,热爱新技术,推崇自动化. 责编:陈秋歌,关注前端开发领域,寻求报道或者投稿请发邮件chenqg#csdn.net. 本文为 ...

  9. Headless Chrome入门

    Headless Chrome指在headless模式下运行谷歌浏览器.本质就是不用谷歌运行谷歌!它将由Chromium和Blink渲染引擎提供的所有现代网页平台的特征都转化成了命令行. 它有什么用? ...

最新文章

  1. rabbitmq利用死信队列+TTL 实现延迟队列
  2. centos 6.3 安装reids
  3. TZOJ--3560: Ordered Fractions (枚举)
  4. Golang之gjson
  5. JAVA 入门(一)
  6. python写小猪佩奇_python之小猪佩奇
  7. CodeForces 592C The Big Race
  8. 库克:10年内可能离开苹果
  9. 四叶草社交平台——十天冲刺(7)
  10. ❤️Spring的静态、动态代理模式
  11. python项目开发实例-有趣的十个Python实战项目,让你瞬间爱上Python!
  12. 启用了文件索引,干脆连文件都找不到了
  13. ios6.x 插件介绍及常用源
  14. windows 中获取字体文件名
  15. java语言程序设计二级_计算机二级Java语言程序设计试题
  16. kali linux嗅探图片_kali linux 密码嗅探工具 Dsniff 详解
  17. 基于Quartz实现定时任务-框架学习
  18. 学生上课睡觉班主任怎么处理_学生上课睡觉,老师该怎么处理?
  19. 200个句子涵盖了高中英语4500词汇
  20. 5、ORB-SLAM闭环检测之通过求解出来的sim3寻找当前关键帧和闭环候选帧之间的更多匹配

热门文章

  1. 回测框架之计算收益模块
  2. Java :个人账目管理系统
  3. Java的反射机制 及 操作Class类
  4. 一个毕业设计 家庭理财app
  5. 系列文章-大数阶算之计算从入门到精通(序)
  6. 小米10s返回键设置步骤分享(图文教程)
  7. 投资理财财经 现在每个月可以抽出2000元的闲钱,投资什么项目比较好?
  8. 闭环管理中断裂的一环
  9. webpack5图片打包处理
  10. 面试-cookies和session