python 自动化学习(四) pyppeteer 浏览器操作自动化

背景

之前我在工作中涉及到了很多地方都是重复性的页面点点点工作,又因为安全保密原则不开放接口和数据库,只有一个页面来提供点击进行操作,就想着用前面学的自动化来实现,但发现前面学的模拟操作对浏览器来说并没有那么友好,而后改用“selenium”,但是存在一个问题,我这里并不能直接访问外网,好不容易找到selenium的库文件,发现又需要相对应版本的浏览器引擎,导致我无法使用,在此期间我发现了另一个不需要浏览器引擎的库pyppeteer 成功实现了一部分功能,这里做一下笔记

 介绍

1、selenium   //跨浏览器,官方维护的比较好,资料也多,各个版本比较稳定,源码读起来舒服//缺点是配置时需要留心程序语言的版本和驱动版本以及浏览器版本,还有就是本身不支持步//需要重写源码或者利用grid分布式来实现异步2、pyppeteer  //是基于chrome官方为chromium定制的自动化测试框架puppeteer而//实现的一个python包装的非官方版本框架,最后一次更新是在2018年//优点就是速度比selenium快,支持异步,常被拿来做爬虫,//缺点就是兼容性很差,而且它没有跟随chromium以及puppeteer的迭代而更新//使用时会有很多问题。

安装

pip install pyppeteer==1.0.2

入门案例

我们打开浏览器、输入、点击按钮什么的都是是耗时的操作,我们下面通过使用异步关键字 async 和 await,定义了一个异步函数 main。通过在异步函数中使用 await 关键字,可以将耗时的操作转化为非阻塞的异步调用

import asyncio                          # 导入 asyncio 模块,用于编写异步代码
from pyppeteer import launch           # 导入 pyppeteer 的 launch 函数,用于启动浏览器async def main():                      # 定义一个异步函数 mainasyncio.get_event_loop().run_until_complete(main())    # 运行 main 函数

一、定义浏览器并打开页面

import asyncio
from pyppeteer import launchasync def main():browser = await launch(executablePath="C:\Program Files\Google\Chrome\Application\chrome.exe",headless=False,args=['--start-maximized'])page = await browser.newPage()await page.setViewport({'width':0,'height':0,'deviiceScaleFactor':1})await page.goto('https://www.baidu.com')await page.waitFor(10000)await browser.close()asyncio.get_event_loop().run_until_complete(main())

参数说明

async def main():browser = await launch(executablePath="C:\Program Files\Google\Chrome\Application\chrome.exe",headless=False,args=['--start-maximized'])#launch 定义一个浏览器实例#executablePath   本地谷歌浏览器路径#headless=False   有界面的浏览器#args=['--start-maximized']浏览器窗口最大化//在浏览器上创建一个新页面page = await browser.newPage()   //width 和height 自动匹配浏览器大小//deviiceScaleFactor 将页面的视口设置为浏览器的默认大小,并将设备像素比设置为 1await page.setViewport({'width':0,'height':0,'deviiceScaleFactor':1})//打开浏览器并跳转到指定地址   await page.goto('https://www.google.com')  //上面任务结束后等待10sawait page.waitFor(10000)//关闭浏览器await browser.close()

我们这里能打开浏览器并且跳转了,下面我们正常情况下需要做的就是模拟鼠标键盘的一些操作,我们这里以码云的登录注册平台来做测试

#注册地址,可能有变动直接百度搜索
https://gitee.com/signup?redirect_to_url=%2F%3Fchannel_utm_content%3D%25E5%25B9%25BF%25E5%2591%258A%25E8%2583%258C%25E6%2599%25AF%25E5%259B%25BE%26channel_utm_medium%3Dsem%26channel_link_type%3Dweb%26channel_utm_source%3D%25E7%2599%25BE%25E5%25BA%25A6%26sat_cf%3D2%26channel_utm_campaign%3D%25E5%2593%2581%25E4%25B8%2593%26channel_utm_term%3D%25E5%25B9%25BF%25E5%2591%258A%25E8%2583%258C%25E6%2599%25AF%25E5%259B%25BE%26_channel_track_key%3Du1BDg7fB%26link_version%3D1%26wl_src%3Dbaidu

二、寻找页面元素信息

浏览器页面根据我们分辨率大小和窗口大小,跳转浏览器的位置都会导致我们无法直接通过之前的方法获取坐标,这里我们依赖的是直接获取web页面的元素信息(span a dir id class等等)通过他们定位具体的元素坐标

登录页面查看元素

我们登录到注册页面按F12 进入开发者模式,点击查看栏能看到html的信息,点击左边的箭头,选择我们要查看的页面元素,下面图中是选择了第一个输入框的位置

 

 得到html信息

<input class="session-register__name" required="required" placeholder="姓名" maxlength="60" size="60" type="text" name="user[name]" id="user_name">

三、常见的几种获取元素坐标方法

各个场景的html编写的不相同,同一种方法切换场景后很可能就不好使了,这里放几种我常用的方法

1、通过元素class或id获取坐标

#基于class名称获取坐标
async def click_radio(page,selector):await page.waitForSelector(selector)  #等待元素出现element = await page.querySelector(selector)  #查找指定的元素信息if element:box = await  element.boundingBox()  #获取元素坐标和尺寸x = box['x']y = box['y']widht = box['width']height = box['height']await page.mouse.move(x + widht / 2,  y + height / 2)await page.mouse.down()  #模拟鼠标点击一次await page.mouse.up()else:print("element not found")

调用函数

async def main():
...#修改地址为码云await page.goto('https://gitee.com/signup?redirect_to_url=%2F%3Fchannel_utm_content%3D%25E8%25BF%259B%25E5%2585%25A5%25E5%25AE%2598%25E7%25BD%2591%26channel_utm_medium%3Dsem%26channel_link_type%3Dweb%26channel_utm_source%3D%25E7%2599%25BE%25E5%25BA%25A6%26sat_cf%3D2%26channel_utm_campaign%3D%25E5%2593%2581%25E4%25B8%2593%26channel_utm_term%3D%25E4%25B8%25BB%25E6%258C%2589%25E9%2592%25AE1%26_channel_track_key%3Dsee7zmAJ%26link_version%3D1%26wl_src%3Dbaidu')#调用自定义函数,传参page  class名称前面要加点"."await click_radio(page,".session-register__name")#模拟输入文本信息await page.keyboard.type("12345678")
...
asyncio.get_event_loop().run_until_complete(main())

注意

上面案例中使用的是class获取的坐标,如果没有定义class或者有多个相同的class时可以通过id获取,区别在于class传参是 "." 加class名称   而id传参是  "#" 加id名称

小知识

//其实在遇到不是特别复杂的情况下,可以不用上面的方法,比如输入账户密码之类的
await page.waitForSelector(#id名称/.类名)  

2、通过文本获取坐标

这个在申请某些东西的时候可能会经常用到,比如申请云服务,某某产品,自研平台等等,会有大量需要挨个点击的图标,用上面第一个的时候不好使了就用这个方法

获取按钮html

<button name="button" type="submit" id="btn-submit" class="ui orange fluid submit button register-btn-submit large" sa_evt="click_GiteeCommunity_signup_signup">立即注册</button>

 向上面有文本内容显示的就可以用,我们获取到他的文本内容"立即注册" 和元素名称button

async def click_center(page,selector,type):#定义检索元素格式test = "//" + type +"[text()=" + "\'" + selector + "\'" + "]"element = await page.waitForXPath(test)  #获取对应元素box = await element.boundingBox()   #获取坐标target_x = box['x'] + box['width'] // 2target_y = box['y'] + box['height'] // 2await page.mouse.click(target_x,target_y)

调用

async def main():browser = await launch(executablePath="C:\Program Files\Google\Chrome\Application\chrome.exe",headless=False,args=['--start-maximized'])page = await browser.newPage()await page.setViewport({'width':0,'height':0,'deviiceScaleFactor':1})await page.goto('https://gitee.com/signup?redirect_to_url=%2F%3Fchannel_utm_content%3D%25E8%25BF%259B%25E5%2585%25A5%25E5%25AE%2598%25E7%25BD%2591%26channel_utm_medium%3Dsem%26channel_link_type%3Dweb%26channel_utm_source%3D%25E7%2599%25BE%25E5%25BA%25A6%26sat_cf%3D2%26channel_utm_campaign%3D%25E5%2593%2581%25E4%25B8%2593%26channel_utm_term%3D%25E4%25B8%25BB%25E6%258C%2589%25E9%2592%25AE1%26_channel_track_key%3Dsee7zmAJ%26link_version%3D1%26wl_src%3Dbaidu')#调用函数,定义文本+元素并点击await click_center(page,"立即注册","button")await page.waitFor(10000)await browser.close()asyncio.get_event_loop().run_until_complete(main())

 测试通过上面俩方法能解决绝大部分问题,如果遇到的坐标有偏移,比如说我文本输入框在文本的右侧,我通常会用下面的方法

    target_x = box['x'] + box['width'] + 200target_y = box['y'] + box['height'] // 2

小知识

你遇到点击某个按钮后会跳转到下一步的时候,最好按钮按下后面的第一个步骤中添加 await page.waitForNavigation()  这个是等等页面加载完成

3、修改页面元素,然后基于页面元素输入

特殊情况下,上面的方法都不适用,比如说我遇到过一个常见,需要申请两个文件系统/app1 和/app2  一个50G  一个100G ,但他的输入框上只有一个class,并且每个class都是完全已有的,没有id什么其他的元素,特征就是初始值为一个输入框,可以新增一个输入框,我的想法我把第一个输入框的元素class进行修改,第二个元素出现时class类就和第一个元素不同了,然后基于这个修改后的class名称在做具体的操作

我这里通过密码那一栏获取到下面的代码
<input required="required" autocomplete="new-password" placeholder="密码不少于6位" data-password-regx="^(?=.*[0-9])(?=.*[a-zA-Z!@_#$%^&amp;*()\-+=,.?]).{6,32}$" type="password" name="user[password]" id="user_password">可以看到,他有一个id,但是没有做class我们用这个做实验

 案例

    await page.evaluate('''() => {const elements = document.querySelectorAll('#user_password');elements.forEach(element => {element.classList.add("ddd");});}''')#我们需要等等元素出现后在进行下面的操作await page.waitForSelector(".ddd")...#另外,单独说个事,如果切换页面后逻辑中存在多个等待页面加载完成,那么页面就不动了

可以看到上面图里他帮忙添加了一个class的名称,我们可以在后面去调用他,需要注意的是,如果你要添加的元素的id不唯一那么所有的元素都会去添加相同的class,如果碰到了多个class名称,如  app1 app2 app3    class的名称则需要设置为 .app1 .app2 .app3  如果是id则是 #app1  #app2 #app3

4、查找特定文本元素并点击

我又碰到一个特殊的案例,我没找到演示用的页面,当记录下笔记了,这个是应用于li的一个下拉选项的场景,和第二步类似

async def click_multiple(page,selector):elements = await page.JJ('li')for element in elements:text_content = await element.getProperty("textContent")text_content = await text_content.jsonValue()if selector in text_content:box = await  element.boundingBox()coordinates = {'x': box['x'],'y': box['y'],'width': box['width'],'height': box['height']}await element.click()

上面的函数是查找页面所有的 li 元素,并检查每个元素的文本内容中是否包含给定的选择器。如果找到了匹配的元素,则对该元素执行点击操作。

参数说明

async def click_multiple(page, selector):elements = await page.JJ('li')  # 查找页面中所有的 <li> 元素并保存在 elements 变量中for element in elements:  # 遍历 elements 中的每个元素text_content = await element.getProperty("textContent")  # 获取元素的文本内容text_content = await text_content.jsonValue()  # 将文本内容转换为 JSON 格式if selector in text_content:  # 检查文本内容是否包含给定的选择器box = await element.boundingBox()  # 获取元素的位置和大小coordinates = {'x': box['x'],  # 元素的 x 坐标'y': box['y'],  # 元素的 y 坐标'width': box['width'],  # 元素的宽度'height': box['height']  # 元素的高度}await element.click()  # 点击元素

四、读取excel表数据并使用

def open_xlsx():from openpyxl import load_workbookwb = load_workbook("111.xlsx")ws = wb["Sheet1"]data = []for row in ws.iter_rows(min_row=2): #从第二行开始算row_values = []for cell in row:row_values.append(cell.value)data.append(row_values)wb.close()return datadata = open_xlsx()#这里的user_list取出来的是表中每一行的数据,下面的0-1-2-3是每一列的数据
for user_list in data:print(user_list[0])

说明

def open_xlsx():from openpyxl import load_workbook# 打开 Excel 文件wb = load_workbook("111.xlsx")# 选择要读取的工作表ws = wb["Sheet1"]# 创建一个空的列表用于存储读取的数据data = []# 从第二行开始遍历每一行for row in ws.iter_rows(min_row=2):row_values = []# 遍历当前行的每一个单元格for cell in row:# 将单元格的值添加到行值列表中row_values.append(cell.value)# 将该行的值列表添加到数据列表中data.append(row_values)# 关闭 Excel 文件wb.close()# 返回读取的数据return data# 调用 open_xlsx 函数并获取数据
data = open_xlsx()# 遍历数据列表的每一行,并打印出每行的第一列数据
for user_list in data:print(user_list[0])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/45250.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安装pyrender和OSMesa

1&#xff09;安装 pyrender Pyrender是一个基于OpenGL的库&#xff0c;可以加载和渲染三维网格、点云、相机等对象3。 pip install pyrender 2&#xff09;理解PyOpenGL和OSMesa的关系是: PyOpenGL是Python的OpenGL绑定库&#xff08;接口壳子&#xff09;,它提供了在Python中…

代码部署到服务器

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

uniapp 企业微信侧边栏开发网页授权 注入企业权限 注入应用权限 获取userid(2)

1、网页授权&#xff0c;获取code 代码&#xff1a; oauthUrl() {const that thisuni.removeStorageSync(code)let REDIRECT_URI encodeURIComponent(window.location.href)let CORPID webConfig.appIdlet url https://open.weixin.qq.com/connect/oauth2/authorize?appi…

Flink-----Yarn应用模式作业提交流程

Yarn应用模式作业提交流程 在Yarn当中又分为Session&#xff0c;PerJob&#xff0c;Application&#xff0c;建议和推荐使用独立集群的&#xff0c;其中就包含PerJob 和Application&#xff0c;但是1.17版本的Flink已将PerJob标记为过时&#xff0c;并且Application可以解决Pe…

AI绘画之三_StableDiffusion_界面操作

1 介绍 首先&#xff0c;介绍界面中的重要元素&#xff0c;如图所示&#xff1a; 基础模型&#xff1a;基础模型是最重要的设置项文生图&#xff1a;选项卡列出了各大功能&#xff0c;文生图指通过文字生成图片图生图&#xff1a;图生图指通过图片和文字生成图片修复照片&am…

sql类型-用户定义表类型

一、创建用户定义表类型String_Table_Type CREATE TYPE String_Table_Type AS TABLE ( Id nvarchar(200) NOT NULL ) GO DECLARE test String_Table_Type INSERT INTO test VALUES(a),(b),(c) SELECT * FROM test 二、SqlSugar中使用

【IMX6ULL驱动开发学习】06.DHT11温湿度传感器驱动程序编写与测试

一、DHT11简介 DHT11是一款可测量温度和湿度的传感器。比如市面上一些空气加湿器&#xff0c;会测量空气中湿度&#xff0c;再根据测量结果决定是否继续加湿。 DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器&#xff0c;具有超小体积、极低功耗的特点…

银行客户关系管理系统springboot财务金融进销存java jsp源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 银行客户关系管理系统springboot 系统有1权限&#x…

Jetpack系列-ViewModel的使用及原理浅析

作者&#xff1a;碎星 简介 ViewModel在架构中用于承载业务逻辑和作为容器保存屏幕状态&#xff0c;它可以缓存界面的状态&#xff0c;并且能在配置变更后持久保留相应的界面状态。 在jetpack套件中&#xff0c;ViewModel随lifecycle一起提供。 优势 简介 ViewModel在架构…

第5步---MySQL的DQL查询语句

第5步---MySQL的DQL查询语句 DQL 数据库查询语言 1.基本的查询语句 1.完整得查询得语句 简化版的查询语句 select * from 表名 where 条件; 2.创建用于测试的表 1.创建测试数据 -- DQL -- 创建测试表 DROP TABLE IF EXISTS product; CREATE TABLE IF NOT EXISTS product( pi…

一文详解4种聚类算法及可视化(Python)

在这篇文章中&#xff0c;基于20家公司的股票价格时间序列数据。根据股票价格之间的相关性&#xff0c;看一下对这些公司进行聚类的四种不同方式。 苹果&#xff08;AAPL&#xff09;&#xff0c;亚马逊&#xff08;AMZN&#xff09;&#xff0c;Facebook&#xff08;META&…

计算机毕设项目之基于django+mysql的疫情实时监控大屏系统(前后全分离)

系统阐述的是一款新冠肺炎疫情实时监控系统的设计与实现&#xff0c;对于Python、B/S结构、MySql进行了较为深入的学习与应用。主要针对系统的设计&#xff0c;描述&#xff0c;实现和分析与测试方面来表明开发的过程。开发中使用了 django框架和MySql数据库技术搭建系统的整体…

多线程实现与管理

进程与线程 进程 &#xff1a; 进程是操作系统进行资源分配的最小单位&#xff0c;每执行一个程序、一条命令操作系统都会启动一个进程&#xff0c;进程是一个程序的执行过程&#xff0c;当程序启动时&#xff0c;操作系统会把进程的代码加载到内存中&#xff0c;并为新进程分配…

uni-app根据经纬度逆解析详细地址

uni-app中的getLocation()方法可以获取到用户当前的地理位置&#xff08;经纬度&#xff09;、速度。 但是返回参数中的address在app中才会显示&#xff0c;小程序中不会显示&#xff0c;所以我们需要进行逆解析其地址&#xff0c;解析出它的地址信息。 1.首先要在腾讯位置服务…

如何正确地设置Outlook SMTP发送电子邮件(wordpress配置)

如何正确地设置Outlook SMTP发送电子邮件&#xff08;wordpress配置&#xff09; 作者&#xff1a;虚坏叔叔 博客&#xff1a;https://pay.xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; 正在寻找正确的Outlook SMTP设置&#xff1f…

LRU 算法

LRU 缓存淘汰算法就是一种常用策略。LRU 的全称是 Least Recently Used&#xff0c;也就是说我们认为最近使用过的数据应该是是「有用的」&#xff0c;很久都没用过的数据应该是无用的&#xff0c;内存满了就优先删那些很久没用过的数据。 力扣&#xff08;LeetCode&#xff09…

自动方向识别式 TXB型电平转换芯片

大家好,这里是大话硬件。 在上一篇文章分析了LSF型的电平转换芯片,LSF型电平转换芯片最常见是应用在I2C总线上。I2C为OD型总线,LSF使用时增加电阻。 对于不是OD型总线的电平转换,比如UART,SPI,普通GPIO口信号,这些信号在进行双向电平转换使用什么样的芯片呢? 从上面…

面试之快速学习STL-deuqe和list

1. deque deque 容器用数组&#xff08;数组名假设为 map&#xff09;存储着各个连续空间的首地址。也就是说&#xff0c;map 数组中存储的都是指针如果 map 数组满了怎么办&#xff1f;很简单&#xff0c;再申请一块更大的连续空间供 map 数组使用&#xff0c;将原有数据&…

每天一道leetcode:433. 最小基因变化(图论中等广度优先遍历)

今日份题目&#xff1a; 基因序列可以表示为一条由 8 个字符组成的字符串&#xff0c;其中每个字符都是 A、C、G 和 T 之一。 假设我们需要调查从基因序列 start 变为 end 所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。 例如&#xff0c;&quo…

博弈论 | 斐波那契博弈

斐波那契博弈 博弈论是二人或多人在平等的对局中各自利用对方的策略变换自己的对抗策略,达到取胜目标的理论。博弈论是研究互动决策的理论。博弈可以分析自己与对手的利弊关系,从而确立自己在博弈中的优势,因此有不少博弈理论,可以帮助对弈者分析局势,从而采取相应策略,最终达…