puppeteer学习笔记(三)--API问题解决--切换frame和iframe框

终于环境搭建好啦,能够开始快乐的玩耍了,开始记录我遇到的问题了

官方英文版API入口:github.com/GoogleChrom…. 汉化版API入口:yq.aliyun.com/articles/60….javascript

具体API我就不解释,在前边第一篇中已经给出学习的目录了,可去看下基础的,API实在是太多了,我这边只列出我本身遇到的有问题的APIhtml

一、切换单层iframe框架

先给出具体代码:一个登陆163邮箱的例子 看一下效果图java

在这里插入图片描述
代码以下:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless:false});
  const page = await browser.newPage();
  await page.goto('https://mail.163.com/');
  await page.setViewport({width:1000,height:800});
  //切换iframe框代码
  await page.waitFor('#loginDiv>iframe');//等待个人iframe出现
  const frame = ( await page.frames() )[3];//经过索引获得个人iframe
  await frame.waitFor('.j-inputtext.dlemail');//等待用户名输入框出现
  await frame.type('.j-inputtext.dlemail','12345');//输入帐户
  await frame.waitFor('.dlpwd');//等待密码框出现
  await frame.type('.dlpwd','12345');//输入密码
  //等待3秒后退出浏览器
  await page.waitFor(3000);
  await browser.close();
})();
复制代码

当时学习这个可真是苦恼我了,查了好多资料,看了好多教程都没有解决切换的问题,都只是说使用page.frames()获得全部的frame框返回一个列表来使用,可是并无什么例子,看的我云里来雾里去的,幸亏我有UI自动化的功底,有一些思路,因而本身摸索出来了,话很少说、上分析吧:

1.首先在第9行我加了一个智能等待,等待包含输入帐户和密码的iframe框加载出来,有时候网络加载慢这个iframe框还没出来,可是其它的iframe已经加载出来了,而page.frames()语句照样会执行,这样就会找不到我要的iframe了,因此加一下等待 2. 第10行代码我用的是索引的方法直接获得个人iframe,由于没有name的属性不能找到,若是有name的属性能够这样写:git

const frame = await page.frames().find(f => f.name() === 'name');
复制代码

另外若是使用索引的时候能够这样查看列表有多少个值:github

const frame = await page.frames();//获得全部的frame框
console.log(frames.length);//查看获得的frame列表数量
复制代码

3.第11行我加了一个智能等待,等输入框出现,这个我不知道为何?若是我不加的话就会报错,找不到输入框,若是加上的话就没问题,若是谁知道怎么回事能够给我说下。 4.后面的12,13,14行都同样了就是正常的等待和输入就好啦。api

二、切换多层iframe框架

这个多层的iframe真的不多了,至少我都是见到的单层的,如今已经不多会有多层了,不过少归少并不表明没有,因而本身写了几个html为你们讲解一下吧! 先看下效果图: 浏览器

在这里插入图片描述
首先新建三个HTML文件和脚本文件,放到一个路径下,输入如下内容: input.html

<!DOCTYPE html>
<html> <head> <title>input</title> </head> <body> <input type="text" id="input_01"> </body> </html> 复制代码

frame.html网络

<!DOCTYPE html>
<html> <head> <title>frame</title> </head> <body> <iframe src="input.html" name="mainframe"></iframe> </body> </html>
复制代码

iframe.html框架

<!DOCTYPE html>
<html> <head> <title>iframe</title> </head> <body> <iframe src="frame.html" name="leftframe"></iframe> <iframe src="frame.html" name="rightframe"></iframe> <input type="text" id="input_02"> </body> </html> 复制代码

多层切换会有一些麻烦,脚本以下(PS:记得把page.goto()中的地址换成本身电脑的,由于是本地文件,每一个地址都不一样:less

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless:false});
  const page = await browser.newPage();
  await page.goto('file:///MAC/Study/27.Puppeteer/case/iframe.html');
  await page.setViewport({width:1000,height:800});
  // 获得第一个iframe框架
  const frame1 = await page.frames().find(f => f.name() === 'leftframe');
  // 获得第一个iframe框架的子框架
  const childframe1 = ( await frame1.childFrames() )[0];
  // 等待输入框出现,输入信息
  await childframe1.waitFor('#input_01');
  await childframe1.type('#input_01','第一次输入:leftframe');
  
  // 获得第二个iframe框架
  const frame2 = await page.frames().find(f => f.name() === 'rightframe');
  // 获得第二个iframe框架的子框架
  const childframe2 = ( await frame2.childFrames() )[0];
  // 等待输入框出现,输入信息
  await childframe2.waitFor('#input_01');
  await childframe2.type('#input_01','第一次输入:rightframe');

  // 在iframe外面的输入框输入文字,直接使用句柄进行操做,不用切换iframe
  await page.waitFor('#input_02');
  await page.type('#input_02','第一次输入:out');

  // 第二次输入
  // 在第一个iframe中清空文本再次输入,不用从新获取frame,直接使用句柄操做
  await page.waitFor(2000);
  await childframe1.waitFor('#input_01');
  await childframe1.$eval('#input_01',input => input.value='第二次输入:leftframe')
  // 在第二个iframe中清空文本再次输入,不用从新获取frame,直接使用句柄操做
  await page.waitFor(2000);
  await childframe2.waitFor('#input_01');
  await childframe2.$eval('#input_01',input => input.value='第二次输入:leftframe')
  // 在iframe最外面的清空文本再次输入,不用从新获取frame,直接使用句柄操做
  await page.waitFor(2000);
  await page.waitFor('#input_02');
  await page.$eval('#input_02',input => input.value='第二次输入:out');

  await page.waitFor(3000);
  await browser.close();
})();
复制代码

好啦,脚本和HTML文件完成了,我特地为每一个iframe添加了name的属性、本身运行看下效果吧: 那我就开始分析啦: 一、第9行中page.frames()获得全部的frame框架,而后用find(f => f.name() === 'leftframe')的函数获得左侧的iframe框架 二、第11行中使用frame1.childFrames()的函数获得儿子iframe框,用的句柄第9行获得的frame1,由于只有一个子框因此我直接用索引的方式获得 三、第1三、14行使用儿子iframe框的句柄childframe1进行操做等待和输入文字 四、16-22行脚本是操做第二个框架和第一个iframe是同样的。我就再也不多说了, 五、25-26是在最外面的input框输入文字,直接使用page的句柄操做 六、29-40行代码就是第二次输入文本了,为了能看清变化,特意等待了几秒, 七、你们可能会发现,而且疑问我第二次输入是直接进行操做的,没有切换iframe?恩这个值得说明下,咱们在用Selenium作UI自动化的时候切换进去一个iframe以后,操做其它的元素必须跳出来才能操做,由于Selenium只有driver一个句柄能够进行操做,可是看看我们的puppeteer脚本里的句柄:page、frame一、frmae二、childframe一、childframe2,足足五个句柄可使用呀,固然能够直接进行操做了,手动滑稽。这就是我喜欢这个框架的缘由, 八、补充说一下5个句柄表明的含义,若是对句柄这个概念很懵逼的小伙伴自行去百度,我就不过多解释啦!

  • page:表明整个页面的句柄,从标签body开始的,能够进行全部的操做
  • frame1:表明第一个左侧的,iframe框架的句柄,只能操做左侧iframe框架里面的元素
  • frmae2:表明第二个右侧的,iframe框架的句柄,只能操做右侧iframe框架里面的元素
  • childframe1:表明第一个左侧的iframe框架子元素的句柄,只能操做子元素里面的元素
  • childframe2:表明第二个右侧的iframe框架子元素的句柄,只能操做子元素里面的元素

输入我用了另一个代码childframe2.$eval(),这个是一个很强大的语法用处很大,后续我会把用法写出来,有兴趣的能够先看下官方API:

childframe2.$eval('#input_01',input => input.value='第二次输入:leftframe')
复制代码
相关文章
相关标签/搜索