吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3432|回复: 17
收起左侧

[Python 转载] pandas+selenium的实践应用

  [复制链接]
陈茹 发表于 2022-3-22 21:52

1.  前言

这个项目源自坛友的求助:“自动生成核酸检测采集码”;
其需求为读取Excel里面的个人信息,输入到核酸检测预约系统里去提交,再保存生成的核酸检测采集码。

网站链接:202.102.252.250:8010/index.html

我也不是专业的,程序设计难免存在遗漏之处,有问题欢迎大家批评指正、回复讨论,希望这篇文章能给Python初学者,特别是selenium初学者提供一点帮助。

成品动图展示:

完整演示.gif

2. 设计思路

利用 pandas 库解析Excel内容;
利用 selenium 库提交数据及保存二维码。

所有用到的头文件

import pandas as pd #用于Excel的读取和解析
from selenium import webdriver #浏览器自动化
from time import sleep #延时
import sys,win32api,win32con #用于系统弹窗

3. pandas

表格样式:

表格样式.jpg

a. 使用read_excel读取文件
data = pd.read_excel(excel_file) #excel_file为文件路径

b. 通过len获取Excel的行数,为后期程序循环的结束提供判断条件
Excel_len = len(data)

c. 使用data.iloc[a,b]读取表格的指定行列(a为行数,b为列数),这儿读取的数据不包含标题行,以下面表格为例,读取“张三”使用的是print(data.iloc[0,0]),为确保读取的数据类型准确,我在这里还使用强制类型转换将其转换成字符串,print(str(data.iloc[0,0]))

姓名 电话 身份证号
张三 10086 1001001000

在后期测试中遇到的读取手机号出现了末尾加.0的情况,但Excel中看似一切正常,我使用了[0:11]处理数据,例如:

tel = "13813813815.0"
print(tel) #此时输出为13813813815.0
tel = tel[0:11]
'''截取字符串的第1至第11位,这个是“前闭后开”的原则,
和数组类似,字符串的第一个元素的下标为0,tel[0:11]可以
用数学中的区间[0,11)表示,包含了第0至第10这十一个元素
嗯,大概就是这样'''
print(tel) #此时输出为13813813815

通过以上的数据处理,就能一定程度上保证获取的数据就是我们想要的数据,以避免出现错误的情况。

4. selenium

我使用的是火狐浏览器,火狐与chrome相比的优势在于驱动不需要随着浏览器的升级而升级,最开始玩selenium的时候因浏览器版本问题走过很多弯路,真是一言难尽啊。

browser = webdriver.Firefox()定义并启动浏览器,驱动文件放在python安装路径下或当前编程文件夹就能直接找到,否则需要在括号中指定驱动路径。运行完这条命令后浏览器将自动打开。

browser.set_window_size(312,1015)设置浏览器窗口大小。那个网站为手机版网站,不能自适应电脑的分辨率,因为后期需要截图保存二维码,故需要指定窗口大小,这样看起来才和手机相似。

以上我放在程序的前面,因为启动浏览器是比较费时间了,为了提高工作效率,在程序运行前启动一次就好,后续就直接打开链接操作即可,因为是批量填写、提交和截图,那我定义一个函数,通过for或者while反复调用即可。

使用def 函数名(形参):定义函数,以下是我定义的函数:

def Tijiao(Name,Tel,Id,Xian,Zhen,Cun,Zu,Addr):

我将所有需要的信息都定义了进来,虽然多但缺一不可,后续只需要调用这个函数就能完成一次的填写、提交和截图。

使用browser.get(Url)打开网页,初次接触python的同学可能会在子函数中打开网页这一步遇到问题——NameError: name 'browser' is not defined,因为前面的 browser定义是在程序中,虽然作用域是全局,但在子函数中直接去调用还是找不到的。需要在调用前,需要使用global browser申明"browser"这个变量是全局变量,这样才能够直接使用。

打开了网站接下来就是selenium元素定位的重头戏了,这儿我不挨个详细讲了,大家可以看看这个博客的介绍 https://www.cnblogs.com/eastonliu/p/9088301.html  。
我习惯使用xpath定位,在我的编程经验中只有xpath定位能够兼容各种网站、各类元素,browser.find_element_by_xpath()括号中填写从浏览器中复制的xpath地址,前后需要加引号,因为参数类型是字符串,以需要填写的第一项姓名为例:

inputN = browser.find_element_by_xpath("/html/body/uni-app/uni-page/uni-page-wrapper/uni-page-body/uni-view/uni-view/uni-form/span/uni-view[1]/uni-input/div/input")#这个xpath地址是直接从网页中复制的
inputN.clear()#清除网页输入框中原有的值
inputN.send_keys(Name)#将名字填写进去

Xpath复制展示:

xpath演示.gif

姓名、身份证号、手机号、现居住地 这四项都能通过这个方法直接定位找到填写,问题难点在于地区选择,系统中的选项有上千种组合方式,再使用上面这中xpath定位肯定不行,通过审查元素不难发现,选项都是一个一个的文字,那是不是可以直接搜索文字,已达到找到元素的目的,在xpath定位中有个contains方法,它与text组合就能实现模糊定位文字,以选择县为例,完整参数如下:

Click = browser.find_element_by_xpath("//*[contains(text(),'" + Xian + "')]") #"Xian"是形参,通过这样的组合才能将变量带入进去
Click.click() #点击元素

同理后面的镇、村、小组选择这样写,现在就剩须知和保存提交两个按钮需要点击,通过前面的xpath定位再.click()就能完成,以须知为例:

Iknow = browser.find_element_by_xpath("//uni-view[6]/uni-radio-group/uni-label/uni-radio/div/div")
Iknow.click()

提交完成后使用get_screenshot_as_file保存截图,完整如下:

browser.get_screenshot_as_file('./img/'+Name+"_"+Id+".png")#括号中为路径和文件名

看似妥了,一切完美,简直不要太好......

然而这个网站会保存cookie和缓存,批量提交时问题就暴露了出来:

a.第二次打开或强制刷新网页仍位于上一次提交后的二维码页面上;
b. 地区选择仍保留了上一次的选择结果,比如这次选择的县和上次相同,那么contains(text()将搜索到两个及以上的元素,导致不能提交。
如图:
3个元素.jpg

一开始我从清除cookie和缓存出发,不过测试+查了许久的资料都不能解决。那要么就直接关闭浏览器,第二次提交再打开,但是启动浏览器非常缓慢,如果每次提交都关闭再打开显然效率就降低了,于是我从网站本身出发,提交后的网页有“返回”这个按钮,那我使用contains(text()找到这个按钮再点击就好了,这样就解决了问题a。

对于问题b,在xpath定位中有一个针对多个元素定位的方法,即find_elements_by_xpath,就是在"element"后面加一个"s",这样就能将所有的元素都查找出来,通过分析网页的结构,尽管有多个元素,但我需要的都是排在最后那个元素,所以以县为例,完整如下:

Click = browser.find_elements_by_xpath("//*[contains(text(),'" + Xian + "')]")
Click[len(Click)-1].click() #len方法是获取长度(数组、列表、元组等),长度-1即为最后一个元素的下标

这样我大致完成了第一版程序,我万万没想到他们那儿村民小组居然可以多达二十多组,那时候我们村也才几组,contains方法是模糊定位,也就是只要包含就能找到,那假如想要选择的是“二组”,就能将“十二组”、“二十二组”等都匹配上,而我前面处理又多个元素又是直接取的最后一个元素,bug就这样产生了......

再一次打开网站进行分析,无意中发现选择按钮的文字都位于div标签以内,而这也是与其他非按钮元素的区别,也就是说,只要通过定位div标签内的文字不就能排除掉因cookie和缓存导致的干扰吗,因为“二组”和“十二组”的相似性,模糊查找也不能选用了,以选择小组为例,完整如下:

Click = browser.find_elements_by_xpath("//div[text()='"+Zu+"']")
Click[len(Click)-1].click()

对比.jpg

至此,selenium的核心程序设计完成了。

5. 逻辑设计

程序执行过程中由于环境、路径、配置文件、网络等原因,不可避免的会出现异常,如果不做处理就会导致程序终止,并且还不知道原因,python中使用try—except处理异常,详细了解可参考这篇文章https://www.runoob.com/python/python-exceptions.html ,我将所有程序都嵌套在try:下,用except Exception:处理抛出的异常,使用print(sys.exc_info()[1]))将原始的异常提示打印出来,这样就能知道原因,以便能对症下药,整体结构如下:

try:
    '''放入需要执行和捕获的程序'''
except Exception:
    print('错误代码:'+str(sys.exc_info()[1]))
    win32api.MessageBox(0, str(sys.exc_info()[1], '出错!',win32con.MB_OK)#弹出一个警示框

警示框详解可以参考这篇文章 https://www.cnblogs.com/microtiger/p/14812480.html


利用pands读取到文件后,我使用了while循环来执行批量提交,定义了一个变量a,用于while循环的计数,通过a的计数与3.b中的Excel_len对比,就能知道何时终止循环结束程序。

计数变量a正好等同于表格的行数,那么str(data.iloc[a,列数])就能循环读取,并将其赋值到实参上,完整如下:

Name = str(data.iloc[a,0])
Tel = str(data.iloc[a,1])
Tel = Tel[0:11]
Id = str(data.iloc[a,2])
Xian = str(data.iloc[a,3])
Zhen = str(data.iloc[a,4])
Cun = str(data.iloc[a,5])
Zu = str(data.iloc[a,6])
Addr = str(data.iloc[a,7])

然后将上述实参传递至selenium核心子函数进行调用,就能实现一次的提交。

在selenium自动化处理时,我的设计逻辑为:1.打开链接;2.判断是否位于提交后的界面→若是则点击返回;3.判断是否位于首页→若是则往下填写;针对于以上否的情况,则采用刷新、重新打开链接或延时一定时间再判断进行的处理。


中间为填写、选择和提交。在地区选择的部分,我也使用了一个异常处理,如果Excel中的地区没有严格按照网页中的选项填写,选择时就会导致程序异常,后面的就无法执行了,通过异常处理就能跳过这一个的填写,以便不影响大局。


根据该系统的特性,在点击提交保存按钮后立马截了一张图,如果是身份证号码有误、电话有误、已经提交保存过等原因导致无法正常提交,在点击提交保存按钮后能立马显示出来,这时候截一张图在后续查看的时候就能明确知道原因以便修改。

从提交成功再到二维码加载出来需要一定的时间,可以使用sleep()方法进行延时等待,其单位为秒,sleep(1)延时一秒。

延时一定时间后,通过模糊查找网页中是否包含“返回”二字,来判断是的提交成功,若成功,则再次截一张图保存(以相同名字保存截图会覆盖上一张图片)。

if (len(browser.find_elements_by_xpath("//*[contains(text(),'返回')]")) == 1 ):#判断是否添加成功

6.结语

深思熟虑之后还是不将完整源码附上了,因为该系统是当地正式运行的核酸预约系统,大家批量的去提交、测试必定会一定程度上影响系统的正常运行,核心部分已经贴出,剩下的无非就是逻辑的完善和细节的处理,相信以上方案能给初学者提供一定解决问题的思路,学习过程中遇到问题可以私信我。

c语言是我大学学习的第一个语言,然后是Java,第一次接触Python也是在大学课堂,还只有半学期课程,由于众所周知的原因课程结束我都没能明白Python是什么,课程结束后的一次偶然因素再次与Python相识,经过反复的测试+查资料完成了人生的一个Python实践程序,有了第一次的成功之后,我对Python也有了浓厚兴趣,兴趣是最好的老师,由此我展开了一系列的Python学习之旅,毕业后误打误撞来到工控领域工作,Python虽然用不上,但自学Python过程中积累的各类经验还是蛮有意义的。

免费评分

参与人数 8吾爱币 +8 热心值 +7 收起 理由
AzZ丶咖灰 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
kongdang1 + 1 用心讨论,共获提升!
panison + 1 + 1 用心讨论,共获提升!
l3693685 + 1 + 1 谢谢@Thanks!
科大的思念 + 1 + 1 谢谢@Thanks!
fairesense + 1 + 1 谢谢@Thanks!
lizy169 + 1 + 1 谢谢@Thanks!
zhanglei1371 + 2 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

萌新与小白 发表于 2022-3-26 15:28
本帖最后由 萌新与小白 于 2022-3-26 15:34 编辑

1.火狐的驱动只需下载一次,以后再也不用管它?甚至火狐浏览器更新好几个版本也不用管?是的话,请问是在哪得知这一点的?我用的chrome的驱动,没用过火狐的。
2.find_element()和find_elements()取代了旧的find_element_by_xx()和find_elements_by_xx(),例如find_element(By.ID, 's-usersetting-top'),需from selenium.webdriver.common.by import By
3.我这都是让自己填信息,自己保存二维码,我识别了我自己的二维码,得到的字符串在格式上像token,猜测可以找出生成规律,直接生成,这样就拿到二维码了,至于提交数据可以直接用接口提交;当然也可以分析接口返回值,看能不能根据返回值手动生成二维码
4.我看你图中的报错信息是红色的,请问怎么生成的?还有打印报错的语句我用的和你不一样,例如随便写个异常,我用的是
except json.decoder.JSONDecodeError as e:
    raise Exception('发生了异常,具体异常为:'+'json.decoder.JSONDecodeError: '+str(e))
   
 楼主| 陈茹 发表于 2022-3-26 17:11
萌新与小白 发表于 2022-3-26 15:28
1.火狐的驱动只需下载一次,以后再也不用管它?甚至火狐浏览器更新好几个版本也不用管?是的话,请问是在哪 ...

火狐驱动这个我也是遭受Google浏览器更新之苦之后多次测试发现的,从用火狐浏览器驱动以来即使浏览器更新多次,驱动我都没有重新下载过,从驱动下载页面也能发现火狐的驱动版本相较于Google少很多,当然具体情况具体分析哈,只是我的经验告诉我火狐不需要反复去下载驱动。
关于异常处理,有多种方式,我用的最简单最直接的方式,只为了能将最原始的、全部的提示信息输出,以便根据提示我自己能分析出原因,至于红色字体,是通过转义序列控制的,这儿有几篇文章有详细介绍,你可以看看:
https://www.cnblogs.com/easypython/p/9084426.html
https://www.cnblogs.com/huchong/p/7516712.html
https://zhuanlan.zhihu.com/p/136173259
头像被屏蔽
tl;dr 发表于 2022-3-23 06:26
chinguy 发表于 2022-3-23 07:56
逻辑很好,值得仔细学习,尤其找提交位置的方法,值得学习。
lizs0827 发表于 2022-3-23 08:34
赞一个,非常不错
ccwuax 发表于 2022-3-23 08:35
你这样太麻烦了,速度又慢,简单看了一下,就是把提交的信息用url编码,再用BASE64编码,再生成二维码就可以了,速度又快,格式:
{"username":"姓旬","usercard":"身份证号","usertel":"电话号码","useraddr":"博爱县,许良镇,许良村,十二组,1号楼1单元3室"}
最后一个就是地址
helloworld2022 发表于 2022-3-23 08:49
非常不错,学习一下。
godmandxw 发表于 2022-3-23 09:23
非常不错,学习了
 楼主| 陈茹 发表于 2022-3-23 12:23
ccwuax 发表于 2022-3-23 08:35
你这样太麻烦了,速度又慢,简单看了一下,就是把提交的信息用url编码,再用BASE64编码,再生成二维码就可以了, ...

谢谢指正!确实,二维码可以通过这种方法生成,提交和查询也可以利用requests库通过post和get请求来实现,效率也高,这个系统的post和get方法都比较简单,但在selenium的元素定位方面具有一定的代表性,所以写了这篇文章,希望能给初学selenium的同学提供一点帮助。
科大的思念 发表于 2022-3-25 21:19
陈茹 发表于 2022-3-23 12:23
谢谢指正!确实,二维码可以通过这种方法生成,提交和查询也可以利用requests库通过post和get请求来实现 ...

http://36.99.39.228:9830/zhouk-qrcode/#/personal 大佬,帮帮看看我们这个能用吗?
 楼主| 陈茹 发表于 2022-3-25 23:57
科大的思念 发表于 2022-3-25 21:19
http://36.99.39.228:9830/zhouk-qrcode/#/personal 大佬,帮帮看看我们这个能用吗?

明天我看看,弄好了私信给你
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 07:42

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表