重新写了一个东南大学体育场馆的定时预约脚本,使用selenium和chromedriver实现,tesseract识别验证码

上次写的半成品用的是urllib库直接提交post表单,但是现在不可用了,主要是post请求的字段里,新添了几个不知道的值,而且密码采用的加密是ase128,我是懒的去实现。
正好试一下selenium,selenium是一个很好的用于自动化测试的模块,可以直接调动浏览器,模拟人的输入点击等操作,而且非常简单易用,但是效率相对而言就低一些,因为很多操作要等页面元素加载出来才可以找到。

这次不仅写了脚本,还搭建了一个网站,接受预定,并且写入数据库,每天早上08:01执行预约脚本,有兴趣的或者需要的同学可以看这里,http://116.62.5.101:8000,
后面会再写一篇文章,介绍如何在服务器上部署基于flask网站,数据库,selenium、tesseract4.0、无界面的chrome浏览器和chromdriver。



selenium最核心的使用方法就是使用选择器找到页面的相应的元素作为对象,例如:
bro是一个selenium中webdriver的一个浏览器对象,可以使用find_element_by的方法,通过name,id,class找到元素,
如果这些都没有的元素,可以使用xpath,xpath有兴趣的小伙伴可以去详细了解一下,不过最简单的方法就是F12打开开发者模式之后,右键响应的元素就可以copy它的Xpath。

tesseract 是一个识别引擎,用于识别验证码





import pymongo
import schedule
import time
import pytesseract
from PIL import Image
from multiprocessing import Pool
from bson import ObjectId
from selenium import webdriver
import datetime
import random
import os


def addmates(matesid,framenum,bro):

button_addmates = bro.find_element_by_id("handle-add")
button_addmates.click()
bro.switch_to.frame("xubox_iframe"+str(framenum))
input_matesid = bro.find_element_by_id("cardNo")
input_matesid.send_keys(matesid)
button_findmate = bro.find_element_by_class_name("search-id")
button_findmate.click()
input_existmates = bro.find_elements_by_class_name("user")
oldcontacts = []
for input_existmate in input_existmates:
# print(input_existmate.get_attribute("textContent"))
oldcontacts.append(input_existmate.get_attribute("textContent").strip())

time.sleep(1)
# print(bro.page_source)
input_newcontact = bro.find_element_by_id("contact")
# print(input_newcontact.get_attribute("textContent"))
newcontact = input_newcontact.get_attribute("textContent")

if newcontact not in oldcontacts:
button_addtocontacts = bro.find_element_by_class_name("add-user")
button_addtocontacts.click()
time.sleep(1)
else:
for input_existmate in input_existmates:
if input_existmate.get_attribute("textContent").strip() == newcontact:
checkbox = input_existmate.find_element_by_name("user")
checkbox.click()
time.sleep(1)
button_submitaddmates = bro.find_element_by_class_name("del-all-users")
button_submitaddmates.click()
break


# ssl._create_default_https_context = ssl._create_unverified_context
def main(reserverdic,orderid):

#隐藏浏览器界面
option = webdriver.ChromeOptions()
option.add_argument('headless')
option.add_argument('--no-sandbox')
bro = webdriver.Chrome(options=option)
# bro = webdriver.Chrome()
print("Chrome 已启动")
url = 'https://newids.seu.edu.cn/authserver/login?goto=http://my.seu.edu.cn/index.portal'


bro.get(url)
# print(bro.page_source)
#bro.save_screenshot("ddd.png")
#print("saved")
# 登录预约系统
id=reserverdic["idpwd"]["ssid"]
pwd=reserverdic["idpwd"]["pwd"]
time.sleep(3)
input_username = bro.find_element_by_id("username")
input_password = bro.find_element_by_id("password")
input_username.send_keys(id)
input_password.send_keys(pwd)
# print(input_username)
# print(input_password)

# 多个class 要用下面的形式 不能直接find_element_by_class
botton_login = bro.find_element_by_css_selector("[class='auth_login_btn primary full_width']")
botton_login.click()

# url3="http://yuyue.seu.edu.cn/eduplus/order/initOrderIndex.do?sclId=1"
# bro.get(url3)
#打开预约界面
info = reserverdic["info"]
# info = {
# 'dayInfo': "2018-11-23",
# 'itemId': 7,
# 'time': "12:00-13:00"
# }
# infourl = urllib.parse.urlencode(info)
"""
'itemId':7, 九龙湖乒乓,1-3人
'itemId':8, 九龙湖篮球,全场9-14,半场5-8人
'itemId':9, 九龙湖排球,4-15人
'itemId':10, 九龙湖羽毛球,1-5人
'itemId':11, 九龙湖舞蹈,非必选
'itemId':12, 九龙湖健身,非必选
'itemId':13, 九龙湖武术,非必选
'itemId':14, 九龙湖跆拳道,非必选
'itemId':15, 四牌楼羽毛球,1-3人
'itemId':16, 四牌楼乒乓,1-3人
'itemId':17, 四牌楼网球,1-3人
"""

url2 = "http://yuyue.seu.edu.cn/eduplus/order/initEditOrder.do?sclId=1&dayInfo="+info['dayInfo']+"&itemId="+info['itemId']+"&time="+info["time"]
# print(url2)
# bro.execute_script("window.open()")
# bro.switch_to.window(bro.window_handles[1])
bro.get(url2)

#处理篮球半场全场
basketball=reserverdic["phonemate"]["halffull"]
if basketball == 2:
buttonhalffull = bro.find_elements_by_name("orderVO.useMode")
buttonhalffull[1].click()
#添加电话
phonenumber = reserverdic["phonemate"]["phone"]
input_phone = bro.find_element_by_id("phone")
input_phone.clear()
input_phone.send_keys(phonenumber)

#添加好友
framenum=0
for eachmate in reserverdic["phonemate"]["mateid"]:
framenum+=1
addmates(eachmate,framenum,bro)
time.sleep(1)



#处理验证码
screenshot = str(random.randint(1,100000))+'screenshot.png'
validcodeshot = str(random.randint(1,100000))+'validateimage.png'
bro.get_screenshot_as_file(screenshot)
img = bro.find_element_by_xpath('//*[@id="fm"]/table/tbody/tr[6]/td[2]/img')
left = int(img.location['x'])
top = int(img.location['y'])
right = int(img.location['x'] + img.size['width'])
bottom = int(img.location['y'] + img.size['height'])

# 通过Image处理图像
im = Image.open(screenshot)
im = im.crop((left, top, right, bottom))
im.save(validcodeshot)

img = Image.open(validcodeshot)
validcode = pytesseract.image_to_string(img)
# print(validcode)

input_validcode = bro.find_element_by_id("validateCode")
input_validcode.send_keys(validcode)
button_reserve = bro.find_element_by_id("do-submit")
button_reserve.click()

os.remove(screenshot)
os.remove(validcodeshot)
time.sleep(1)



try:
alertcontent=bro.find_element_by_css_selector("[class='xubox_msg xubox_text']")
if alertcontent.get_attribute("textContent"):
updatestatus(orderid, alertcontent.get_attribute("textContent")+",预约失败")
print(alertcontent.get_attribute("textContent"), "预约失败")
bro.quit()
return 0
except Exception:
bro.quit()
updatestatus(orderid,"预约成功")
print("预约成功")
return 1


def mmain():
# 测试用例
# reserverdic1 = {
# "idpwd": {
# 'ssid': 220187988,
# 'pwd': "mima"
# },
# "info": {
# 'dayInfo': "2019-09-02",
# 'itemId': "7",
# 'time': '12:00-13:00'
# },
# "phonemate": {
# "phone": 1885187965558,
# "mateid": [220184346], # list 所有好友id
# "halffull": 1 # 1表示全场,2表示半场,非蓝球默认位1,或者空
# }
# }
# reserverdic2 = {
# "idpwd": {
# 'ssid': 220175358,
# 'pwd': "mima"
# },
# "info": {
# 'dayInfo': "2019-09-08",
# 'itemId': "7",
# 'time': '17:00-18:00'
# },
# "phonemate": {
# "phone": 18851879658,
# "mateid": [220184348], # list 所有好友id
# "halffull": 1 # 1表示全场,2表示半场,非蓝球默认位1,或者空
# }
# }
# groups=[reserverdic1,reserverdic2]


orderlist = getorderlist()
if not orderlist:
print(str(datetime.date.today()),"没有订单")

pool = Pool()
pool.map(doorder,orderlist)

# pool.map(main, groups)


def doorder(order):
try:
print("process order", order)
main(order[0], order[1])
except Exception:
newstutas = "预约失败,检查提交信息是否出错"
updatestatus(order[1], newstutas)
print(newstutas)


def getorderlist():


today=datetime.date.today()
myclient = pymongo.MongoClient("mongodb://localhost:27017/")
mydb = myclient["order"]
mycol = mydb["order"]
findresult = mycol.find({'date': str(today)}, {"reservedic": 1,"_id":1})
orderlist=[]
for x in findresult:
orderlist.append([x["reservedic"],x["_id"]])

return orderlist


def updatestatus(orderid, newinfo):
myclient = pymongo.MongoClient("mongodb://localhost:27017/")
mydb = myclient["order"]
mycol = mydb["order"]
mycol.update_one({ "_id" : ObjectId(orderid)},{ "$set": { "status": newinfo } })


if __name__ == '__main__':
# mmain()

mmain()


# schedule.every().day.at('08:00').do(mmain)
# while True:
# schedule.run_pending()

猜你喜欢

转载自www.cnblogs.com/CooperXia-847550730/p/11479752.html