用Python驱动Headless Chrome
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可以给测试带来显著好处:
- 对于UI自动化测试,少了真实浏览器加载css,js以及渲染页面的工作。无头测试要比真实浏览器快的多。
- 可以在无界面的服务器或CI上运行测试,减少了外界的干扰,使自动化测试更稳定。
- 在一台机器上可以模拟运行多个无头浏览器,方便进行并发测试。
headless browser有什么缺陷?
以phantomjs为例
- 虽然Phantom.js 是fully functional headless browser,但是它和真正的浏览器还是有很大的差别,并不能完全模拟真实的用户操作。很多时候,我们在Phantom.js发现一些问题,但是调试了半天发现是Phantom.js自己的问题。
- 将近2k的issue,仍然需要人去修复。
- Javascript天生单线程的弱点,需要用异步方式来模拟多线程,随之而来的callback地狱,对于新手而言非常痛苦,不过随着es6的广泛应用,我们可以用promise来解决多重嵌套回调函数的问题。
- 虽然webdriver支持htmlunit与phantomjs,但由于没有任何界面,当我们需要进行调试或复现问题时,就非常麻烦。
那么Headless Chrome与上面提到fully functional headless browser又有什么不同呢?
什么是Headless Chrome?
Headless Chrome 是 Chrome 浏览器的无界面形态,可以在不打开浏览器的前提下,使用所有Chrome支持的特性,在命令行中运行你的脚本。相比于其他浏览器,Headless Chrome 能够更加便捷的运行web自动化测试、编写爬虫、截取图等功能。
有的人肯定会问:看起来它的作用和phantomjs没什么具体的差别?
对,是的,Headless Chrome 发布就是来代替phantomjs。
我们凭什么换用Headless Chrome?
- 我爸是Google,那么就意味不会出现phantomjs近2k问题没人维护的尴尬局面。 比phantomjs有更快更好的性能。
- 有人已经做过实验,同一任务,Headless Chrome要比现phantomjs更加快速的完成任务,且占用内存更少。(https://hackernoon.com/benchmark-headless-chrome-vs-phantomjs-e7f44c6956c)
- chrome对ECMAScript 2017 (ES8)支持,同样headless随着chrome更新,意味着我们也可以使用最新的js语法来编写的脚本,例如async,await等。
- 完全真实的浏览器操作,chrome headless支持所有chrome特性。
- 更加便利的调试,我们只需要在命令行中加入–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相关推荐
- python chrome headless_使用Python控制Headless Chrome
首先要解释一下 Headless Chrome,通俗的讲就是运行一个没有GUI的Chrome,在 Headless Chrome 出现以前有 PhantomJS ,但是自从 Headless Chro ...
- python selenium headless chrome chromedriver 等安装
python selenium 略 chrome: https://blog.csdn.net/zhuyiquan/article/details/79537623 6及以下版本不适用 6及以下版本不 ...
- 在Docker中使用Python Selenium和Headless Chrome进行网站自动化测试的方法
by Joyz 通过乔伊斯 在Docker中使用Python Selenium和Headless Chrome进行网站自动化测试的方法 (A recipe for website automated ...
- Python+selenium 自动化-chrome驱动的下载安装
chrome驱动下载 chrome驱动获取: chromedriver.storage.googleapis.com 如何查看对应浏览器版本的驱动: 不同的版本的驱动支持不同版本的浏览器,所以版本一定 ...
- Web自动化之Headless Chrome概览
Web自动化 这里所说的Web自动化是所有跟页面相关的自动化,比如页面爬取,数据抓取,页面内容检测,页面功能测试,页面加载性能测试,页面回归测试等等,当前主要由如下几种解决方式: 文本数据获取 这就是 ...
- 初探 Headless Chrome
2019独角兽企业重金招聘Python工程师标准>>> 什么是 Headless Chrome Headless Chrome 是 Chrome 浏览器的无界面形态,可以在不打开浏览 ...
- centos安装使用puppeteer和headless chrome
Google推出了无图形界面的headless Chrome之后,可以直接在远程服务器上直接跑一些测试脚本或者爬虫脚本了,猴开心!Google还附送了Puppeteer用于驱动没头的Chome. 阿里 ...
- 探索Headless Chrome
作者:陈宁,就职于饿了么先后从事电商.CRM开发,经历前端从蛮荒到现代的过程,热爱新技术,推崇自动化. 责编:陈秋歌,关注前端开发领域,寻求报道或者投稿请发邮件chenqg#csdn.net. 本文为 ...
- Headless Chrome入门
Headless Chrome指在headless模式下运行谷歌浏览器.本质就是不用谷歌运行谷歌!它将由Chromium和Blink渲染引擎提供的所有现代网页平台的特征都转化成了命令行. 它有什么用? ...
最新文章
- rabbitmq利用死信队列+TTL 实现延迟队列
- centos 6.3 安装reids
- TZOJ--3560: Ordered Fractions (枚举)
- Golang之gjson
- JAVA 入门(一)
- python写小猪佩奇_python之小猪佩奇
- CodeForces 592C The Big Race
- 库克:10年内可能离开苹果
- 四叶草社交平台——十天冲刺(7)
- ❤️Spring的静态、动态代理模式
- python项目开发实例-有趣的十个Python实战项目,让你瞬间爱上Python!
- 启用了文件索引,干脆连文件都找不到了
- ios6.x 插件介绍及常用源
- windows 中获取字体文件名
- java语言程序设计二级_计算机二级Java语言程序设计试题
- kali linux嗅探图片_kali linux 密码嗅探工具 Dsniff 详解
- 基于Quartz实现定时任务-框架学习
- 学生上课睡觉班主任怎么处理_学生上课睡觉,老师该怎么处理?
- 200个句子涵盖了高中英语4500词汇
- 5、ORB-SLAM闭环检测之通过求解出来的sim3寻找当前关键帧和闭环候选帧之间的更多匹配