使用Puppeteer實(shí)現(xiàn)頁(yè)面遍歷的示例代碼
前言
很多時(shí)候我們需要遍歷我們的頁(yè)面來檢查頁(yè)面是否存在問題,以更好的保證可用性和安全性,所以遍歷一個(gè)給定頁(yè)面是比較通用的能力,是很多高級(jí)功能的基礎(chǔ)。下面就介紹怎么使用puppeteer來實(shí)現(xiàn)頁(yè)面遍歷的功能。
基本算法
實(shí)現(xiàn)頁(yè)面的遍歷功能,我們需要實(shí)現(xiàn)幾個(gè)基礎(chǔ)的方法,如下:
- 怎么獲取到登錄態(tài)
- 頁(yè)面如何打開
- 獲取到頁(yè)面的可點(diǎn)擊節(jié)點(diǎn)
- 頁(yè)面的滑動(dòng),點(diǎn)擊,截圖等基礎(chǔ)功能
- 頁(yè)面請(qǐng)求的攔截,識(shí)別
- 頁(yè)面返回/退出
上述能力實(shí)現(xiàn)之后,將他們組合起來,就可以實(shí)現(xiàn)一個(gè)頁(yè)面的遍歷功能,我們分別講解每個(gè)功能如何實(shí)現(xiàn)。
功能實(shí)現(xiàn)
登錄態(tài)
不同的帳號(hào)有不同的登錄方式,最通用的就是專門寫一個(gè)腳本來實(shí)現(xiàn)登錄功能。對(duì)于需要掃碼登錄的頁(yè)面,其實(shí)是從服務(wù)端獲取登錄token,可以直接調(diào)用服務(wù)端來獲?。ㄇ疤崾悄阕约旱臉I(yè)務(wù))。否則就只能老老實(shí)實(shí)的通過腳本來實(shí)現(xiàn)了(在瀏覽器端實(shí)現(xiàn)腳本相對(duì)容易)。
頁(yè)面打開
puppeteer提供了專門的方法來打開頁(yè)面,我們只要初始化之后,調(diào)用這個(gè)功能就可以了。代碼如下:
async function openUrl( targetUrl ){ //const browser = await puppeteer.connect(config.browserLaunchOptions); const browser = await puppeteer.launch(config.browserLaunchOptions); console.log("userAgent:"+JSON.stringify(await browser.userAgent())); const page = await browser.newPage(); interactor(page) /** * 開啟監(jiān)聽頁(yè)面請(qǐng)求數(shù)據(jù) */ await setPageWatcher(page); await page.emulate(config.pageEmulateOptions); await page.goto(targetUrl, {timeout:config.timeoutMillSeconds, waitUntil: config.waitUntilStr}).catch(err => {}); await page.waitFor(10000); await waitForPageComplete(page,2); await setBrowserWatcher(browser); loginPageUrl = targetUrl; return page; }
獲取頁(yè)面的可點(diǎn)擊點(diǎn)
拿到一個(gè)頁(yè)面之后我們需要獲取到他可點(diǎn)擊的點(diǎn)位信息,以便我們后續(xù)遍歷的時(shí)候操作,所以需要一個(gè)獲取頁(yè)面可點(diǎn)擊點(diǎn)的方法。實(shí)現(xiàn)如下:
async function getClickableElements( targetFrame ){ try{ let sections = await targetFrame.$$('[data-clickable=true],.tr-tabbar-item') return sections; } catch (e) { console.log(e); return null; } }
頁(yè)面的滑動(dòng),點(diǎn)擊,截圖等基礎(chǔ)功能
對(duì)于頁(yè)面的滑動(dòng),點(diǎn)擊和截圖,有專門的方法來實(shí)現(xiàn),代碼如下:
function screenshot( page,picName ){ return new Promise((resolve, reject) => { setTimeout(async () => { var newPage=null; try { var buf=null; if( newPagePromise ){ console.log('新開了一個(gè)頁(yè)面'); newPage = await newPagePromise; await newPage.waitFor(6000); var currentUrl=await newPage.url(); console.log("new-Page-Url:"+currentUrl); if(currentUrl&¤tUrl.includes('https://login.xxx.com/login.htm?redirectURL=')){ currentUrl = currentUrl.replace('https://login.xxx.com/login.htm?redirectURL=',config.loginUrl); console.log("newUrl="+currentUrl); await openTargetUrl(newPage,currentUrl); } buf = await newPage.screenshot({ }) await newPage.close(); newPagePromise = null; await page.bringToFront(); } else { buf = await page.screenshot({ }) } if(buf){ console.log('截圖完成,開始上傳'); var picUrl =await util.uploadImageWithRetry(picName,buf); console.log("截圖成功:"+picUrl); resolve(picUrl) } resolve(null); } catch (e) { if (newPage) { await newPage.close(); } newPagePromise = null; await page.bringToFront(); console.log(e); reject(null) } }) }) } // 元素點(diǎn)擊 await element.tap(2000);
頁(yè)面請(qǐng)求的攔截,識(shí)別
在執(zhí)行過程中頁(yè)面可能出現(xiàn)跳轉(zhuǎn),并且我們還需要監(jiān)聽頁(yè)面的請(qǐng)求來檢查是不是正常。實(shí)現(xiàn)如下:
function setPageWatcher(page) { page.on('requestfailed', error => { if(error.url()&&error.url().includes('https://login.xxx.com')){ console.log("跳轉(zhuǎn)到了登錄頁(yè)面:"+error); needReLogin = true; } }) page.on('error', (error) => { //console.log(chalk.red('?? whoops! there was an error')) //console.log(error) }) page.on('pageerror', (error) => { //console.log(error) }) page.on('response',(response) => { if( "image"==response.request().resourceType() && response.url() && response.headers()['content-length'] && response.headers()['content-length'] >200 ){ allResource.push({ size: response.headers()['content-length'], type: response.request().resourceType(), url: response.url() }); } }) page.on('dialog', async dialog => { console.log("dialog"); await dialog.accept(); console.log(dialog.message()); //await dialog.dismiss(); }); }
頁(yè)面返回/退出
代碼如下:
function pageBack( page, frameInfo,num ){ ??????? console.log("開始回到首頁(yè)"); return new Promise((resolve, reject) => { setTimeout(async () => { try { let backIcons = await frameInfo.backIconFrame.$$('.backIcon'); if(backIcons.length>0&&!needReLogin){ try{ console.log("回到首頁(yè)"); await backIcons[0].tap(2000); await page.waitFor(2000); resolve(frameInfo); }catch (e) { resolve(reloadPage(page,num)); } } else { resolve(reloadPage(page,num)); } } catch (e) { console.log('回到首頁(yè)出錯(cuò)!',e); resolve(reloadPage(page,num)) } }) }) }
以上基本功能就實(shí)現(xiàn)了,歡迎交流
以上就是使用Puppeteer實(shí)現(xiàn)頁(yè)面遍歷的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Puppeteer頁(yè)面遍歷的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Node.js中fs模塊實(shí)現(xiàn)配置文件的讀寫操作
在Node.js中, fs模塊提供了對(duì)文件系統(tǒng)的訪問功能,我們可以利用它來實(shí)現(xiàn)配置文件的讀取和寫入操作,這篇文章主要介紹了Node.js中fs模塊實(shí)現(xiàn)配置文件的讀寫,需要的朋友可以參考下2024-04-04利用node.js搭建簡(jiǎn)單web服務(wù)器的方法教程
本文主題是使用node來搭建最簡(jiǎn)單的web服務(wù)器,其后可以自己根據(jù)需要深入了解,目前在開發(fā)過程中可以用來模擬與服務(wù)器進(jìn)行簡(jiǎn)單的交互,比如返回的資源控制等。需要的朋友可以參考學(xué)習(xí),下面來一起看看吧。2017-02-02Vue+Node服務(wù)器查詢Mongo數(shù)據(jù)庫(kù)及頁(yè)面數(shù)據(jù)傳遞操作實(shí)例分析
這篇文章主要介紹了Vue+Node服務(wù)器查詢Mongo數(shù)據(jù)庫(kù)及頁(yè)面數(shù)據(jù)傳遞操作,結(jié)合實(shí)例形式分析了node.js查詢MongoDB數(shù)據(jù)庫(kù)及vue前臺(tái)頁(yè)面渲染等相關(guān)操作技巧,需要的朋友可以參考下2019-12-12nodejs對(duì)express中next函數(shù)的一些理解
這篇文章主要介紹了nodejs對(duì)express中next函數(shù)的一些理解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09使用Node.js實(shí)現(xiàn)base64和png文件相互轉(zhuǎn)換的方法
這篇文章主要介紹了使用Node.js實(shí)現(xiàn)base64和png文件相互轉(zhuǎn)換的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03node.js使用express-fileupload中間件實(shí)現(xiàn)文件上傳
本文使用express作為服務(wù)端,使用express-fileupload庫(kù)提供的中間件函數(shù)來接受從客戶端傳來的圖片,并將圖片作為文件存儲(chǔ)在服務(wù)端,感興趣的可以了解一下2021-07-07nodejs獲取微信小程序帶參數(shù)二維碼實(shí)現(xiàn)代碼
這篇文章主要介紹了nodejs獲取微信小程序帶參數(shù)二維碼實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-04-04