自动化选课(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领取奖励 目标:连续四天自动运行脚本,自动领取所 ...
随机推荐
- Mysql优化基础之Explain工具
字段解释 id:代表sql中查询语句的序列号,序列号越大则执行的优先级越高,序号一样谁在前谁先执行.id为null则最后执行 select_type:查询类型,表示当前被分析的sql语句的查询的复杂度 ...
- 机器学习-学习笔记(二) --> 模型评估与选择
目录 一.经验误差与过拟合 二.评估方法 模型评估方法 1. 留出法(hold-out) 2. 交叉验证法(cross validation) 3. 自助法(bootstrapping) 调参(par ...
- 【clickhouse专栏】基础数据类型说明
本文是clickhouse专栏第五篇,更多内容请关注本号历史文章! 一.数据类型表 clickhouse内置了很多的column数据类型,可以通过查询system.data_type_families ...
- ESXI系列问题整理以及记录——使用Windows PowerShell中的SSH功能连接ESXI控制台
首先进入ESXI管理页面,开启ESXI的SSH功能 接下来到位于同一局域网的Win主机上开启Powershell,如果ESXI主机的IP地址为192.168.1.77,则在Powershell中输入: ...
- 3D大场景展示功能你了解多少?见详解!
裸眼3D技术的出现打破了真实与虚拟的界限,人们不仅希望能够体验奇妙的虚拟场景,也希望足不出户在短短几分钟内就能看到遍布各地的场景,希望能实时对接关键数据. 裸眼3D技术的出现打破了真实与虚拟的界限,人 ...
- Windows-安装OpenVINO
安装指导书链接: https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_wi ...
- 手写一个仿微信登录的nodejs程序
前言 首先,我们看一下微信开放文档中的一张图: 上面的一幅图中清楚地介绍了微信登录整个过程,下面对图上所示进行总结: 一.二维码的获得 用户打开登录网页后,登录网页后台根据微信OAuth2.0协议向微 ...
- mybatis转义反斜杠_MyBatis Plus like模糊查询特殊字符_、\、%
在MyBatis Plus中,使用like查询特殊字符_,\,%时会出现以下情况: 1.查询下划线_,sql语句会变为"%_%",会导致返回所有结果.在MySQL中下划线" ...
- [JLOI2015]装备购买 题解 / 实数线性基学习笔记
题目链接 看这道题之前,以为线性基只是支持异或的操作... 那么,我认为这道题体现出了线性基的本质: 就是说如何用最小的一个集合去表示所有出现的装备. 我们假设已经会使用线性基了,那么对于这道题该怎么 ...
- SHT11和SHT21传感器
1.传感器概述 SHT11和SHT21为瑞士Sensirion公司生产,精度和测量范围较广,但价格较高.SHT11和SHT21是具有IIC总线接口的单片全校准数字式相对湿度和温度传感器.该传感器采用独 ...