Node.js库Puppeteer经常使用API及骚操做总结

导读

这篇文章,主要用于收集整理经常使用的Puppeteer的一些经常使用API操做,自动化操做,爬虫测试,基础使用等等。固然至因而什么是Puppeteer呢,咱们来看下官方介绍:Puppeteer是谷歌官方出品的一个经过DevTools协议控制headless ChromeNode库。能够经过Puppeteer的提供的api直接控制Chrome模拟大部分用户操做来进行UI Test或者做为爬虫访问页面来收集数据。 css

在这里插入图片描述

首先备注好中文API文档地址:点击打开Puppeteer中文文档API查看访问URL地址 官方API文档地址:github.com/GoogleChrom… 比较不错的新手文档资料参考:小一辈无产阶级码农的《Puppeteer 入门教程》html

环境和安装

cnpm i puppeteer -S
复制代码

安装的时候须要注意deshi ,Puppeteer安装时自带一个最新版本的Chromium,能够经过设置环境变量或者npm config中的PUPPETEER_SKIP_CHROMIUM_DOWNLOAD跳过下载。若是不下载的话,启动时能够经过puppeteer.launch([options])配置项中的executablePath指定Chromium的位置。git

基本使用

咱们能够经过操做Browser实例来操做浏览器做出对应的事情,好比生成页面,窗口截图、生成pdf文件(文字可复制),获取页面数据等等,这些都是能够作到的。github

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('http://rennaiqian.com');
  await page.screenshot({path: 'example.png'});
  await page.pdf({path: 'example.pdf', format: 'A4'});
  await browser.close();
})();
复制代码

固然,咱们也能够新增一个headless:true,不打开浏览器就能执行咱们的各类操做,默认后台运行,修改以下:npm

const browser = await puppeteer.launch({headless:false})
复制代码

new browser.newPage() : 这个方法能够打开一个新选项卡并返回选项卡的实例page,经过page上的各类方法能够对页面进行经常使用操做。上述代码就进行了截屏和打印pdf的操做。 json

在这里插入图片描述
固然咱们最经常使用仍是,动态的植入JS脚本,操做页面上的元素,而且获取一些信息,那咱们该如何来实现呢?咱们可使用 page.evaluate(pageFunction, ...args)来实现这一目的,向页面注入咱们的自定义函数:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('http://rennaiqian.com');

  // Get the "viewport" of the page, as reported by the page.
  const dimensions = await page.evaluate(() => {
    // 在这里能够进行DOM操做
    return {
      width: document.documentElement.clientWidth,
      height: document.documentElement.clientHeight,
      deviceScaleFactor: window.devicePixelRatio
    };
  });
  console.log('Dimensions:', dimensions);
  await browser.close();
})();
复制代码

爬虫相关实现

固然,这个puppeteer这个框架,用的最多的地方就是在数据爬虫,页面模拟点击操做,用户名密码自动输入,表单提交,cookie无密码登陆等等这些操做;api

1. 模拟切换设备

这些操做呢,基本上都须要识别当前的设备,因此咱们如何来模拟咱们的当前设备呢?咱们能够经过page.emulate(mobile)来模拟咱们所须要的设备,以下所示:数组

const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors'); // puppeteer内置的一些常见设备的模拟参数
const iPhone = devices['iPhone 6'];

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  await page.emulate(iPhone);
  await page.goto('https://www.example.com');
  // other actions...
  await browser.close();
});
复制代码

2. 模拟点击输入

使用puppeteer的童鞋大多数都是奔着,自动化测试,使用脚本自动操做页面内容来着,爬取动态加载网页;因此呢,模拟点击输入整个功能是很是重要,且十分方便的,很是相似于selenium框架,可是比这个框架配置要简单得多,直接安装就可使用了,好,接下来咱们就来看看这个点击输入又是怎么完成的呢?浏览器

首先咱们须要对点击输入分一下类别,分红 ==键盘==和==鼠标==操做,那咱们分别来看下有哪些键盘和鼠标操做?bash

2-1. 键盘操做

首先咱们列出经常使用的一些API,再罗列出经常使用的一些小案例:

  • keyboard.down(key[, options]) :触发 keydown 事件
  • keyboard.press(key[, options]) :按下某个键,key 表示键的名称,好比 ‘ArrowLeft’ 向左键,详细的键名映射* 请戳这里
  • keyboard.sendCharacter(char) :输入一个字符
  • keyboard.type(text, options) :输入一个字符串
  • keyboard.up(key) :触发 keyup 事件

接下来展现一些经常使用到的一些小案例:

page.keyboard.press("Shift"); //按下 Shift 键
page.keyboard.sendCharacter('嗨'); // 输入一个字符
page.keyboard.type('Hello'); // 一次输入完成
page.keyboard.type('World', {delay: 100}); // 像用户同样慢慢输入
复制代码

2-2. 鼠标操做
  • mouse.click(x, y, [options]) :移动鼠标指针到指定的位置,而后按下鼠标,这个其实 mouse.move 和mouse.down 或 mouse.up 的快捷操做
  • mouse.down([options]) :触发 mousedown 事件,options 可配置:
    • options.button 按下了哪一个键,可选值为 [left, right, middle], 默认是 left, 表示鼠标左键
    • options.clickCount 按下的次数,单击,双击或者其余次数
    • delay 按键延时时间
  • mouse.move(x, y, [options]): 移动鼠标到指定位置, options.steps 表示移动的步长
  • mouse.up([options]) :触发 mouseup 事件

3. 修改浏览器运行配置

在咱们爬虫的过程当中,常常会遇到各式各样请求头的问题,比较常常遇到的就是user-agent等等这些参数,因此若是咱们能够直接修改这些配置的话,就能够很好的进行爬虫工做了;并且呢,这个puppeteer同时给咱们提供了一些 API 可让咱们修改浏览器终端的配置:

  • Page.setViewport() :修改浏览器视窗大小
  • Page.setUserAgent() :设置浏览器的 UserAgent 信息
  • Page.emulateMedia() :更改页面的CSS媒体类型,用于进行模拟媒体仿真。 可选值为 “screen”, “print”, “null”, 若是设置为 null 则表示禁用媒体仿真。
  • Page.emulate() :模拟设备,参数设备对象,好比 iPhone, Mac, Android 等,爬H5页面,亲测很好用

再接着,咱们来看一下一些经常使用的小案例:

page.setViewport({width:1920, height:1080}); //设置视窗大小为 1920x1080
page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36');
page.emulateMedia('print'); //设置打印机媒体样式
复制代码

除此以外咱们还能够模拟非 PC 机设备, 好比下面这段代码模拟 iPhone 6 访问百度:

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);
  await page.goto('https://www.baidu.com');
  // other actions...
  await browser.close();
});
复制代码

4. 获取页面元素

这里呢,咱们来探讨下,如何使用pupeteer来获取页面的元素,以及元素里的内容及属性;由于这也是使用很是很是频繁的操做,可是呢,估计你们都比较熟悉,因此呢,把它放在后面进行讲解;

4-1. 获取页面的元素节点

(1) Page.$(selector) 获取单个元素,底层是调用的是 document.querySelector(), 因此选择器的 selector 格式遵循 css 选择器规范

let inputElement = await page.$("#search", input => input);
//下面写法等价
let inputElement = await page.$('#search');
复制代码

(2) Page.$$(selector) 获取一组元素,底层调用的是 document.querySelectorAll(). 返回 Promise(Array(ElemetHandle))元素数组.

const links = await page.$$("a");
//下面写法等价
const links = await page.$$("a", links => links);
复制代码
4-1. 获取页面的元素属性

Puppeteer 获取元素属性跟咱们平时写前段的js的逻辑有点不同,按照一般的逻辑,应该是现获取元素,而后在获取元素的属性。可是上面咱们知道 获取元素的 API 最终返回的都是 ElemetHandle 对象,而你去查看 ElemetHandle 的 API 你会发现,它并无获取元素属性的 API.

Puppeteer 专门提供了一套获取属性的 API, Page.$eval()Page.$$eval()

const value = await page.$eval('input[name=search]', input => input.value);
const href = await page.$eval('#a", ele => ele.href);
const content = await page.$eval('.content', ele => ele.outerHTML);
复制代码

5. 执行自定义的 JS 脚本

执行自定义脚本也是目前来讲爬虫中,比较经常使用的一些功能,经过自定义脚本去拿到接口的签名等等,都是比较一种很是不错的爬虫方式,好,那咱们就一块儿来看看如何向页面动态植入自定义脚本呢?

PuppeteerPage 对象提供了一系列 evaluate 方法,你能够经过他们来执行一些自定义的 js 代码,主要提供了下面三个 API

5-1. page.evaluate(pageFunction, …args)

这个page.evaluate返回一个可序列化的普通对象,pageFunction 表示要在页面执行的函数, args 表示传入给 pageFunction 的参数, 下面的 pageFunction 和 args 表示一样的意思。

const result = await page.evaluate(() => {
	return Promise.resolve(8 * 7);
});
console.log(result); // 56
复制代码

5-2. Page.evaluateHandle(pageFunction, …args)

这个evaluateHandle在 Page 上下文执行一个 pageFunction, 返回 JSHandle 实体

const aWindowHandle = await page.evaluateHandle(() => Promise.resolve(window));
aWindowHandle; // Handle for the window object. 

const aHandle = await page.evaluateHandle('document'); // Handle for the 'document'.
复制代码

下面这段代码实现获取页面的动态(包括js动态插入的元素) HTML 代码:

const aHandle = await page.evaluateHandle(() => document.body);
const resultHandle = await page.evaluateHandle(body => body.innerHTML, aHandle);
console.log(await resultHandle.jsonValue());
await resultHandle.dispose();
复制代码

5-3. Page.exposeFunction

Page.exposeFunction,这个 API 用来在页面注册全局函数,很是有用: 由于有时候须要在页面处理一些操做的时候须要用到一些函数,虽然能够经过 Page.evaluate() API 在页面定义函数,好比下面代码实现给 Page 上下文的 window 对象添加 md5 函数:

const puppeteer = require('puppeteer');
const crypto = require('crypto');

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  page.on('console', msg => console.log(msg.text));
  await page.exposeFunction('md5', text =>
    crypto.createHash('md5').update(text).digest('hex')
  );
  await page.evaluate(async () => {
    // use window.md5 to compute hashes
    const myString = 'PUPPETEER';
    const myHash = await window.md5(myString);
    console.log(`md5 of ${myString} is ${myHash}`);
  });
  await browser.close();
});
复制代码

能够看出,Page.exposeFunction API 使用起来是很方便的,也很是有用,在好比给 window 对象注册 readfile全局函数:

const puppeteer = require('puppeteer');
const fs = require('fs');

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  page.on('console', msg => console.log(msg.text));
  await page.exposeFunction('readfile', async filePath => {
    return new Promise((resolve, reject) => {
      fs.readFile(filePath, 'utf8', (err, text) => {
        if (err)
          reject(err);
        else
          resolve(text);
      });
    });
  });
  await page.evaluate(async () => {
    // use window.readfile to read contents of a file
    const content = await window.readfile('/etc/hosts');
    console.log(content);
  });
  await browser.close();
});
复制代码

6. 等待执行

等待执行相关的 API 主要由 Page.waitFor 所提供

  • page.waitFor(selectorOrFunctionOrTimeout[, options[, …args]]),下面三个的综合 API
  • page.waitForFunction(pageFunction[, options[, …args]]) ,等待 pageFunction 执行完成以后
  • page.waitForNavigation(options),等待页面基本元素加载完以后,好比同步的 HTML, CSS, JS 等代码
  • page.waitForSelector(selector[, options]) ,等待某个选择器的元素加载以后,这个元素能够是异步加载的,这个 API 很是有用,你懂的。

好比我想获取某个经过 js 异步加载的元素,那么直接获取确定是获取不到的。这个时候就可使用 page.waitForSelector 来解决:

await page.waitForSelector('.gl-item'); //等待元素加载以后,不然获取不到异步加载的元素
const links = await page.$$eval('.gl-item > .gl-i-wrap > .p-img > a', links => {
	return links.map(a => {
		return {
			href: a.href.trim(),
			name: a.title
		}
	});
});
复制代码

7. 自动化网页性能测试

经过 page.getMetrics() 能够获得一些页面性能数据, 捕获网站的时间线跟踪,以帮助诊断性能问题。

  • Timestamp 度量标准采样的时间戳
  • Documents 页面文档数
  • Frames 页面 frame 数
  • JSEventListeners 页面内事件监听器数
  • Nodes 页面 DOM 节点数
  • LayoutCount 页面布局总数
  • RecalcStyleCount 样式重算数
  • LayoutDuration 全部页面布局的合并持续时间
  • RecalcStyleDuration 全部页面样式从新计算的组合持续时间。
  • ScriptDuration 全部脚本执行的持续时间
  • TaskDuration 全部浏览器任务时长
  • JSHeapUsedSize JavaScript 占用堆大小
  • JSHeapTotalSize JavaScript 堆总量

总结

总的来讲, puppeteer 是一款很是不错的 headless 工具,操做简单,功能强大。用来作UI自动化测试,和一些小工具都是很不错的。

相关文章
相关标签/搜索