自动化选课(Python + selenium
前几天听到朋友说自己选课事情,突发奇想想要搞这样一个东西,但是由于各种原因只做到以下的完成度,具体的情况也会在解释的最后留下。这个只适用于曲师大的教务系统,因为用的这个系统来进行的一个调试,对于其他的系统,思路都是一样的,代码也只适用于学习,请不要用以其他用途!代码放在最后。
工具
- Python3
- selenium库(浏览器自动化操作)
- ddddocr库(OCR图片文字识别)
- time库(定时操作)
思路
对于想要做到的这个需求呢,我选择的是python + selenium库进行一个浏览器自动化操作,在写的过程中因为发现了一个验证码的问题所以又用到了一个ddddocr库,如果想要定时操作的话再加上一个time库。之后就是理清操作的顺序就好了,想到于人工操作一遍的过程。
- 进入系统登录界面
- 进入用户界面
- 进入选课界面
- 开始选课
大的一个方向、思路就是上面这四步,具体的细化之后再谈及。
过程
进入系统登录界面
这一步就很简单,直接用selenium库打开chormedriver就好了
self.driver = webdriver.Chrome()
self.driver.maximize_window() # 最大化
进入用户界面
这一步就是登录,要完成的就是把账号,密码输入对应的框,然后输入验证码,点击登录。
首先把账号密码输入到框里很简单
self.driver.find_element(By.ID, 'userAccount').send_keys(self.user_account)
self.driver.find_element(By.ID, 'userPassword').send_keys(self.user_password)
直接调用selenium库中的函数就可以进行该操作
接下来是这一步骤的一个问题,就是如何过验证码,因为该系统的验证码图片并不复杂,我想到的一个解决措施就是把验证码截图,然后识别图片上的信息,然后重复上述操作就好了。
如何截图,我首先想到的是指定位置然后用某个库截图或者是打开图片的链接保存图片,后来发现每次点开链接图片都是不一样的(应该是JS的原因),最后发现原来selenium库自带一个元素截图的函数。
ocr = ddddocr.DdddOcr()
img = self.driver.find_element(By.ID, 'SafeCodeImg') # 定位到验证码图片
img.screenshot('code.png') # 给验证码元素截图并保存
with open('code.png', 'rb') as f:
img_bytes = f.read() # 读取图片编码
return ocr.classification(img_bytes) # 返回图片中的验证码
这样的话只需要定位到这个图片元素,然后保存下来,再读取编码信息,使用ddddocr库来进行一个文字识别,返回图片的验证码模拟登陆就好了
最后登录也就是找到元素然后调用函数模拟点击就好了
self.driver.find_element(By.XPATH, "//*[@class='btn btn-primary login_btn']").click()
进入选课界面
这一部分本来难度不算很高,但是因为JS的原因,有一些地方需要注意。
首先就是模拟点击一些摁扭可以转到选课界面的地方。因为这个选课系统转到一个页面以后会产生一些新的东西(框架),这时候我们要再找上面的元素就要分清楚在哪一个框架上。
self.driver.switch_to.frame("Frame1") # !!
通过F12开发者选项可以找到这个元素所在的框架不是初始的框架(frame)而是在JS产生的一个新框架中,那么就需要用这个函数来转到新的框架Frame1(通过开发者选项找到的frame id)
只有这一点需要特别注意!!!
开始选课
首先一点,进入这个界面的时候,浏览器的界面是切换了的,因此我们也需要将selenium的定位切换到我们所看到的界面上。
new_window = self.driver.window_handles[-1]
self.driver.switch_to.window(new_window)
之后通过点击又转产生了一个新的框架,因此在进行一个转框架的操作。
最后就是通过课程id、上课老师名字、上课是星期几三个来作为键确定唯一的课程,进行一个选择,并重复上述操作直到完成全部选课。
for my_course in self.user_course:
self.driver.find_element(By.ID, 'kcxx').send_keys(my_course[1]) # 通过课程信息查找
self.driver.find_element(By.ID, 'skls').send_keys(my_course[2]) # 通过上课老师查找
self.driver.find_element(By.XPATH, f"//*[@id='skxq']/option[{my_course[3]+1}]").click()
# 选择星期(一 - 2, 二 - 3, 三 - 4, 四 - 5, 五 - 6)
self.driver.find_element(By.XPATH, "html/body/div[3]/input[6]").click()
self.driver.find_element(By.ID, 'kcxx').clear() # 清空课程查询框
self.driver.find_element(By.ID, 'skls').clear() # 清空上课老师框
time.sleep(1)
"""
没刷新出来加一个等待1秒
"""
course_remain = self.driver.find_element(By.XPATH, "//*[@class='odd']/td[9]").text # 查看课余量
if int(course_remain) > 0:
self.driver.find_element(By.XPATH, "//*[@class='odd']/td[11]/div/a").click()
"""
这里缺少了一部分确定的代码
"""
else:
print(f'{my_course[1]}选课失败')
time.sleep(3) # 3秒的暂停
附加功能
定时功能
使用time库来进行一个定时开始执行
run_time_h = 9 # 定时小时
run_time_m = 0 # 定时分钟
while True:
current_time = time.localtime(time.time())
print(str(current_time.tm_hour) + '-' + str(current_time.tm_min) + '-' + str(current_time.tm_sec))
if current_time.tm_hour == run_time_h and current_time.tm_min == run_time_m:
break
一些操作的解释
- selenium库的使用可以查一下其他博主的介绍
- 关于元素的定位,一般我习惯于使用通过ID和XPATH来定位(XPATH 就是 "//*[@xx='abc']/li[1]/")这个也可以看看如何去使用。
- ddddocr库是看图片的编码来转换成文本
此代码可能出现的问题(完成度不是很高):
因为我本身不是曲师大的校友所以说我没有进行一个完全的操作,对系统的认识也不是很充分这样写出来的代码当然也完成度也不能说是很高的,下面我就大概说一下这个代码可能产生的问题。
- 如果系统崩溃(加载不出页面……),程序应该是不能执行命令。
- 最后的选课部分只进行了一个点击,并没有确认,因此实际上这段代码是无法完成选课的!
- 可能图片识别有一定的误差,导致不能登陆成功(ddddocr库可能出的问题)
- 操作过快以至于元素没有加载出来,这一点我通过time.sleep()函数来进行了一个优化,每次选课间隙也添加一个3秒的一个等待。
import time
import ddddocr
from selenium import webdriver
from selenium.webdriver.common.by import By
class CClassSelect:
def __init__(self, i_account, i_password, i_course):
self.user_account = i_account
self.user_password = i_password
self.user_course = i_course
self.login_url = 'http://202.194.188.38/'
self.account_url = 'http://202.194.188.38/jsxsd/framework/xsMain.jsp'
self.driver = webdriver.Chrome()
self.driver.maximize_window()
def LoginAccount(self):
self.driver.get(self.login_url)
self.driver.find_element(By.ID, 'userAccount').send_keys(self.user_account)
self.driver.find_element(By.ID, 'userPassword').send_keys(self.user_password)
identify_code = self.Ocr()
self.driver.find_element(By.ID, 'RANDOMCODE').send_keys(identify_code)
self.driver.find_element(By.XPATH, "//*[@class='btn btn-primary login_btn']").click()
def LoginClassSelect(self):
time.sleep(1)
self.driver.find_element(By.XPATH, "//*[@id='onesidebar']/div/ul/li[3]/span").click()
self.driver.find_element(By.XPATH, "//*[@class='sidebar-menu']/li[7]/a").click()
time.sleep(1)
self.driver.find_element(By.XPATH, "//*[@class='treeview-menu menu-open']/li[1]/a").click()
self.driver.switch_to.frame("Frame1") # !!
"""
iframe问题,卡了一段时间这个地方,可以百度到是不在一个frame的原因
定位不到这个‘进入选课’元素,
"""
self.driver.find_element(By.ID, "jrxk").click()
self.driver.find_element(By.XPATH, "//*[@class='Nsb_pw']/div/center/input[1]").click()
def ClassSelect(self):
new_window = self.driver.window_handles[-1]
self.driver.switch_to.window(new_window)
"""
切换到新的窗口
"""
self.driver.find_element(By.XPATH, "//*[@id='topmenu']/li[4]/a").click()
self.driver.switch_to.frame("mainFrame") # 换frame
"""
选课代码 ↓
"""
for my_course in self.user_course:
self.driver.find_element(By.ID, 'kcxx').send_keys(my_course[1]) # 通过课程信息查找
self.driver.find_element(By.ID, 'skls').send_keys(my_course[2]) # 通过上课老师查找
self.driver.find_element(By.XPATH, f"//*[@id='skxq']/option[{my_course[3]+1}]").click()
# 选择星期(一 - 2, 二 - 3, 三 - 4, 四 - 5, 五 - 6)
self.driver.find_element(By.XPATH, "html/body/div[3]/input[6]").click()
self.driver.find_element(By.ID, 'kcxx').clear() # 清空课程查询框
self.driver.find_element(By.ID, 'skls').clear() # 清空上课老师框
time.sleep(1)
"""
没刷新出来加一个等待1秒
"""
course_remain = self.driver.find_element(By.XPATH, "//*[@class='odd']/td[9]").text # 查看课余量
if int(course_remain) > 0:
self.driver.find_element(By.XPATH, "//*[@class='odd']/td[11]/div/a").click()
"""
这里缺少了一部分确定的代码
"""
else:
print(f'{my_course[1]}选课失败')
time.sleep(3) # 3秒的暂停
def Ocr(self):
ocr = ddddocr.DdddOcr()
img = self.driver.find_element(By.ID, 'SafeCodeImg') # 定位到验证码图片
img.screenshot('code.png') # 给验证码元素截图并保存
with open('code.png', 'rb') as f:
img_bytes = f.read() # 读取图片编码
return ocr.classification(img_bytes) # 返回图片中的验证码
def Run(self):
self.LoginAccount()
self.LoginClassSelect()
self.ClassSelect()
self.driver.quit()
if __name__ == '__main__':
# 定时运行
run_time_h = 9 # 定时小时
run_time_m = 0 # 定时分钟
while True:
current_time = time.localtime(time.time())
print(str(current_time.tm_hour) + '-' + str(current_time.tm_min) + '-' + str(current_time.tm_sec))
if current_time.tm_hour == run_time_h and current_time.tm_min == run_time_m:
break
# 主程序
input_account = "12345" # 用户账号
input_password = "abcde" # 用户密码
input_course = [['12345', '张三', 3], ['54321', '李四', 5]] # 要选的课(ID,上课老师,星期)
app = CClassSelect(input_account, input_password, input_course)
app.Run()
自动化选课(Python + selenium的更多相关文章
- web自动化 基于python+Selenium+PHP+Ftp实现的轻量级web自动化测试框架
基于python+Selenium+PHP+Ftp实现的轻量级web自动化测试框架 by:授客 QQ:1033553122 博客:http://blog.sina.com.cn/ishou ...
- 一次完整的自动化登录测试-基于python+selenium进行cnblog的自动化登录测试
Web登录测试是很常见的测试!手动测试大家再熟悉不过了,那如何进行自动化登录测试呢!本文作者就用python+selenium结合unittest单元测试框架来进行一次简单但比较完整的cnblog自动 ...
- python selenium自动化(二)自动化注册流程
需求:使用python selenium来自动测试一个网站注册的流程. 假设这个网站的注册流程分为三步,需要提供比较多的信息: 在这个流程里面,需要用户填入信息.在下拉菜单中选择.选择单选的radio ...
- 使用python selenium进行自动化functional test
Why Automation Testing 现在似乎大家都一致认同一个项目应该有足够多的测试来保证功能的正常运作,而且这些此处的‘测试’特指自动化测试:并且大多数人会认为如果还有哪个项目依然采用人工 ...
- WEB自动化(Python+selenium)的API
在做Web自动化过程中,汇总了Python+selenium的API相关方法,给公司里的同事做了第二次培训,分享给大家 ...
- 【转】基于Selenium的web自动化框架(python)
1 什么是selenium Selenium 是一个基于浏览器的自动化工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案.Selenium主要包括三部分:Selenium IDE.Sel ...
- python selenium自动化点击页面链接测试
python selenium自动化点击页面链接测试 需求:现在有一个网站的页面,我希望用python自动化的测试点击这个页面上所有的在本窗口跳转,并且是本站内的链接,前往到链接页面之后在通过后退返回 ...
- 一次简单完整的自动化登录测试-基于python+selenium进行cnblog的自动化登录测试
Web登录测试是很常见的测试,手动测试大家再熟悉不过了,那如何进行自动化登录测试呢!本文就基于python+selenium结合unittest单元测试框架来进行一次简单但比较完整的cnblog自动化 ...
- python+selenium自动化登录dnf11周年活动界面领取奖励登录部分采坑总结[1]
背景: Dnf的周年庆活动之一,游戏在6月22日 06:00~6月23日 06:00之间登陆过游戏后可以于6月25日 16:00~7月04日 06:00领取奖励 目标:连续四天自动运行脚本,自动领取所 ...
随机推荐
- 深入C++04:模板编程
模板编程 函数模板 模板意义:对类型也进行参数化: 函数模板:是不编译的,因为类型不知道 模板的实例化:函数调用点进行实例化,生成模板函数 模板函数:这才是要被编译器所编译的 函数模板.模板的特例化. ...
- 快速选择 第k个数
快速选择 第k个数 题目描述 给定一个序列,求第k小的数 算法思想 利用快速排序思想,算法复杂度能达到O(n)步骤如下: 1.找到排序分界点x,这里选择区间最左值 2.排序,让左边的值都小于x,右边都 ...
- SmartIDE v0.1.19 - 码云(Gitee)最有价值开源项目奖项、工作区策略、类虚拟机镜像VMLC、Server安装手册
SmartIDE v0.1.19 (CLI Build 3909, Server Build 3890) 已经发布,本次Sprint主要完成2个重要特性,工作区策略和类虚拟机容器(VM Like Co ...
- 使用 Dapr JS SDK 让 Nest.js 集成 Dapr
Dapr 是一个可移植的.事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的.无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架. Dapr 中文手册:ht ...
- 送分题,ArrayList 的扩容机制了解吗?
1. ArrayList 了解过吗?它是啥?有啥用? 众所周知,Java 集合框架拥有两大接口 Collection 和 Map,其中,Collection 麾下三生子 List.Set 和 Queu ...
- 经典漏洞-后台备份数据库getshell
由于接触安全时间不多,一些老的getshell方法不是很清楚.这次碰到了个老站,正好学习了一下. 首先这边是用户名可以猜测出来的,因为输入错误的用户名显示用户名不存在,如果存在的话会显示密码错误. 爆 ...
- SAP IDOC
物料主数据 供应商主数据 价格档案 采购订单 采购计划协议 srm发货单 物料凭证 发票校验 发票校验过账或删除信息返回 CALL FUNCTION 'BAPI_INCOMINGINVOICE_PAR ...
- Python之枚举法解数学题
作为初二的学生,数学题总是令我苦恼的问题.尤其是我们这里的预备班考试(即我们这里最好的两所高中提前一年招生,选拔尖子生的考试)将近,我所面对的数学题越发令人头疼. 这不,麻烦来了: 如图,在正方形AB ...
- SQL Server数据库 备份A库,然后删除A库,再还原A库,此时数据库一直显示“正在还原”的解决方法
SQL Server数据库 备份A库,然后删除A库,再还原A库,此时数据库一直显示"正在还原"的解决方法: A库一直显示"正在还原". 在这种状态下,由于未提交 ...
- Elasticsearch学习系列七(Es分布式集群)
核心概念 集群(Cluster) 一个Es集群由多个节点(Node)组成,每个集群都有一个共同的集群名称作为标识 节点(Node) 一个Es实例就是一个Node.Es的配置文件中可以通过node.ma ...