首页 > 其他分享 >Puppeteer实践:复杂的问题简单化

Puppeteer实践:复杂的问题简单化

时间:2024-03-22 10:30:23浏览次数:19  
标签:const 简单化 await 实践 Puppeteer puppeteer 数据 page

最近遇到一个需求需要将上千条的数据写入到基于Wordpress搭建的系统中,但是对于底层数据录的写入逻辑不是很清楚,通过sql各种写入也没有完全达到效果。

后面想了想或许可以换一个方向,不能从底层逻辑写入数据那就通过正常操作写入。由于数据量大所以需要自动化处理,这时候就想到了之前用过的Puppeteer,这个库可以模拟操作浏览器的各种行为,包括获取数据和操作提交等。对于这个场景很适合,不用管底层的实现逻辑,也不需要去扒源码了解各种加密加签的逻辑,只需要模拟操作提交数据即可。

复杂的问题瞬间简单了,在这篇文章中记录如何使用Puppeteer批量提交数量。

安装Puppeteer

在这之前确保你已经安装了Node.js。运行以下命令安装Puppeteer:

npm install puppeteer

Puppeteer脚本

接下来编写需要执行的脚本,创建一个名为puppeteer.js的文件,并添加以下代码:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: false 
  });
  const page = await browser.newPage();
  await page.goto('https://baidu.com');   
  await browser.close();
})();

puppeteer.launch() 是用于启动一个浏览器实例,为后续的网页操作和自动化测试提供基础。可以接受一些配置选项,如指定浏览器的路径、是否启用无头模式、设置视口大小等。完整配置还有很多,可查阅官网了解。

保持用户状态

需要写入的系统是需要登录后才能操作且需要多次操作,所以在操作过程中需要记录用户状态。这一点我们可以在初始化浏览器实例的时候配置 userDataDiruserDataDir 用于指定一个目录,该目录用于存储浏览器的用户数据,如缓存、Cookie、本地存储数据等。可以让 Puppeteer 在每次启动浏览器时都使用相同的用户数据,从而保持用户状态的连续性。

const browser = await puppeteer.launch({
    userDataDir: 'userA' 
});

模拟登录

然后就是第一次的模拟登录和后续操作校验登录状态。通过 page.cookies() 获取存储的用户数据,如果不存在则模拟登录。

// 从puppeteer中获取cookie
const cookies = await page.cookies(); 
let isLogin = false
cookies.forEach(json => {
    if (json.name.includes('wordpress')) {
        isLogin = true
    }
});

console.log('[ isLogin ] >', isLogin)

if (!isLogin) {
    // 模拟输入用户名密码
    await page.type('#user_login', 'XXXX', { delay: 100 });
    await page.type('#user_pass', 'XXXX', { delay: 100 });
    // 模拟点击
    await page.click('#rememberme', { delay: 110 });
    await page.click('#wp-submit', { delay: 120 });  
     // 等待页面完全加载
    await page.waitForNavigation()   
}

数据处理

接下来就是业务数据处理了,首先将数据转换成JSON方便批量处理。每次处理一批数组,这里在for循环中使用 Promise 同步处理,待所有的数据都处理完成后关闭浏览器结束脚本。在 performAsyncOperation 中执行具体的数据操作过程。

const list = require('./list.js')

function performAsyncOperation(item) {
    return new Promise(async (resolve, reject) => {
        // todo item
        resolve();
    });
}

// 使用async函数来包裹异步操作
async function processItems() {
    for (const item of list) {
        // 使用await等待异步操作完成
        await performAsyncOperation(item); 
    }
    console.log('All items processed');
    await browser.close();
}

processItems()

这里有一点特殊处理,要写入的数据是在iframe中的元素,需要通过以下方式对iframe中的dom进行修改赋值。

const elementHandle = await page.waitForSelector('#content_ifr');
const frame = await elementHandle.contentFrame();
await frame.waitForSelector('p:nth-child(1)');
const description = item.description
// 在 iframe 中使用 evaluate 方法来修改元素内的 DOM
await frame.evaluate((description) => {
    // 在这里可以编写 JavaScript 代码来修改 iframe 内的 DOM
    document.querySelector('p:nth-child(1)').textContent = description
}, description);

更新完一条数据后进行下一条数据的写入,这里页面提交数据后界面发生了变化,需要重新回到开始的页面继续处理。回到开始的发布页面后执行成功回调继续下一条数据处理,当所有的数据处理完成则结束脚本。

// 点击发布
await page.click('#publish')
// 等待页面更新
await page.waitForNavigation()
// 点击回到发布页面
await page.click('.page-title-action', { delay: 300 })
// 成功回调继续下一条处理
resolve();

总结

Puppeteer是一个强大的库,它能够让开发者以编程方式控制Chrome或Chromium。这使数据获取或操作页面数据变得更加容易,特别是对于需要与JavaScript交互的页面。

通过上面的例子,你应该对如何使用Puppeteer来处理数据有了一个基本的了解。Puppeteer的能力远不止于此,你可以创建更复杂的脚本来模拟用户登录、填写表单、获取签名数据等。希望这篇文章对你有所帮助~


看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~

专注前端开发,分享前端相关技术干货,公众号:南城大前端(ID: nanchengfe)

标签:const,简单化,await,实践,Puppeteer,puppeteer,数据,page
From: https://blog.csdn.net/qq_37247349/article/details/136932366

相关文章

  • Kubernetes之Pod基本原理与实践
    一、Pod的定义与基本用法1.Pod是什么Pod是可以在Kubernetes中创建和管理的、最小的可部署的计算单元。Pod不是进程,而是容器运行的环境。Pod所建模的是特定于应用的“逻辑主机”,其中包含一个或多个应用容器。当Pod包含多个应用容器时,这些容器的应用之间应该是......
  • 《Python从入门到实践》第九章 类
    面向对象编程是最有效的软件编写方法之一在面向对象编程时,你编写表示现实世界中的事物和情景的类,并基于这些类来创建对象。根据类来创建对象称为实例化,这让你能够使用类的实例创建和使用类创建Dog类classDog:"""一次模拟小狗的简单尝试"""def__init__(self,......
  • 微信团队分享:微信后端海量数据查询从1000ms降到100ms的技术实践
    本文由微信技术团队仇弈彬分享,原题“微信海量数据查询如何从1000ms降到100ms?”,本文进行了内容修订和排版优化。1、引言微信的多维指标监控平台,具备自定义维度、指标的监控能力,主要服务于用户自定义监控。作为框架级监控的补充,它承载着聚合前45亿/min、4万亿/天的数据量。当......
  • Java 8 内存管理原理解析及内存故障排查实践
    作者:vivo互联网服务器团队- ZengZhibin介绍Java8虚拟机的内存区域划分、内存垃圾回收工作原理解析、虚拟机内存分配配置,介绍各垃圾收集器优缺点及场景应用、实践内存故障场景排查诊断,方便读者面临内存故障时有一个明确的思路和方向。一、背景Java是一种流行的编程语言,可......
  • 【RAG实践】基于 LlamaIndex 和Qwen1.5搭建基于本地知识库的问答机器人
    什么是RAGLLM会产生误导性的“幻觉”,依赖的信息可能过时,处理特定知识时效率不高,缺乏专业领域的深度洞察,同时在推理能力上也有所欠缺。正是在这样的背景下,检索增强生成技术(Retrieval-AugmentedGeneration,RAG)应时而生,成为AI时代的一大趋势。RAG通过在语言模型生成答案......
  • Android第一行代码——快速入门 Kotlin 编程(3.6 Activity 的最佳实践)
    目录3.6        Activity的最佳实践3.6.1    知晓当前是在哪一个Activity3.6.2    随时随地退出程序 3.6.3    启动Activity的最佳写法3.6        Activity的最佳实践        关于Activity,你已经掌握了非常多......
  • 第一次实践spring cloud项目出的若干问题
    也许更好的阅读体验技术栈说明springcloud+eureka+feign+ribbon+hystrix+gateway+config+bus反序列化失败:Typedefinitionerror:[simpletype,classcom.elm.po.CommonResult];nestedexceptioniscom.fasterxml.jackson.databind.exc.InvalidDefinition......
  • 云原生最佳实践系列2:基于 MSE 云原生网关同城多活
    方案概述分布在同城多个机房内的应用同时对外提供服务。同城机房物理距离较小,一般小于50公里。同城多活架构的难点有三个:当某机房出现故障,能不能做到机房级的快速切换?如何实现非对等部署下的全局的流量负载均衡?对流量的精细化管控?常见的同城多活实现方式(如下图),在这个架构......
  • JAVA 线程池SingleThreadExecutor实践教程
    SingleThreadExecutor是一个单线程的Executor,它使用单个工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行。下面是使用SingleThreadExecutor的实践教程:步骤1:创建SingleThreadExecutor你可以使用Executors类提供的newSingleThreadExecutor方法来创......
  • JAVA线程池ScheduledThreadPool实践教程
    ScheduledThreadPool用于在给定的延迟之后,或者定期执行任务。以下是如何在Java中实践使用ScheduledThreadPool的步骤:步骤1:创建ScheduledThreadPool首先,使用Executors的newScheduledThreadPool方法来创建一个ScheduledThreadPool。参数是你想要在池中保持的线程数量。i......