6、如何抓取 iframe 中的元素
一个 Frame 包含了一个执行上下文(Execution Context),我们不能跨 Frame 执行函数,一个页面中可以有多个 Frame,主要是通过 iframe 标签嵌入的生成的。其中在页面上的大部分函数其实是 page.mainFrame().xx 的一个简写,Frame 是树状结构,我们可以通过 frame.childFrames() 遍历到所有的 Frame,如果想在其它 Frame 中执行函数必须获取到对应的 Frame 才能进行相应的处理
以下是在登录 188 邮箱时,其登录窗口其实是嵌入的一个 iframe,以下代码时我们在获取 iframe 并进行登录
(async () => { const browser = await puppeteer.launch({headless: false, slowMo: 50}); const page = await browser.newPage(); await page.goto('https://www.188.com'); //点击使用密码登录 let passwordLogin = await page.waitForXPath('//*[@id="qcode"]/div/div[2]/a'); await passwordLogin.click(); for (const frame of page.mainFrame().childFrames()){ //根据 url 找到登录页面对应的 iframe if (frame.url().includes('passport.188.com')){ await frame.type('.dlemail', 'admin@admin.com'); await frame.type('.dlpwd', '123456'); await Promise.all([ frame.click('#dologin'), page.waitForNavigation() ]); break; } } await page.close(); await browser.close(); })();
7、页面性能分析
Puppeteer 提供了对页面性能分析的工具,目前功能还是比较弱的,只能获取到一个页面性能执行的数据,如何分析需要我们自己根据数据进行分析,据说在 2.0 版本会做大的改版: - 一个浏览器同一时间只能 trace 一次 - 在 devTools 的 Performance 可以上传对应的 json 文件并查看分析结果 - 我们可以写脚本来解析 trace.json 中的数据做自动化分析 - 通过 tracing 我们获取页面加载速度以及脚本的执行性能
(async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.tracing.start({path: './files/trace.json'}); await page.goto('https://www.google.com'); await page.tracing.stop(); /* continue analysis from 'trace.json' */ browser.close(); })();
8: 文件的上传和下载
在自动化测试中,经常会遇到对于文件的上传和下载的需求,那么在 Puppeteer 中如何实现呢?
(async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); //通过 CDP 会话设置下载路径 const cdp = await page.target().createCDPSession(); await cdp.send('Page.setDownloadBehavior', { behavior: 'allow', //允许所有下载请求 downloadPath: 'path/to/download' //设置下载路径 }); //点击按钮触发下载 await (await page.waitForSelector('#someButton')).click(); //等待文件出现,轮训判断文件是否出现 await waitForFile('path/to/download/filename'); //上传时对应的 inputElement 必须是<input>元素 let inputElement = await page.waitForXPath('//input[@type="file"]'); await inputElement.uploadFile('/path/to/file'); browser.close(); })();
9、跳转新 tab 页处理
在点击一个按钮跳转到新的 Tab 页时会新开一个页面,这个时候我们如何获取该页面对应的 Page 实例呢?可以通过监听 Browser 上的 targetcreated 事件来实现,表示有新的页面创建:
let page = await browser.newPage(); await page.goto(url); let btn = await page.waitForSelector('#btn'); //在点击按钮之前,事先定义一个 Promise,用于返回新 tab 的 Page 对象 const newPagePromise = new Promise(res => browser.once('targetcreated', target => res(target.page()) ) ); await btn.click(); //点击按钮后,等待新tab对象 let newPage = await newPagePromise;
10、模拟不同的设备
Puppeteer 提供了模拟不同设备的功能,其中 puppeteer.devices 对象上定义很多设备的配置信息,这些配置信息主要包含 viewport 和 userAgent,然后通过函数 page.emulate 实现不同设备的模拟
const puppeteer = require('puppeteer'); const iPhone = puppeteer.devices['iPhone 6']; puppeteer.launch().then(async browser => { const page = await browser.newPage(); await page.emulate(iPhone); await page.goto('https://www.google.com'); await browser.close(); });