-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcourse.py
205 lines (166 loc) · 8.52 KB
/
course.py
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
import os
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
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.options import Options
import requests
import json
from PIL import Image
from io import BytesIO
import base64
# 要抢的课程
courses_wanted = ['DCS5206']
math_courses_wanted = ['专硕矩阵分析']
with open('account.json', 'r') as file:
account = json.load(file)
netid = account['netid']
pwd = account['pwd']
access_token = account['access_token']
os.environ['NO_PROXY'] = '*'
chrome_options = Options()
chrome_options.add_argument('--headless')
service = Service(executable_path='./chromedriver-mac-arm64/chromedriver')
driver = webdriver.Chrome(options=chrome_options, service=service)
# 1. 选课登陆
driver.get('https://cms.sysu.edu.cn/#/login')
login_button = WebDriverWait(driver, 3).until(
EC.element_to_be_clickable((By.XPATH, '/html/body/div[2]/div/div[2]/div[2]/div[1]/div[3]/div[1]/div[2]/button'))
)
login_button.click()
# 2. 中央身份服务
cas_domain = driver.current_url.split('//')[1].split('/')[0]
new_domain = cas_domain
cas_first_try = True
while new_domain == cas_domain:
multi_try_mod = 0 if cas_first_try else 1
# /html/body/div/div[1]/div/div[2]/div[1]/form/div[2]/div/input
netid_input = WebDriverWait(driver, 3).until(
EC.presence_of_element_located((By.XPATH, f'/html/body/div/div[1]/div/div[2]/div[1]/form/div[{1+multi_try_mod}]/div/input'))
)
# /html/body/div/div[1]/div/div[2]/div[1]/form/div[3]/input
pwd_input = WebDriverWait(driver, 3).until(
EC.presence_of_element_located((By.XPATH, f'/html/body/div/div[1]/div/div[2]/div[1]/form/div[{2+multi_try_mod}]/input'))
)
# /html/body/div/div[1]/div/div[2]/div[1]/form/div[4]/input
captcha_input = WebDriverWait(driver, 3).until(
EC.presence_of_element_located((By.XPATH, f'/html/body/div/div[1]/div/div[2]/div[1]/form/div[{3+multi_try_mod}]/input'))
)
# /html/body/div/div[1]/div/div[2]/div[1]/form/section[2]/input[4]
login_button_cas = WebDriverWait(driver, 3).until(
EC.presence_of_element_located((By.XPATH, '/html/body/div/div[1]/div/div[2]/div[1]/form/section[2]/input[4]'))
)
# 填写netid和密码
netid_input.send_keys(netid)
pwd_input.send_keys(pwd)
# 二维码识别
# /html/body/div/div[1]/div/div[2]/div[1]/form/div[4]/img
captcha_image = WebDriverWait(driver, 3).until(
EC.presence_of_element_located((By.XPATH, f'/html/body/div/div[1]/div/div[2]/div[1]/form/div[{3+multi_try_mod}]/img'))
)
captcha_image_x, captcha_image_y = captcha_image.location.values()
captcha_image_h, captcha_image_w = captcha_image.size.values()
screenshot = driver.get_screenshot_as_png()
screenshot = Image.open(BytesIO(screenshot))
# MAC系统因为二倍率截图,需要*2,其他系统去掉即可
captcha_image_screenshot = screenshot.crop((captcha_image_x * 2, captcha_image_y * 2, (captcha_image_x + captcha_image_w) * 2, (captcha_image_y + captcha_image_h) * 2))
# 使用百度OCR识别验证码
captcha_buffer = BytesIO()
captcha_image_screenshot.save(captcha_buffer, 'PNG')
captcha_str = captcha_buffer.getvalue()
captcha_buffer.close()
captcha_base64 = base64.b64encode(captcha_str).decode('utf-8')
# req_url = f'https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token={access_token}'
req_url = f'https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token={access_token}'
headers = {'content-type': 'application/x-www-form-urlencoded'}
response = requests.post(req_url, data={"image": captcha_base64}, headers=headers)
captcha_answer = response.json()['words_result'][0]['words']
captcha_input.send_keys(captcha_answer)
login_button_cas.click()
new_domain = driver.current_url.split('//')[1].split('/')[0]
cas_first_try = False
# 3. 课程管理系统
select_course_button = WebDriverWait(driver, 3).until(
EC.presence_of_element_located((By.XPATH, '/html/body/div[2]/section/div/main/div/div[1]/div[1]/div/div/div[2]/div/div/div[1]/a'))
)
select_course_button.click()
# 4. 选课界面
# driver切换到新tab
all_handles = driver.window_handles
new_handle = all_handles[-1]
driver.switch_to.window(new_handle)
round = 1
while True:
print(f'-----------round {round}---------------')
round += 1
# 滚动屏幕
cms_html_height = driver.execute_script('return document.documentElement.scrollHeight')
cms_html_height_next = None
while cms_html_height != cms_html_height_next:
cms_html_height = driver.execute_script('return document.documentElement.scrollHeight')
driver.execute_script(
'document.documentElement.scrollTop = document.documentElement.scrollHeight'
)
time.sleep(1)
cms_html_height_next = driver.execute_script('return document.documentElement.scrollHeight')
# 课程列表
course_ul = WebDriverWait(driver, 3).until(
EC.presence_of_element_located((By.XPATH, '/html/body/div[1]/div/div/div[2]/div/div[1]/div/div[2]/div[3]/div/div/div[2]/div/ul'))
)
course_li_list = course_ul.find_elements(By.TAG_NAME, 'li')
for course_wanted in courses_wanted:
for course_li in course_li_list:
course_title = course_li.find_element(By.XPATH, ".//div[@class='stu-xk-bot-con-title2']/div[1]").text
course_code = course_title.split('-')[0]
# print(course_title)
# print(course_code)
if course_code == course_wanted:
# 遍历到想选的那门课
registration_button = course_li.find_element(By.XPATH, ".//div[@class='stu-xk-bot-r-unfiltrate']/button[@class='ant-btn ant-btn-primary ant-btn-background-ghost']")
course_selected = False
button_text = registration_button.find_element(By.XPATH, './span').text
if button_text == '选 课':
course_selected = False
elif button_text == '退 课':
course_selected = True
else:
raise ValueError(f'course_selected = {course_selected}')
free_count = int(course_li.find_element(By.XPATH, "./div[2]/div[3]/p[2]").text)
print(f'{course_title} 剩余空位:{free_count}')
if free_count > 0 and not course_selected:
registration_button.click()
print(f'{course_title} 已点击')
elif free_count <= 0:
print(f'{course_title} 容量不足')
elif course_selected:
print(f'{course_title} 已选上,无需再选')
# 选数学课
if course_code == "DCS6703":
course_subdir_text = course_li.find_element(By.XPATH, "./div[1]/div[2]/span[3]").text
for subdir in math_courses_wanted:
if subdir in course_subdir_text:
# 选课
registration_button = course_li.find_element(By.XPATH, ".//div[@class='stu-xk-bot-r-unfiltrate']/button[@class='ant-btn ant-btn-primary ant-btn-background-ghost']")
course_selected = False
button_text = registration_button.find_element(By.XPATH, './span').text
if button_text == '选 课':
course_selected = False
elif button_text == '退 课':
course_selected = True
else:
raise ValueError(f'course_selected = {course_selected}')
free_count = int(course_li.find_element(By.XPATH, "./div[2]/div[3]/p[2]").text)
print(f'{course_title} 剩余空位:{free_count}')
if free_count > 0 and not course_selected:
registration_button.click()
print(f'{course_title} 已点击')
elif free_count <= 0:
print(f'{course_title} 容量不足')
elif course_selected:
print(f'{course_title} 已选上,无需再选')
# 刷新屏幕
driver.refresh()
time.sleep(2)
driver.quit()