自动化选课(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领取奖励 目标:连续四天自动运行脚本,自动领取所 ...
随机推荐
- 选择ERP频频踩雷?国内外ERP有差异,突破ERP软件单一性是关键
信息化日新月异的蓬勃发展,导致企业在选择ERP软件时频频踩雷.企业如何选择出一个适合自己的ERP软件系统呢?是选择国外知名公司的ERP软件产品,还是选择国内性价比高的ERP软件产品呢,小编就带大家了解 ...
- GDOI 2021 普及组溺水记
Day 1 T1 一看样例:答案不就是 \(\dfrac{\max_{i=1}^n a_i +1}{2}\) 吗? 于是自信打上,拍都不拍.然后就,,对了? 插曲:自己出了一个极端数据,发现 scan ...
- 关于全栈项目【臻美Chat】https访问 遇到的问题【技术栈:Nodejs】
首先我上线时可以http访问也可以https访问,那么配置如下:nginx.conf user root;worker_processes auto;error_log /var/log/nginx/ ...
- python 基础知识-day6(内置函数)
1.sorted():用于字典的排序 dict1={"name":"cch","age":"3","sex&q ...
- 【WPF】CAD工程图纸转WPF可直接使用的xaml代码技巧
前言:随着工业化的进一步发展,制造业.工业自动化等多领域,都可能用到上位监控系统.而WPF在上位监控系统方面,应该算是当下最流行的前端框架之一了.而随着监控体系的不断完善与更新迭代,监控画面会变得越来 ...
- centos 7搭建svn+apache及权限控制
SVN服务器运行模式: 模式1:svn服务器单独运行 监听: 3690端口 访问: svn://IP 模式2: svn 服务器+ apache : 80 端口 访问: http://IP 1. #安装 ...
- 如何查看/修改Redis密码
一.修改密码: 打开redis.windows.conf文件,默认是没有红框框里这句话的,因为默认密码是"",就是没有,跟MySql一样. 加上这句话意思就是密码修改为 root ...
- 链表设计与Java实现,手写LinkedList这也太清楚了吧!!!
链表设计与实现 在谈链表之前,我们先谈谈我们平常编程会遇到的很常见的一个问题.如果在编程的时候,某个变量在后续编程中仍需使用,我们可以用一个局部变量来保存该值,除此之外一个更加常用的方法就是使用容器了 ...
- labview从入门到出家5(进阶篇)--程序调试以及labview函数库的运用
跟了前面几章的操作流程,相信大家对labview有了一定的认识.其实只要了解了labview的编程思路,再熟悉地运用各个变量,函数以及属性,那么我们就可以打开labview的大门了.跟其他编程语言一样 ...
- C++算数运算符和位运算符
C++根据功能和用途将运算符分为算数运算符.位运算符.关系运算符和逻辑运算符等不同类型.四种不同运算符的优先级从大到小依次位算-位-关-逻. 一.算数运算符 1.加减乘除(+ - * /) 加减乘除位 ...