了解Puppeteer,可模拟登录和模拟不同设备
Puppeteer 是什么
- Puppeteer 是一个Node 库
- 其提供 API 控制 Chrome
- Puppeteer 翻译就是“操纵木偶的人”,我们可以通过 API 控制 Chrome
Puppeteer 能干嘛
最常用的功能:
- 模拟用户操作,进行 UI 测试
- 作为爬虫访问页面来收集数据
其他的功能,生成屏幕截图、自动执行表单提交、捕获页面时间轴分析性能、测试扩展程序等等。
怎么安装 Puppeteer
和使用其他 node 库一样
npm i puppeteer # yarn add puppeteer
怎么使用 Puppeteer
创建 Browser 实例
两种方式创建:
- launch:每次都要重新启动一个 Chrome 进程,启动参数可动态修改
- connect:可共用同一个 Chrome 实例,远程连接的时候,可部署在不同机器上
例子 - 打开百度:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ headless: false, // 有浏览器界面启动 slowMo: 100, // 放慢浏览器执行速度,方便测试观察 args: ['-no-sandbox', '--window-size=1280,960'], //启动 Chrome 的参数 }); const page = await browser.newPage(); await page.goto('https://www.baidu.com'); await page.close(); await browser.close(); })();
右击执行,会自动打开浏览器,新建页面,去百度,然后自己关闭
打开页面
打开页面主要有以下 API:
- goto:打开新页面
- goBack :回退到上一个页面
- goForward :前进到下一个页面
- reload :重新加载页面
- waitForNavigation:等待页面跳转
那什么情况下才能判断函数执行完毕呢? 两个参数:
- waitUtil:直到什么出现就算执行完毕
- timeout:如果超过这个时间还没有结束就抛出异常。
例子 - 打开百度
await page.goto('https://www.baidu.com', { timeout: 30 * 1000, waitUntil: [ 'load', //等待 “load” 事件触发 'domcontentloaded', //等待“domcontentloaded” 事件触发 'networkidle0', //在 500ms 内没有任何网络连接 'networkidle2', //在 500ms 内网络连接个数不超过 2 个 ], });
上面的 表示满足四个条件,这个函数才算执行完,才能继续往下执行。
理解两个环境
使用 Puppeteer 时,经常遇到在这两个环境之间交换数据:运行 Puppeteer 的 Node.js 环境和 Puppeteer 操作的页面 Page DOM
- Puppeteer 可在
Page DOM Environment
中执行代码 - Puppeteer 提供了
ElementHandle 和 JsHandle
, 将Page DOM Environment
中元素和对象封装成对应的Node.js 对象
,用这些对象的封装函数进行操作Page DOM
用法 1:截图
可以对页面截图,也可以对元素截图。
await page.goto('https://www.baidu.com'); //设置可视区域大小 await page.setViewport({ width: 1920, height: 800 }); // 页面截图 await page.screenshot({ path: path.resolve(__dirname, 'page.png'), fullPage: true, //边滚动边截图 }); // 元素截图 const input = await page.$('#form'); await input.screenshot({ path: path.resolve(__dirname, 'input.png') });
网络异常,图片无法展示
|
因为可以设置视图宽度,可以截图单元素,所以可以进行 UI 测试。
获取页面元素的其他方式:
- page.$('#uniqueId'):获取某个选择器对应的第一个元素
- page.$$('div'):获取某个选择器对应的所有元素
- page.$x('//img'):获取某个 xPath 对应的所有元素
- page.waitForXPath('//img'):等待某个 xPath 对应的元素出现 page.waitForSelector('#uniqueId'):等待某个选择- 器对应的元素出现
用法 2:模拟用户登录
打开网站,试着登录掘金
可以将代码直接复制到本地,然后将用户名和密码改成自己的,看下效果
const puppeteer = require('puppeteer'); const path = require('path'); // 有时候操作需要暂停下 const sleep = (time) => new Promise((resolve) => { setTimeout(resolve, time); }); const login = async ({ username, pwd }) => { const browser = await puppeteer.launch({ slowMo: 100, //放慢速度 headless: false, defaultViewport: { width: 1500, height: 780 }, ignoreHTTPSErrors: false, //忽略 https 报错 }); const page = await browser.newPage(); await page.goto('https://juejin.cn/'); // 先截图看下非登录页面 await page.screenshot({ path: path.resolve(__dirname, 'notLogin.png'), }); // 找到右上角登录按钮,点击 const btnLogin = await page.$('.login-button'); await btnLogin.click(); // 找到登录弹框的其他登录方式,点击 const btnOtherWay = await page.$('.clickable'); await btnOtherWay.click(); sleep(1000); // 输入账号 const inputUsername = await page.$('.account-input'); inputUsername.focus(); for (let i = 0; i < username.length; i++) { await inputUsername.type(username[i]); } // 输入密码 const inputPwd = await page.$('input[name="loginPassword"]'); inputPwd.focus(); for (let i = 0; i < pwd.length; i++) { await inputPwd.type(pwd[i]); } // 提交表单 const btnConfirm = await page.$('.auth-form .btn'); // 等待页面跳转完成,一般点击某个按钮需要跳转时,都需要等待 page.waitForNavigation() 执行完毕才表示跳转成功 await Promise.all([btnConfirm.click(), page.waitForNavigation()]); await sleep(3000); // 截图 await page.screenshot({ path: path.resolve(__dirname, 'login.png'), }); console.log('登录成功~'); await page.close(); await browser.close(); }; login({ username: 'xxx', pwd: 'xx' });
网络异常,图片无法展示
|
网络异常,图片无法展示
|
ElementHandle
提供了哪些操作元素的函数呢?
- elementHandle.click():点击某个元素
- elementHandle.tap():模拟手指触摸点击
- elementHandle.focus():聚焦到某个元素
- elementHandle.hover():鼠标 hover 到某个元素上
- elementHandle.type('hello'):在输入框输入文本
用法 3:植入 javascript 代码
Puppeteer 最强大的功能是,你可以在浏览器里执行任何你想要运行的 javascript 代码
// 打开任意网站 await page.evaluate(async () => { alert('哈哈哈'); });
有哪些函数可以在浏览器环境中执行代码呢?
- page.evaluate(pageFunction[, ...args]):在浏览器环境中执行函数
- page.evaluateHandle(pageFunction[, ...args]):在浏览器环境中执行函数,返回 JsHandle 对象
- page.evaluateOnNewDocument(pageFunction[, ...args]):创建一个新的 Document 时在浏览器环境中执行,会在页面所有脚本执行之前执行
- $$eval/$eval/exposeFunction
用法4:模拟不同设备
Puppeteer 提供了模拟不同设备的功能,可通过函数 page.emulate
实现不同设备的模拟
await page.emulate(puppeteer.devices['iPhone 6']); // 页面截图 await page.screenshot({ path: path.resolve(__dirname, 'page_6.png'), });
网络异常,图片无法展示
|