一开始我本来打算是利用Python的requests库来做的,进行模拟点击收集返回的信息;但是,由于经过多次尝试,我发现我还是无法对弹窗进行post访问,对相关的一些ajax的方面还是不太熟悉。在登录方面的post表单是没有问题的,由于post提交表单的网址的不变的,多个弹窗使用到提交表单的网址也是这个。但在对网页进行post提交表单时,发现返回的结果是没有变化的,没有返回到我想要的结果,由于提交的表单的参数过多,我对部分参数进行反复检查,还是没有发现问题。所以迫于无奈使用到selenium的库。
1.selenium的应用;
在我所知,selenium库的应用是最多在于测试。而我看到selenium提供的网页自动化测试,想到可以通过这个实现我的需求。对于小白的我看来这是一个类似加强版的按键精灵。
本地环境:
win7+python3.7+webdriver.exe+Chrome(版本 75.0.3770.100(正式版本) (32 位))+selenium
下载chromedriver地址
前提安装了webdriver.exe的Chrome的驱动应用,web驱动应放在程序运行目录下,或则指定webdriver的地址;
首先需求分析:
1.想要通过自动化点击来处理日常任务的转移。
2.想要记录表,记录下任务转移的方向等,转给了谁。
3.想要有请假勿转的功能。
4.想要有记录转移发生异常的处理能力。
。。。。后续的需求还有待增加
需求实现:
首先,第一点需求,可以通过selenium的webdriver来是实现网页的自动化点击。通过定位元素的位置后或者执行js脚本。js脚本可以通过F12的console后台来执行检验,最简单的是通过检查网页元素对网页元素进行复制js path。
第二点我的想法是通过xlwings进行实现,由于需要有持续的读写能力。还有判断究竟转给了谁,需要转给谁,我会创建一个嵌套的dict存储的以当天的日期作为维度存储转的次数,{group team:{username:(次数)},利用with open(r'') as f:打开文件进行读写。
第三点,由于需要存储的人员信息关系表不大,我是利用Access数据进行存储的基本的人员信息关系表,在表中加一个字段进行是否请假。(每次读取Access数据库的时候,都先检验一次该字段,把true的挑选出来。)
第四点暂时没有自动处理的方案,只好遇到错误后,手动重新启动运行。
缺点:
因为我发现大部分出现的错误的情况都是因为网页加载慢,导致元素无法被找到,进而报错。
这种情况的处理可以在程序加入等待时间或等待需要的元素加载出来,从而实现。
还有由于可能服务器宕机的风险,网页无法登陆加载的情况没有处理。
相关的conding,主要是浏览器的启动、数据库的链接、初始数据的读取及准备。
from selenium import webdriver
from time import sleep
#登录
driver=webdriver.Chrome()
driver.get('http://xxxxxxxxxx')
sleep(2)
driver.execute_script("document.querySelector('#ContentPlaceHolder1_txtUserName').value='happykkk'")
driver.execute_script("document.querySelector('#ContentPlaceHolder1_txtPassword').value='123456'")
driver.execute_script("document.querySelector('#ContentPlaceHolder1_btnOK').click()")
import pyodbc
DBfile = r"\\login_information.mdb" # 数据库文件
conn = pyodbc.connect(r"Driver={Driver do Microsoft Access (*.mdb)};DBQ=" + DBfile + ";Pwd=p123456")
cursor = conn.cursor()
SQL = "SELECT * from user_relation_autotransfer;"
cur=cursor.execute(SQL)
data=cur.fetchall()
#初始化dict
dic={'Team1':{},'Team2':{},'Team3':{},'Team4':{},'Team5':{},'team6':{},'Team7':{}}
for i in data:
if i[3]==True:
dic[i[1]][i[0]]=0
import json
from datetime import datetime
t=str(datetime.now())[:10]
with open(r'./transfer record{}.txt'.format(t),'r') as f1:
rest=json.load(f1)
#读取excel文件内容
import xlwings as xw #利用xlwings对数据进行读取
try:
filepath=r'C:\11.xlsx'
app = xw.App(visible=False, add_book=False)
wb=app.books.open(filepath)
sht=wb.sheets[0]
taskdata=sht.range('A1').expand('table').value
print(taskdata)
wb.close()
app.quit()
app.kill()
except:
wb.close()
app.quit()
app.kill()
还有部分操控根据网页元素操控模拟点击。
#利用先判断是否,data是指人员关系表。team是指要转的team,maker是指确认岗位的人,默认为None
def chooseperson(data,team,maker=None):
m=list(rest[team].keys())
v=list(rest[team].values())
if maker in m: #先判断maker是否在该team中,转给谁的判断是:该组内谁的任务量最少的
nn=m.index(maker)
m.pop(nn)
v.pop(nn)
num=v.index(min(v))#确定最少的任务量
result=m[num]#要转的人
rest[team][result]+=1 #转完后统计
return result#返回结果
elif maker ==None:
num=v.index(min(v))
result=m[num]
rest[team][result]+=1
return result
else:#出现任务转错team类型,maker与team不匹配
for i in data:
if i[0]==maker:#重新确认要转的team
chooseperson(data,i[1],maker) #递归调用
def searchtask(driver,tasknum):
#点击搜索任务
#利用xpath
# driver.find_element_by_xpath('//*[@id="ContentPlaceHolder1_lbtnSearch"]').click()
driver.execute_script("document.querySelector('#ContentPlaceHolder1_lbtnSearch').click()")
sleep(1.5)
#由于上面打开速度过快点错所以要sleep
driver.execute_script("document.querySelector('#ContentPlaceHolder1_TextBox1').value=''")
# driver.execute_script("document.querySelector('#ContentPlaceHolder1_cmbForm17').click()")
sleep(1)
#选择payroll Team
driver.execute_script("document.getElementById('ContentPlaceHolder1_cmbForm17').options[28].selected=true")
sleep(1)
#填写任务编号
driver.execute_script("document.querySelector('#ContentPlaceHolder1_TextBox2').value='%s'"%(tasknum))
#点击搜索
driver.execute_script("document.querySelector('#ContentPlaceHolder1_Button4').click()")
global rest#全局变量
#判断
def transfertask(driver,data,team,maker):
#点击勾选
sleep(1)
driver.execute_script("document.querySelector('#ContentPlaceHolder1_GridView1_chk1_0').click()")
#点击转移任务
sleep(1)
driver.execute_script("document.querySelector('#ContentPlaceHolder1_ImageButton5').click()")
person=chooseperson(data,team,maker)
print(person)
sleep(1.5)
driver.execute_script("document.querySelector('#ContentPlaceHolder1_TextBox8').value='%s'"%(person))
sleep(2)
# driver.find_element_by_xpath('//*[@id="ContentPlaceHolder1_Button8"]').click()#点击go
driver.execute_script("document.querySelector('#ContentPlaceHolder1_Button9').click()")#点击取消
sleep(1.5)
driver.implicitly_wait(20)
global rest
import datetime
def writesheet(data1,i,person):#打算mark表
# try:
team=''
for d in data1:
if d[0].split(' ')[0].title()==i[4].split(' ')[0].title():
team=d[1]
print(team)
datares=[i[0],team,i[2],'incorrect task allocation','Y',i[5],i[6],'Y',datetime.datetime.strftime(datetime.datetime.now(),'%Y%m%d')[:6],i[4],person]
filepath=r'\\Transfer Record.xlsx'
# filepath=r''
# app = xw.App(visible=False, add_book=False)
# wb=app.books.open(filepath)
wb=xw.Book(filepath)
sht=wb.sheets[0]
# sht2=wb.sheets[1]
nrow = sht.range('A65536').end('up').row+1
print(nrow)
sht.range('A{}'.format(nrow)).value=datares
wb.save(filepath)
for i in taskdata:
tasknum=str(i[0]).split(".")[0]
searchtask(driver,tasknum)
sleep(1.5)
jud=driver.find_element_by_xpath('//*[@id="ContentPlaceHolder1_GridView1"]/tbody/tr[2]/td').text
# print(jud)
if jud!="没有数据记录":
postype=driver.find_element_by_xpath('//*[@id="ContentPlaceHolder1_GridView1"]/tbody/tr[2]/td[4]').text
if postype=='maker岗位':
maker=None
transfertask(driver,data,i[2].title(),maker)
elif postype=='check岗位':
#点击查看任务详情
driver.execute_script("document.querySelector('#ContentPlaceHolder1_GridView1_linkButton1_0').click()")
sleep(1.5)
#获取人员名字
maker=driver.find_element_by_xpath('//*[@id="ContentPlaceHolder1_GridView5"]/tbody/tr[3]/td[3]').text
sleep(1)
print(maker)
driver.execute_script("document.querySelector('#ContentPlaceHolder1_Button9').click()")#退出
sleep(1.5)
searchtask(driver,tasknum)
sleep(1.5)
transfertask(driver,data,i[2].title(),maker)
with open(r'./transfer record{}.txt'.format(t),'w') as f:#记录rest,rest是记录下当天转给每个人的次数
f.write(json.dumps(rest))
加了一些条件判断,可以让模拟点击能操作更为繁琐的操作。
但是这个代码的运行还是存在着一定的问题,比如对于网页元素卡了,网速跟不上,或则服务器异常导致运运行出现错误;这个问题有待解决。想法:可以对发生错误的tasknum重新按上诉逻辑运行一次,如果还是报错则可以让异常扑捉该taskid,返回错误信息提示。若是服务器挂了,我就没有办法了,但是网速卡了,也可以重新运行一次便可。
缺点和存在的问题:
1.由于我使用了多个sleep的情况下,是的程序运行的速度降低
优化,在把一些无关紧要的sleep去掉,但是主要基于网速的考虑而设定的。
2.由于使用了经过处理后的数据集,使得数据中的有些人员被删除,使得在chooseperson函数陷入了死循环。但是由于程序自动结束使得记录丢失。
解决方案:重新引入较为全的数据集作为参数导入
3.没有解决好失败记录的重新转移
selenium引用参考链接:
https://www.cnblogs.com/101718qiong/p/8250104.html