• 【Python】10 自动选课


    背景

    某些学校的选课规定是只能在特定时间,由上千人同时登陆教务系统,选取数量不充足的课程。
    这样做的后果是一部分人登陆不上系统;另一部分人登陆进了系统但已经没有剩余课程了;只有一部分人能够选到课程,但也未必是心仪的课程。

    笔者认为这样的选课规则显然是有问题的,在信息化如此发达的现代社会,采取这种“抢课”的方式,仿佛回到原始社会的大草原上追逐猎物,只有精力充沛、运气好的猎人才能追到猎物。
    如何保证公平是个永恒的话题。我以为一种可能的方案是预选+摇号,这样或许选到课程的人会更多,而不是集中于少数人。

    但如何在现有选课规则下选到课,还得用魔法来打败魔法。在选课结束后,笔者一门课程也没有选到,因此笔者尝试编写一个自动化脚本。脚本每隔固定时间刷新选课网页,当有同学退课时,立即报名。实践表明,这种策略非常有效,三周内成功选到所有七门课程。

    祝大家都能选上心仪的课程!

    实现

    自动化脚本采用Python语言编写,使用selenium库模拟浏览器操作,使用ddddocr库识别验证码。分为自动登录 → \rightarrow 刷新网页 → \rightarrow 报名课程三个步骤。

    自动登录

    教务系统通常有验证码,可采用第三方库ddddocr识别后,再自动输入。

    def Identify_verifi_code(driver):
        driver.save_screenshot("D:\\2.png") #//获取页面截图
        img = Image.open('D:\\2.png') ## 打开2.png文件,并赋值给img
        region = img.crop((650,438,772,491))  #//对获取的截图进行裁剪
        region.save('D:\\3.png')  #//保存裁剪后的图片
        ocr = ddddocr.DdddOcr()  #//导入验证码识别
        with open("D:\\3.png", "rb") as f:
            img_bytes = f.read()
        res = ocr.classification(img_bytes)  #//将识别出来的验证码赋给res
        return res
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    路径和图片名可以按需更改。

    刷新网页

    def do_login(driver):
        driver.maximize_window() #将窗口最大化
        my_action=ActionChains(driver)
    
        verifi_code = Identify_verifi_code(driver) #识别验证码
        # 找到登录框 输入账号密码
        driver.find_element(By.ID, 'UserId').send_keys(username)#输入用户名
        driver.find_element(By.ID, 'Password').send_keys(password)#输入密码
        driver.find_element(By.ID, 'VeriCode').send_keys(verifi_code)#输入验证码
    
        time.sleep(6)
        wait = WebDriverWait(driver, 10) #10秒内每隔500毫秒扫描1次页面变化,当出现指定的元素后结束。
        wait.until(lambda driver: driver.find_element(By.XPATH, login))
        driver.find_element(By.XPATH, login).click() #点击登录
    
        wait = WebDriverWait(driver, 20) #20秒内每隔500毫秒扫描1次页面变化,当出现指定的元素后结束。
        wait.until(lambda driver: driver.find_element(By.XPATH, goverment))
        driver.find_element(By.XPATH, goverment).click()#点击培养管理
    
        time.sleep(1)
        driver.find_element(By.XPATH, lecture_sign_up).click()
        time.sleep(5)
        count = 0
        
        while True:
            count = count + 1
            print(count, end = " ")
            print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
            
            for lecture in lectures:
                time.sleep(1)            
    
                driver.switch_to.frame('mainFrame')
                
                time.sleep(2)
                driver.find_element(By.CLASS_NAME,lecture_name).send_keys(lecture) #输入讲座题目文本框
    
                time.sleep(1)
                driver.find_element(By.XPATH, query).click() #点击查询
    
                time.sleep(2)
                driver.find_element(By.XPATH, sign_up).click() #点击报名
    
                time.sleep(1)
                driver.find_element(By.XPATH, submit).click() #点击确定
    
                time.sleep(1)
                driver.switch_to.parent_frame()
                driver.find_element(By.XPATH, lecture_sign_up).click()
            
            time.sleep(90)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    报名课程

    if __name__ == '__main__':
        # 模拟浏览器打开网站
        # 添加参数
        options = Options()
        # 关闭沙盒启动
        options.add_argument('--no-sandbox')
    
        driver = webdriver.Chrome(chrome_options = options)
        driver.get(url)
    
        # 登录并查询
        try:
            do_login(driver)
        except:
            driver.quit()
            driver = webdriver.Chrome(chrome_options = options)
            driver.get(url)
            do_login(driver)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    完整源码

    # -*- coding: utf-8 -*-
    #2022/10/28
    #自动刷新网站,查询讲座剩余名额,自动报名
    
    from selenium import webdriver
    from selenium.webdriver.support.select import Select
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait 
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.chrome.service import Service
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.action_chains import ActionChains
    from PIL import Image
    import time
    import ddddocr
    import base64
    
    # 只需修改下面三项即可 学号 密码 网址
    username = "12345678"
    password = "88888888"
    url = "https://login.com" 
    
    lectures = []
    # lectures.append("大坝安全技术前沿与创新领域")
    # lectures.append("梯级水库群联合调度高效优化方法研究")
    # lectures.append("海上风电桩基冲刷与防护研究与前沿")
    # lectures.append("高坝泄洪消能研究进展")
    # lectures.append("在高原探寻铅锌宝藏")
    lectures.append("好氧颗粒污泥的研究和应用:新污染物影响与稳定运行")
    # lectures.append("大体积混凝土无人运浇系统模型研究")
    
    # F12找到这些位置的 full XPath
    login = "/html/body/div[2]/form/div/div[1]/div[5]/button" #登录
    
    goverment = "/html/body/div[2]/div/div[1]/div[3]/div[2]/a"#培养管理
    lecture_sign_up = "/html/body/div[2]/div/div[1]/div[3]/div[2]/ul/li[14]/a"#博导讲座报名
    lecture_name = "textbox-text.validatebox-text.textbox-prompt" #讲座题目
    lecture_name_text = "textbox-text.validatebox-text" #讲座题目
    
    query = "/html/body/div[1]/div/div/div/div[2]/a/span/span[1]"#查询
    sign_up = "/html/body/div[1]/div/div/div/div[3]/div/div[1]/div[2]/div[2]/table/tbody/tr/td[10]/div/a[2]"#报名讲座
    submit = "/html/body/div[3]/div[2]/div[4]/a/span"#确定
    
    
    # 识别验证码
    def Identify_verifi_code(driver):
        driver.save_screenshot("D:\\2.png") #//获取页面截图
        img = Image.open('D:\\2.png') ## 打开2.png文件,并赋值给img
        region = img.crop((650,438,772,491))  #//对获取的截图进行裁剪
        region.save('D:\\3.png')  #//保存裁剪后的图片
        ocr = ddddocr.DdddOcr()  #//导入验证码识别
        with open("D:\\3.png", "rb") as f:
            img_bytes = f.read()
        res = ocr.classification(img_bytes)  #//将识别出来的验证码赋给res
        return res
        
    # 模拟登陆打卡
    def do_login(driver):
        driver.maximize_window() #将窗口最大化
        my_action=ActionChains(driver)
    
        verifi_code = Identify_verifi_code(driver) #识别验证码
        # 找到登录框 输入账号密码
        driver.find_element(By.ID, 'UserId').send_keys(username)#输入用户名
        driver.find_element(By.ID, 'Password').send_keys(password)#输入密码
        driver.find_element(By.ID, 'VeriCode').send_keys(verifi_code)#输入验证码
    
        time.sleep(6)
        wait = WebDriverWait(driver, 10) #10秒内每隔500毫秒扫描1次页面变化,当出现指定的元素后结束。
        wait.until(lambda driver: driver.find_element(By.XPATH, login))
        driver.find_element(By.XPATH, login).click() #点击登录
    
        wait = WebDriverWait(driver, 20) #20秒内每隔500毫秒扫描1次页面变化,当出现指定的元素后结束。
        wait.until(lambda driver: driver.find_element(By.XPATH, goverment))
        driver.find_element(By.XPATH, goverment).click()#点击培养管理
    
        time.sleep(1)
        driver.find_element(By.XPATH, lecture_sign_up).click()
        time.sleep(5)
        count = 0
        
        while True:
            count = count + 1
            print(count, end = " ")
            print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
            
            for lecture in lectures:
                time.sleep(1)            
    
                driver.switch_to.frame('mainFrame')
                
                time.sleep(2)
                driver.find_element(By.CLASS_NAME,lecture_name).send_keys(lecture) #输入讲座题目文本框
    
                time.sleep(1)
                driver.find_element(By.XPATH, query).click() #点击查询
    
                time.sleep(2)
                driver.find_element(By.XPATH, sign_up).click() #点击报名
    
                time.sleep(1)
                driver.find_element(By.XPATH, submit).click() #点击确定
    
                time.sleep(1)
                driver.switch_to.parent_frame()
                driver.find_element(By.XPATH, lecture_sign_up).click()
            
            time.sleep(90)
    
    if __name__ == '__main__':
        # 模拟浏览器打开网站
        # 添加参数
        options = Options()
        # 关闭沙盒启动
        options.add_argument('--no-sandbox')
    
        driver = webdriver.Chrome(chrome_options = options)
        driver.get(url)
    
        # 登录并查询
        try:
            do_login(driver)
        except:
            driver.quit()
            driver = webdriver.Chrome(chrome_options = options)
            driver.get(url)
            do_login(driver)    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127

    参考资料

    [1]零基础十分钟看懂自动打卡程序超详细
    [2]selenium元素定位失败常见情况,以及switch_to.frame()的用法
    [3]学习笔记:python识别验证码自动登录

  • 相关阅读:
    记录:2022-9-10 完美数 快乐数 括号生成 请求调页 页面置换 写时复制 页面缓冲算法
    java解压缩
    阿里云体验有奖:使用PolarDB-X与Flink搭建实时数据大屏
    嵌入式Linux上ifpulgd的使用配置与qemu模拟验证
    Make.com实现多个APP应用的自动化的入门指南
    分析思路:数据结构
    java计算机毕业设计人口老龄化常态下的社区老年人管理与服务平台源码+数据库+系统+lw文档+mybatis+运行部署
    在Linux/Ubuntu/Debian中使用lsof和fuser查看/解除文件占用
    高斯消元
    java计算机毕业设计共享充电宝管理系统演示录像2021源码+mysql数据库+系统+lw文档+部署
  • 原文地址:https://blog.csdn.net/weixin_43012724/article/details/127839129