声明:这篇代码是我基于我向我的部长学习的,带有一些理解和稍微一丢丢的改善,就是把他的一些模块套入到循环里这样可以一次性枪很多课,不过写的不是并发的所以会有顺序导致的无法同时抢很多课,而是抢完一个又一个
在这里也附上大佬的链接!!!
https://github.com/Louis0052/SZTU_select_course.git
结果:
代码原理:
利用selenium爬虫去模拟人去点击和输入,并且调用js去选课
详细代码分析:
截取部分,大部分是重复的
1.调整相关设置
链接是这个页面
2.模拟登录点击
输入你的学号跟密码
讲解下第一个点击,原因是教务有时候输入账号密码需要上面点击一下,所以我就写了个点击!!
就是找到那个需要点击的模块然后用selenium去模拟人为点击就好了
之后的点击就是一步一步来了
3.跳转页面
请求的页面会变成第一个,所以加上
driver.window_handles[0]调整要控制的页面
4.设置要抢的课
这是某个课程的特征码
具体怎么看是鼠标右键,然后点击检查
鼠标放在我圈主的地方然后点击就可以看到了
第一个就是我们的my_jx0404id参数,第二个就是我们的my_kcid参数
我们有多门课的话我们就一列一列对应,用单引号闭合着
然后调用js去选课(这一段大佬重点我觉得,最开始我想要click去模拟但是一直没模拟出来,js直接搞出来了)
5.运行代码
修改后的源码:
from selenium import webdriver
from selenium.common import NoSuchElementException
from selenium.webdriver.common.by import By
from time import sleep, strftime, localtimeoption = webdriver.EdgeOptions()
option.add_experimental_option("detach", True) # 开启实验模式,不让浏览器关闭因为资源会回收
# option.add_argument("--headless") # 隐藏浏览器,但是写的时候最好打开,这样可以看到模拟过程
option.add_argument('user-agent=ywy') #设置ua头
driver = webdriver.Edge(options=option)
url = r"https://auth.sztu.edu.cn/idp/authcenter/ActionAuthChain?entityId=jiaowu" # 要访问的教务系统地址def bool_exist(driver, path): # 这个函数比较重要,它可以识别你的网页是否加载出来,如果没加载出来就继续等while 1: # 加载出来就可以返回寻找的路径,然后去模拟点击try:ele = driver.find_element(By.XPATH, path)return eleexcept NoSuchElementException:print("Element not found. Keep trying again.")sleep(0.5)def login_to_jw(username, passwd):driver.get(url=url)span_element = bool_exist(driver, "//span[@class='tab tab1' and @title='用户名密码认证']") # 调用判断的函数span_element.click() # 模拟点击input_username = driver.find_element(By.ID, "j_username")input_username.send_keys(username)sleep(0.5)input_passwd = driver.find_element(By.ID, "j_password")input_passwd.send_keys(passwd)sleep(0.5)login_button = driver.find_element(By.ID, "loginButton")login_button.click()# 成功登录link_element = bool_exist(driver, "//a[@href='/jsxsd/xsxk/xklc_list?Ves632DSdyV=NEW_XSD_PYGL']")link_element.click()# 成功进入选课界面1link_element = bool_exist(driver, "//a[contains(text(), '进入选课')]")link_element.click()last_button = bool_exist(driver, "//input[@value='进入选课']")last_button.click()sleep(5)# 进入到了选课界面def jump_coursepage(kind):match kind:case '1':driver.get('https://jwxt.sztu.edu.cn/jsxsd/xsxkkc/comeInBxqjhxk')case '2':driver.get('https://jwxt.sztu.edu.cn/jsxsd/xsxkkc/comeInGgxxkxk')case _:print('Course type error')driver.quit()exit()return driverdef choice_course(kind, my_jx0404id, my_kcid):# kind是选课类型,计划内还是公选js_method = ""js_jhn = f"xsxkOper('{my_jx0404id}','','','{my_kcid}','null','null');" # 这是必修课的格式js_gxk = f"xsxkFun('{my_jx0404id}','{my_kcid}','null');" # 公选课的格式match kind:case '1':js_method = js_jhnreturn js_methodcase '2':js_method = js_gxkreturn js_methodcase _:print('course type error')exit()def select_course(js_method):try_time = 1while True:driver.execute_script(js_method) # 控制台执行选课js方法select_status = driver.switch_to.alert.text # 获取选课状态if '你确认选择' in select_status:driver.switch_to.alert.accept()select_status = driver.switch_to.alert.text# sleep(0.5)driver.switch_to.alert.accept()if '选课成功' in select_status:print(strftime('%Y-%m-%d %H:%M:%S', localtime()), select_status)returnelif '已选择' in select_status or '冲突' in select_status:print(select_status)returnelse: # 为了能够第一时间抢课,即使不在选课时间范围时程序也将持续运行print(select_status)try_time += 1sleep(2)print(f'第{try_time}次自动选课中...')if __name__ == '__main__':username = "your student's num"passwd = "your student's password"kind_list = ['1', '1', '2'] # 1是计划内选课 2是公选课my_jx0404id_list = ['xxx', 'xxx', 'xxx']my_kcid_list = ['xxx', 'xxx', 'xxx']course_num = len(kind_list)login_to_jw(username, passwd)for i in range(0, course_num): # 用循环嵌套然后可以多门课js_method = "" # 下面这个函数是为了获取js需要模拟点击的部分,与课程相关,经过一定上面参数的组合js_method = choice_course(kind_list[i], my_jx0404id_list[i], my_kcid_list[i])jump_coursepage(kind_list[i])driver.window_handles[0]select_course(js_method)
最开始是想自己写的,但是遇到很多困难,例如页面加载比较慢,我就睡眠2s那样很笨,还有在选课的时候如果不调用js而是直接去点击的话也会麻烦很多,会出很多事情,所以我觉得大佬的思路挺好的。有些不改变的页面点击我就get请求,然后去操作那个请求的页面。学到挺多的
这个跨年级选课和跨专业选课因为需要自己提前搜索才会显示所以我没实验,计划内和公选课是可以成功的!!!