本文旨在分享选课selenium脚本python代码
2024-6-26更新
脚本介绍:
- 基于requests(2.31.0),selenium(4.9.0)与google。
- 由于编程水平局限,脚本运行可能会出现bug,并非完美封装.
- 脚本完全模拟手动选课,受网络环境影响较大,要想更快可以直接向服务器发送请求,但是这不是本次分享的主题(请求参数容易变化...).
抢课具体的程序:
本人运行环境为:python-3.10 pycharm平台
# -*- coding: utf-8 -*-
# @Time : 2023/12/2 22:55
import os
try:
from selenium import webdriver
except:
print("没有找到selenium,尝试下载--")
os.system(f'pip install selenium')
from selenium import webdriver
import time
from queue import Queue
from datetime import datetime
from threading import Thread
from selenium.webdriver.common.by import By
from selenium.common import TimeoutException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException, ElementNotInteractableException
class GetCourse:
url = "https://my.cqu.edu.cn"
def __init__(self, courseList, driver=None):
self.driver = webdriver.Chrome() if driver is None else driver
self.courseList = courseList
def wait(self, sensitivity=1, *element):
# 隐式等待 - 单元素
while sensitivity > 0:
try:
webWait = WebDriverWait(self.driver, 4)
wait = webWait.until(EC.presence_of_element_located((element)))
return wait
except TimeoutException:
sensitivity -= 1
try:
ele = self.driver.find_element(*element)
self.driver.execute_script("arguments[0].scrollIntoView();", ele)
except Exception as e:
print(e)
print("retry")
raise NoSuchElementException
def waits(self, *element):
# 隐式等待 - 多元素
count = 0
while True:
try:
webWait = WebDriverWait(self.driver, 4)
wait = webWait.until(EC.presence_of_all_elements_located((element)))
return wait
except TimeoutException:
count += 1
if count % 3 == 0:
self.driver.refresh()
def login(self, kind, text):
while True:
input = self.wait(10, By.XPATH, f"//app-login-normal//form/div[{kind}]/nz-input-group/input")
input.clear()
input.click()
time.sleep(0.4)
input.send_keys(text)
if input.get_attribute("value") == text:
break
def initial_cookie(self):
# 执行登录
self.driver.get(self.url)
self.login(1, Properties.ID)
self.login(2, Properties.pwd)
self.driver.find_element(By.XPATH, "//*[@id=\"login-normal\"]/div[2]/form/div[6]/div/button").click()
def do(self, func):
# 从主界面进入选课界面
self.driver.get("https://my.cqu.edu.cn/enroll/Home")
xpathStr = f"//div[contains(@class,\"select-model\")]//div[contains(@class,\"select-list-model\") or contains(@class,\"selected-course-info\")]//button[.//span[contains(text(), \"{func}\")]]"
while True:
try:
self.wait(2, By.XPATH, xpathStr)
while datetime.now() <= Properties.begin:
pass
self.driver.find_elements(By.XPATH, xpathStr)[-1].click()
'''
list_windows = self.driver.window_handles
self.driver.switch_to.window(list_windows[-1])
转换页面, 如果发生页面跳转
'''
break
except ElementNotInteractableException:
self.driver.find_elements(By.XPATH, xpathStr)[0].click()
break
except Exception as e:
print(e) # 打印Exception信息
time.sleep(Properties.DELAY_TIME)
self.driver.get("https://my.cqu.edu.cn/enroll/Home")
def close(self):
try:
self.driver.find_element(By.XPATH, "//i[@aria-label=\"图标: close\"]").click()
except Exception:
pass
def select(self, name):
# 执行选课操作
while True:
try:
# 选择课程种类
self.wait(2, By.XPATH, f"//a[@title=\"{name}\"]").click()
# 选择课程号
xpath_CID = f"//tbody[@class=\"ant-table-tbody\"]/tr[.//span[text()=\"{self.courseList[name]}\"]]/td[last()]/span"
self.wait(2, By.XPATH, xpath_CID)
try:
self.driver.find_element(By.XPATH, f"{xpath_CID}[./label]").click()
except NoSuchElementException:
print("{}课程无法选择".format(name))
self.close()
return False
break
except Exception:
self.driver.refresh()
# 初步确认
try:
self.driver.find_element(By.XPATH,
f"//div[@class=\"select-class-info-modal\"]//button[.//span[contains(text(),\"选\")]]").click()
# 进一步确认
self.driver.find_element(By.XPATH,
f"//div[@class=\"ant-modal-confirm-btns\"]//button[.//span[contains(text(), \"确\")]]").click()
except Exception as e:
pass
finally:
self.close()
return True
def isSelected(self, name):
# 判断是否成功选到目标课程
had_Selected = self.waits(By.XPATH, "//div[@id=\"resultList\"]//span[@class=\"resultList-name\"]/span/a")
for i in had_Selected:
Properties.had_Selected_items.add(i.get_attribute("innerText").strip())
print("未选课程{}".format(set(self.courseList.keys() - Properties.had_Selected_items)))
if name in Properties.had_Selected_items:
return True
return False
def circle(self, courseQueue):
preCourseList = []
while courseQueue.empty() is False:
courseName = courseQueue.get()
if self.select(courseName):
preCourseList.append(courseName)
for course in preCourseList:
if not self.isSelected(course):
courseQueue.put(course)
if courseQueue.empty():
return True
time.sleep(1)
self.driver.refresh()
time.sleep(10)
return self.circle(courseQueue)
def run_rand(self, courseQueue):
self.driver.maximize_window()
self.initial_cookie()
time.sleep(Properties.DELAY_TIME)
self.do("选")
print(f"时间已到,开始抢课")
time.sleep(Properties.DELAY_TIME)
self.circle(courseQueue)
print("任务完成")
def run(courseList, thread_num, driver=None):
# 只开几个线程,
queue = Queue(len(courseList))
thread_lis = []
for courseName, v in courseList.items():
queue.put(courseName)
for i in range(0, thread_num):
thread_lis.append(Thread(target=GetCourse(courseList, driver).run_rand, args=(queue,)))
for thread in thread_lis:
thread.start()
class Properties:
# 全局变量
ID = "" # 统一认证账号
pwd = ".." # 统一认证密码
try:
import version_s as props
ID = props.ID
pwd = props.password
except ImportError:
pass
had_Selected_items = set()
begin = datetime.strptime("2024-06-29 8:50:01", "%Y-%m-%d %H:%M:%S") # 开始抢课时间
DELAY_TIME = 0.9 # 延迟时间,防止页面未加载完成,如果程序运行不稳定,可以适当增加延迟时间
# 自定义课程列表 课程名:课程班号
courseList = {
"能源大数据与人工智能": "154020-002",
}
google_path = r"C:\Program Files\Google\Chrome\Application\chrome.exe" # 你的谷歌浏览器路径
def __init__(self):
# 配置selenium参数
from selenium.webdriver.chrome.service import Service
service = Service(r"chromedriver.exe")
options = Options()
options.binary_location = self.google_path
try:
driver = webdriver.Chrome(options=options, service=service)
except Exception:
print("驱动异常,正在下载--")
from updateDriver import update_driver
update_driver()
print("下载完成--")
driver = webdriver.Chrome(options=options, service=service)
self.driver = driver
if __name__ == '__main__':
driver = Properties().driver # 配置参数
run(Properties.courseList, thread_num=1, driver=driver)
程序介绍:
Properties:配置类,自定义相关参数:账号,抢课时间,课程列表,延时时间,驱动配置.
课程字典参数定义:
获取浏览器驱动的代码:
# -*- coding: utf-8 -*-
# @Time : 2023/8/29 13:48
import requests
import zipfile
import os
import json
root = "."
def removeDirs(path, dir):
if os.path.exists(os.path.join(path, dir)):
path = os.path.join(path, dir)
if os.path.isdir(path):
os.chdir(path)
absPath = os.getcwd()
for inner in os.listdir('.'):
if os.path.isdir(inner):
removeDirs(os.getcwd(), inner)
continue
os.remove(inner)
os.chdir(absPath[:absPath.rfind("\\")])
os.removedirs(dir)
else:
os.remove(path)
def update_driver():
url = 'https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json'
resp = json.loads(requests.get(url).text)
for platforms in resp['channels']['Stable']['downloads']['chromedriver']:
if platforms['platform'] == "win64":
zips = platforms['url']
file = requests.get(zips).content
with open('./chromedriver-win64.zip', 'wb') as f:
f.write(file)
zip_file = zipfile.ZipFile('chromedriver-win64.zip')
name_ = filter(lambda x: x.endswith(".exe"), zip_file.namelist()).__next__()
zip_file.extract(name_, root)
if os.path.exists(f'{root}\chromedriver.exe'):
os.remove(f'{root}\chromedriver.exe')
zip_file.close()
os.rename(os.path.join(root, name_), f'{root}\chromedriver.exe')
removeDirs(root, 'chromedriver-win64')
removeDirs(root, 'chromedriver-win64.zip')
update_driver()
最后再附上文件目录:
将两个程序放到同一个文件夹下就行了,如果安装selenium报错,那么请自行搜寻如何安装selenium.
希望这个脚本可以帮助到你,如果遇到了bug欢迎向我反馈,我会很感激.