官方英文版API入口:github.com/GoogleChrom…. 漢化版API入口:yq.aliyun.com/articles/60….javascript
具體API我就不解釋,在前邊第一篇中已經給出學習的目錄了,可去看下基礎的,API實在是太多了,我這邊只列出我本身遇到的有問題的APIhtml
先給出具體代碼:一個登陸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();
})();
複製代碼
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真的不多了,至少我都是見到的單層的,如今已經不多會有多層了,不過少歸少並不表明沒有,因而本身寫了幾個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個句柄表明的含義,若是對句柄這個概念很懵逼的小夥伴自行去百度,我就不過多解釋啦!
輸入我用了另一個代碼childframe2.$eval(),這個是一個很強大的語法用處很大,後續我會把用法寫出來,有興趣的能夠先看下官方API:
childframe2.$eval('#input_01',input => input.value='第二次輸入:leftframe')
複製代碼