使用Puppeteer实现页面遍历的示例代码

 更新时间:2023年06月26日 11:40:48   作者:日拱一車  
很多时候我们需要遍历我们的页面来检查页面是否存在问题,以更好的保证可用性和安全性,下面就来讲讲如何使用puppeteer来实现页面遍历的功能吧

前言

很多时候我们需要遍历我们的页面来检查页面是否存在问题,以更好的保证可用性和安全性,所以遍历一个给定页面是比较通用的能力,是很多高级功能的基础。下面就介绍怎么使用puppeteer来实现页面遍历的功能。

基本算法

实现页面的遍历功能,我们需要实现几个基础的方法,如下:

  • 怎么获取到登录态
  • 页面如何打开
  • 获取到页面的可点击节点
  • 页面的滑动,点击,截图等基础功能
  • 页面请求的拦截,识别
  • 页面返回/退出

上述能力实现之后,将他们组合起来,就可以实现一个页面的遍历功能,我们分别讲解每个功能如何实现。

功能实现

登录态

不同的帐号有不同的登录方式,最通用的就是专门写一个脚本来实现登录功能。对于需要扫码登录的页面,其实是从服务端获取登录token,可以直接调用服务端来获取(前提是你自己的业务)。否则就只能老老实实的通过脚本来实现了(在浏览器端实现脚本相对容易)。

页面打开

puppeteer提供了专门的方法来打开页面,我们只要初始化之后,调用这个功能就可以了。代码如下:

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)
    /**
     * 开启监听页面请求数据
     */
    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;
}

获取页面的可点击点

拿到一个页面之后我们需要获取到他可点击的点位信息,以便我们后续遍历的时候操作,所以需要一个获取页面可点击点的方法。实现如下:

async function getClickableElements( targetFrame ){
    try{
        let sections = await targetFrame.$$('[data-clickable=true],.tr-tabbar-item')
        return sections;
    } catch (e) {
        console.log(e);
        return null;
    }
}

页面的滑动,点击,截图等基础功能

对于页面的滑动,点击和截图,有专门的方法来实现,代码如下:

function screenshot( page,picName ){
    return new Promise((resolve, reject) => {
        setTimeout(async () => {
            var newPage=null;
            try {
                var buf=null;
                if( newPagePromise ){
                    console.log('新开了一个页面');
                    newPage = await newPagePromise;
                    await newPage.waitFor(6000);
                    var currentUrl=await newPage.url();
                    console.log("new-Page-Url:"+currentUrl);
                    if(currentUrl&&currentUrl.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)
            }
        })
    })
}
// 元素点击
await element.tap(2000);

页面请求的拦截,识别

在执行过程中页面可能出现跳转,并且我们还需要监听页面的请求来检查是不是正常。实现如下:

function setPageWatcher(page) {
    page.on('requestfailed', error => {
       if(error.url()&&error.url().includes('https://login.xxx.com')){
           console.log("跳转到了登录页面:"+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();
    });
}

页面返回/退出

代码如下:

function pageBack( page, frameInfo,num ){
​​​​​​​     console.log("开始回到首页");
     return new Promise((resolve, reject) => {
         setTimeout(async () => {
             try {
                 let backIcons = await frameInfo.backIconFrame.$$('.backIcon');
                 if(backIcons.length>0&&!needReLogin){
                     try{
                         console.log("回到首页");
                         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('回到首页出错!',e);
                 resolve(reloadPage(page,num))
             }
         })
     })
}

以上基本功能就实现了,欢迎交流

以上就是使用Puppeteer实现页面遍历的示例代码的详细内容,更多关于Puppeteer页面遍历的资料请关注脚本之家其它相关文章!

相关文章

  • Nest 复杂查询示例解析

    Nest 复杂查询示例解析

    这篇文章主要为大家介绍了Nest 复杂查询示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • 使用nodejs连接mySQL写接口全过程(增删改查)

    使用nodejs连接mySQL写接口全过程(增删改查)

    这篇文章主要给大家介绍了关于使用nodejs连接mySQL写接口(增删改查)的相关资料,MySQL是一种常用的关系型数据库,它与Node.js的结合可以提供强大的数据存储和检索功能,需要的朋友可以参考下
    2023-12-12
  • 基于Node.js实现大文件断点续传的完整方案

    基于Node.js实现大文件断点续传的完整方案

    本文介绍了Vue前端和Node.js后端实现大文件断点续传的方法,前端通过分片上传、计算文件哈希、记录已上传分片索引实现断点续传;后端提供检查和上传分片、合并文件的接口,通过并发控制、错误重试等技术提高上传效率和稳定性,需要的朋友可以参考下
    2026-04-04
  • Node多进程的实现方法

    Node多进程的实现方法

    我们都知道 Node.js 是以单线程的模式运行的,但它使用的是事件驱动来处理并发,这样有助于我们在多核 cpu 的系统上创建多个子进程,从而提高性能
    2022-08-08
  • Node.js学习教程之Module模块

    Node.js学习教程之Module模块

    这篇文章主要给大家介绍了关于Node.js学习教程之Module模块的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Node.js具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-09-09
  • 整理几个关键节点深入理解nodejs

    整理几个关键节点深入理解nodejs

    这篇文章主要介绍了整理几个关键节点深入理解nodejs,文章围绕主题展开详细的内容介绍,需要的小伙伴可以参考一下,需要的小伙伴可以参考一下
    2022-07-07
  • nodejs log4js 使用详解

    nodejs log4js 使用详解

    这篇文章主要介绍了nodejs log4js 使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-05-05
  • Node.js包管理器npm的具体使用

    Node.js包管理器npm的具体使用

    Node.js安装包中都带有一个重要的工具 包管理器npm,本文主要介绍了Node.js包管理器npm的具体使用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • 在Node.js下运用MQTT协议实现即时通讯及离线推送的方法

    在Node.js下运用MQTT协议实现即时通讯及离线推送的方法

    这篇文章主要介绍了在Node.js下运用MQTT协议实现即时通讯及离线推送的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • Node.js API详解之 readline模块用法详解

    Node.js API详解之 readline模块用法详解

    这篇文章主要介绍了Node.js API详解之 readline模块用法,结合实例形式详细分析了Node.js API中readline模块基本函数、功能、用法及操作注意事项,需要的朋友可以参考下
    2020-05-05

最新评论