首页 > 编程语言 >自动化选课(Python + selenium

自动化选课(Python + selenium

时间:2022-08-20 18:33:48浏览次数:71  
标签:选课 Python selenium self driver element course time find

​ 前几天听到朋友说自己选课事情,突发奇想想要搞这样一个东西,但是由于各种原因只做到以下的完成度,具体的情况也会在解释的最后留下。这个只适用于曲师大的教务系统,因为用的这个系统来进行的一个调试,对于其他的系统,思路都是一样的,代码也只适用于学习,请不要用以其他用途!代码放在最后。

工具

  • Python3
  • selenium库(浏览器自动化操作)
  • ddddocr库(OCR图片文字识别)
  • time库(定时操作)

思路

​ 对于想要做到的这个需求呢,我选择的是python + selenium库进行一个浏览器自动化操作,在写的过程中因为发现了一个验证码的问题所以又用到了一个ddddocr库,如果想要定时操作的话再加上一个time库。之后就是理清操作的顺序就好了,想到于人工操作一遍的过程。

  1. 进入系统登录界面
  2. 进入用户界面
  3. 进入选课界面
  4. 开始选课

大的一个方向、思路就是上面这四步,具体的细化之后再谈及。

过程

进入系统登录界面

​ 这一步就很简单,直接用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

一些操作的解释

  1. selenium库的使用可以查一下其他博主的介绍
  2. 关于元素的定位,一般我习惯于使用通过ID和XPATH来定位(XPATH 就是 "//*[@xx='abc']/li[1]/")这个也可以看看如何去使用。
  3. ddddocr库是看图片的编码来转换成文本

此代码可能出现的问题(完成度不是很高):

​ 因为我本身不是曲师大的校友所以说我没有进行一个完全的操作,对系统的认识也不是很充分这样写出来的代码当然也完成度也不能说是很高的,下面我就大概说一下这个代码可能产生的问题。

  1. 如果系统崩溃(加载不出页面……),程序应该是不能执行命令。
  2. 最后的选课部分只进行了一个点击,并没有确认,因此实际上这段代码是无法完成选课的!
  3. 可能图片识别有一定的误差,导致不能登陆成功(ddddocr库可能出的问题)
  4. 操作过快以至于元素没有加载出来,这一点我通过time.sleep()函数来进行了一个优化,每次选课间隙也添加一个3秒的一个等待。
  5. 可能通过ID、上课老师、上课星期几三个限制无法确定唯一的课程
    ……
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,self,driver,element,course,time,find
From: https://www.cnblogs.com/F0und/p/16608360.html

相关文章

  • 【Python基础教程】类的定义和使用
    哈喽兄弟们,今天咱们分享一下类的定义和使用。 在Python中,类表示具有相同属性和方法的对象的集合。在使用类时,需要先定义类,然后再创建类的实例,通过类的实例就可以访问......
  • 配置环境并使用测试--python
    一、使用anaconda搭建python环境condainfo--env 查看环境condaremove-nweb--all删除环境condacreate--namepythonpython=3.8创建名为python的虚拟环境......
  • 爱吃瓜?那就来用python采集每天热点,发送到自己的邮箱,绝不错过
    前言嗨喽,大家好呀~这里是爱看美女的茜茜呐本篇文章内容主要为如何用代码,把你想要的内容,以邮件的形式发送出去内容可以自己完善,还可以设置一个定时发送,或者开机启动自动......
  • Python小游戏——外星人入侵(保姆级教程)第一章 03 04
    系列文章目录第一章:武装飞船03:设置飞船图片04:创建Ship类——管理飞船行为的类一、设置飞船图片1.注意事项A.将图片设置为位图bmp格式最简单,因为pygame默认加载位图B......
  • Python常用命名规范,让你的代码更加优雅!
    哈喽兄弟们,今天分享一下以前总结的一些Python常用命名规范,希望对大家有所帮助。命名规范在编写代码中起到很重要的作用,虽然不遵循命名规范,程序也可以运行,但是使用命名......
  • python a* 寻址算法 我是按照像素来判断是不是障碍物
    fromrandomimportrandintfromPILimportImageclassSearchEntry():def__init__(self,x,y,g_cost,f_cost=0,pre_entry=None):self.x=x......
  • Python快速生成无用大文件(GB)
    importtimedefcreatfilesize(n):local_time=time.strftime("%Y%m%d%H%M%S",time.localtime())file_name=r"D:\data\test\\"+str(local_time)+".txt"......
  • 中国科学院大学研一选课
    秋季选课1.公共学位课(5)新时代zgtssh主义理论与实践(2)硕士学位英语(3)2.专业学位课(8)自然语言处理-网安学院(3)信息检索导论-网安学院(3)数据科学导论-网安学院(2)3.......
  • python 对文本进行分词
    #导入正则表达式相关模块importre#定义一个函数,通过该函数查找文本字符串中的每一个单词#然后计算每个单词出现的次数,最后按照出现次数从多到少放到变量中defg......
  • 学习:python 程序打包exe文件
    python程序打包exe.py首先要安裝模块pipinstall pyinstaller按住shift右鍵 打开命令窗口-输入命令intaller-F文件名.py,等待执行完成后,文件夹内会多一个dis......