# python 实现自动选课

主要利用 selenium 与 ddddocr 库实现了对南大选课系统已收藏课程的自动化选择, 频率约为每两秒一次。实际测试中在一天时间内抢到了三门通识与两次近代史。

驱动这个项目动力来自于南大选课系统的落后。在开放选课的前一分钟 mikeMao 点击了一下刷新按钮,然后当 mikeMao 看到选课界面时已经是十分钟以后了。他没有任何体育课,也没有抢到近代史(因为他上学期为了逃离黑榜退掉了近代史),并且只中了一门必中的通识课!如果只靠蹲,mikeMao 这学期的课表可能会爆炸,于是 mikeMao 吐槽能否开发一个自动选课脚本,他的室友 stonerXiao 花了两小时写了一个可以使用的抢课脚本,mikeMao 获得了源码。但是他觉得一些地方写的不是很好,于是第二天上课(两点的课,两点零一群里通知老师有事不来了),他就动手改了一遍,借鉴了 stonerXiao 的刷新思路,mikeMao 几乎重写了一份代码。并在接下来的一天内塞满了课表。

源码

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.edge.options import Options
import time
import ddddocr
import traceback
# 使用须知 需要安装:selenium 与 ddddorc 库 edge 浏览器及对应版本的驱动程序 并且参照注释对下面源码进行改动 将想选的课收藏
# 可能不明原因退出或报错 可能是收藏被吞了(重新收藏一下) 或者网络波动(重启程序即可)
username = ""  # 添加用户名
password = ""  # 添加密码
url = "https://xk.nju.edu.cn/xsxkapp/sys/xsxkapp/*default/index.do"
login_button = "/html/body/div[1]/article/section/div[4]/div[1]/button"
start = "/html/body/div[1]/article/section/div[4]/div[2]/button"
favorite = "/html/body/div[1]/header/div[2]/ul/li[8]/a"
special = "/html/body/div[1]/header/div[2]/ul/li[1]/a"  # for refresh
select = "/html/body/div[1]/article/div[2]/div[2]/table/tbody/tr[{}]/td[8]/a[2]"
confirm = "/html/body/div[3]/div[2]/div[2]/div[1]"
confirm_ = "/html/body/div[3]/div[2]/div[2]/div"
course_list = []
# 识别验证码
def Identify_verifi_code(driver):
    img = driver.find_element(By.XPATH, '//*[@id="vcodeImg"]')
    img.screenshot('vcode.png')
    ocr = ddddocr.DdddOcr()
    with open('vcode.png', 'rb') as f:
        img_bytes = f.read()
    res = ocr.classification(img_bytes)
    return res
def login(driver):
    # driver.maximize_window ()  # 将窗口最大化
    verifi_code = Identify_verifi_code(driver)  # 识别验证码
    # 找到登录框 输入账号密码
    driver.find_element(By.ID, 'loginName').send_keys(username)  # 输入用户名
    driver.find_element(By.ID, 'loginPwd').send_keys(password)  # 输入密码
    driver.find_element(By.ID, 'verifyCode').send_keys(verifi_code)  # 输入验证码
    wait = WebDriverWait(driver, 10)  # 10 秒内每隔 500 毫秒扫描 1 次页面变化,当出现指定的元素后结束。
    wait.until(lambda driver: driver.find_element(By.XPATH, login_button))
    driver.find_element(By.XPATH, login_button).click()  # 点击登录
    try:
        while True:
            verifi_code = Identify_verifi_code(driver)  # 识别验证码
            driver.find_element(By.ID, 'verifyCode').clear()
            driver.find_element(By.ID, 'verifyCode').send_keys(verifi_code)  # 输入验证码
            time.sleep(1)
            wait = WebDriverWait(driver, 10)  # 10 秒内每隔 500 毫秒扫描 1 次页面变化,当出现指定的元素后结束。
            wait.until(lambda driver: driver.find_element(By.XPATH, login_button))
            driver.find_element(By.XPATH, login_button).click()  # 点击登录
    except:
        {}
    wait = WebDriverWait(driver, 20)  # 20 秒内每隔 500 毫秒扫描 1 次页面变化,当出现指定的元素后结束。
    wait.until(lambda driver: driver.find_element(By.XPATH, start))
    driver.find_element(By.XPATH, start).click()
def is_Login(driver):
    try:
        driver.find_element(By.ID, 'loginName')
        return False
    except:
        return True
def start_select(driver):
    if is_Login(driver) == False:
        return False
    time.sleep(1)
    wait = WebDriverWait(driver, 20)  # 20 秒内每隔 500 毫秒扫描 1 次页面变化,当出现指定的元素后结束。
    wait.until(lambda driver: driver.find_element(By.XPATH, favorite))
    driver.find_element(By.XPATH, favorite).click()
    time.sleep(1)
    course_board = driver.find_element(By.CLASS_NAME, 'course-body')
    tr_list = course_board.find_elements(By.CLASS_NAME, 'course-tr ')
    print('已收藏课程:')
    for tr in tr_list:
        wait = WebDriverWait(tr, 5)
        wait.until(lambda tr: tr.find_element(By.XPATH, './td[2]'))
        course_name = tr.find_element(By.XPATH, './td[2]').text
        print(course_name, end="\n")
    count = 0
    while True:
        count = count + 1
        if count % 100 == 0:
            print('已尝试次数:' + count, end=" ")
            print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
        time.sleep(1)
        course_board = driver.find_element(By.CLASS_NAME, 'course-body')
        tr_list = course_board.find_elements(By.CLASS_NAME, 'course-tr ')
        for tr in tr_list:
            wait = WebDriverWait(tr, 5)
            wait.until(lambda tr: tr.find_element(By.XPATH, './td[8]/a[2]'))
            course_name = tr.find_element(By.XPATH, './td[2]').text
            select_button = tr.find_element(By.XPATH, './td[8]/a[2]')
            select_button.click()
            try:
                driver.find_element(By.XPATH, confirm).click()
                print("选课成功!")
                print("已成功选中{}".format(course_name))
                course_list.append(course_name)
                print("确认中")
                wait = WebDriverWait(driver, 10)  # 20 秒内每隔 500 毫秒扫描 1 次页面变化,当出现指定的元素后结束。
                wait.until(lambda driver: driver.find_element(By.XPATH, confirm_))
                driver.find_element(By.XPATH, confirm_).click()
                print("确认成功!")
            except:
                {}
        wait = WebDriverWait(driver, 3)  # 10 秒内每隔 500 毫秒扫描 1 次页面变化,当出现指定的元素后结束。
        wait.until(lambda driver: driver.find_element(By.XPATH, special))
        driver.find_element(By.XPATH, special).click()
        time.sleep(0.5)
        wait = WebDriverWait(driver, 3)  # 10 秒内每隔 500 毫秒扫描 1 次页面变化,当出现指定的元素后结束。
        wait.until(lambda driver: driver.find_element(By.XPATH, favorite))
        driver.find_element(By.XPATH, favorite).click()
def working():
    options = Options()
    # 关闭沙盒启动 把下面两行注释掉 会出现浏览器界面 建议注释掉看看能不能运行 可以再取消注释
    #options.add_argument('--no-sandbox')
    #options.add_argument("--headless")
    driver = webdriver.Edge(executable_path="msedgedriver.exe", options=options)  # executable_path 改成下载的 edge 驱动程序路径
    driver.get(url)
    # 登录并查询
    try:
        login(driver)
        start_select(driver)
    except:
        traceback.print_exc()
    finally:
        print("已选到如下课程:")
        print(course_list)
        driver.quit()
if __name__ == '__main__':
    working()
更新于

请我喝[茶]~( ̄▽ ̄)~*

MikeMao 微信支付

微信支付

MikeMao 支付宝

支付宝

MikeMao 贝宝

贝宝