自动化选课(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领取奖励 目标:连续四天自动运行脚本,自动领取所 ...
随机推荐
- Spring IOC源码研究笔记(2)——ApplicationContext系列
1. Spring IOC源码研究笔记(2)--ApplicationContext系列 1.1. 继承关系 非web环境下,一般来说常用的就两类ApplicationContext: 配置形式为XM ...
- React简单教程-4-事件和hook
前言 在上一章 React 简单教程-3-样式 中我们建立了一个子组件,并稍微美化了一下.在另一篇文章 React 简单教程-3.1-样式之使用 tailwindcss 章我们使用了 tailwind ...
- .NET C#基础(7):接口 - 人如何和猫互动
0. 文章目的 面向有一定基础的C#初学者,介绍C#中接口的意义.使用以及特点. 1. 阅读基础 了解C#基本语法(如定义一个类.继承一个类) 理解OOP中的基本概念(如继承,多态) 2. ...
- 开发工具-Redis Desktop Manager下载地址
更新记录 2022年6月10日 完善标题. 官方: https://github.com/uglide/RedisDesktopManager 免费打包版: https://github.com/le ...
- 彰显个性│制作一个独一无二的动态 svg 头像
一.头像预览 看一下博主的动态图像,是不是很炫酷,想不想拥有一个? 这是一个 svg 图片,svg 图片不仅可以通过制图软件制作外,其实也可以通过代码进行开发 因为 svg 本质上是一个下 xml 文 ...
- 【Java面试】介绍下Spring IoC的工作流程
Hi,我是Mic 一个工作了4年的粉丝,在面试的时候遇到一个这样的问题. "介绍一下Spring IOC的工作流程" 他说回答得不是很好,希望我能帮他梳理一下. 关于这个问题,我们 ...
- 《ECMAScript 6 入门》【二、变量的解构赋值】(持续更新中……)
前言: 让我们看下es6的新语法解构,跟模式匹配类似.一.数组的解构赋值 举个例子给多个变量赋值的写法: var a =1;var b =2;var c =3; 需要写多个变量特别麻烦,我们先使用以前 ...
- SAP APO - Architecture
SAP APO体系结构由多个组件组成-数据库,BI环境包含InfoCube和实时缓存. InfoCube是BI数据集市的一部分,实时缓存是您保留与计划和调度有关的所有数据的主要区域. 您可以在实时缓存 ...
- wsl2安装百度apollo及其基本配置
一. wsl2的开启 首先 WSL2 gui 需要Windows 11 Build 22000版本以上才支持 利用管理员权限打开PowerShell 执行 dism.exe /online /enab ...
- CSS进阶内容—盒子和阴影详解
CSS进阶内容 在学习了CSS基本知识之后,我们需要进一步了解CSS,因此写下了这篇文章 当然如果没有学习之前的知识,可以到我的主页中查看之前的文章:秋落雨微凉 - 博客园 CSS三大特性 首先我们先 ...