├── init.conf ├── README.md └── CC.py /init.conf: -------------------------------------------------------------------------------- 1 | [token] 2 | # 1为本方案课程 2为其他方案课程 3 | type =1 4 | # 1为搜索 0为不搜索 5 | type2 =1 6 | # 学号(非int报错) 7 | user_id_str =19289999 8 | # 密码 9 | password_str =XXXXXXXX 10 | xpath_str = 11 | delta =0.9 12 | course_number =A121006B 13 | 14 | [ttpicture] 15 | # 图鉴部分 16 | uname=***** 17 | pwd=****** -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BJTU抢课脚本 2 | 3 | [项目地址](https://github.com/aosiweixin/BJTU-CC)||[博客地址](http://www.auswitz.top/2021/11/27/BJTU%E9%80%89%E8%AF%BE%E5%86%B2%E5%86%B2%E5%86%B2/)||[col](https://github.com/MrP25) 4 | 5 | ## 依赖 6 | 7 | 主要单独需要下载一个selenium用于模拟浏览器,安装起来稍微有一点麻烦,要注意对应版本,网上搜教程就好啦~~ 8 | 9 | 10 | 11 | chromedriver的[下载地址](https://npm.taobao.org/mirrors/chromedriver/),下载的版本一定要一一对应~ 12 | 13 | 推荐直接使用[**release1.0**](https://github.com/aosiweixin/BJTU-CC/releases/tag/fin) 14 | 15 | 推荐直接使用[**release1.0**](https://github.com/aosiweixin/BJTU-CC/releases/tag/fin) 16 | 17 | 推荐直接使用[**release1.0**](https://github.com/aosiweixin/BJTU-CC/releases/tag/fin) 18 | 19 | 直接修改init.conf文件和替换对应版本的chromedriver即可~~~ 20 | 21 | 22 | 23 | ```python 24 | from selenium import webdriver 25 | from selenium.webdriver.chrome.options import Options 26 | from selenium.webdriver.support.ui import WebDriverWait 27 | from selenium.common.exceptions import TimeoutException 28 | import time 29 | from PIL import Image 30 | import base64 31 | import json 32 | import requests 33 | ``` 34 | 35 | ## 使用 36 | 37 | 第一部分需要修改这些参数 38 | 39 | ``` 40 | type = 1 # 1为本方案课程 2为其他方案课程 41 | type2 = 1 # 1为搜索 0为不搜索 42 | user_id_str = '1928****' # 学号 43 | password_str = '********' # 密码 44 | xpath_str = '' 45 | delta = 0.9 46 | course_number = 'A121006B' 47 | ``` 48 | 49 | 自动读取验证码需要使用[图鉴](http://www.ttshitu.com/)的api 50 | 51 | 进入图鉴之后,注册账号 52 | 53 | [![](https://pic.imgdb.cn/item/61a2456d2ab3f51d9138e3dd.jpg)](https://pic.imgdb.cn/item/61a2456d2ab3f51d9138e3dd.jpg) 54 | 55 | 非常便宜,充值1元可以用四年。 56 | 57 | [图鉴使用文档](http://www.ttshitu.com/docs/python.html#pageTitle) 58 | 59 | ```python 60 | import base64 61 | import json 62 | import requests 63 | # 一、图片文字类型(默认 3 数英混合): 64 | # 1 : 纯数字 65 | # 1001:纯数字2 66 | # 2 : 纯英文 67 | # 1002:纯英文2 68 | # 3 : 数英混合 69 | # 1003:数英混合2 70 | # 4 : 闪动GIF 71 | # 7 : 无感学习(独家) 72 | # 11 : 计算题 73 | # 1005: 快速计算题 74 | # 16 : 汉字 75 | # 32 : 通用文字识别(证件、单据) 76 | # 66: 问答题 77 | # 49 :recaptcha图片识别 78 | # 二、图片旋转角度类型: 79 | # 29 : 旋转类型 80 | # 81 | # 三、图片坐标点选类型: 82 | # 19 : 1个坐标 83 | # 20 : 3个坐标 84 | # 21 : 3 ~ 5个坐标 85 | # 22 : 5 ~ 8个坐标 86 | # 27 : 1 ~ 4个坐标 87 | # 48 : 轨迹类型 88 | # 89 | # 四、缺口识别 90 | # 18 : 缺口识别(需要2张图 一张目标图一张缺口图) 91 | # 33 : 单缺口识别(返回X轴坐标 只需要1张图) 92 | # 五、拼图识别 93 | # 53:拼图识别 94 | def base64_api(uname, pwd, img, typeid): 95 | with open(img, 'rb') as f: 96 | base64_data = base64.b64encode(f.read()) 97 | b64 = base64_data.decode() 98 | data = {"username": uname, "password": pwd, "typeid": typeid, "image": b64} 99 | result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text) 100 | if result['success']: 101 | return result["data"]["result"] 102 | else: 103 | return result["message"] 104 | return "" 105 | 106 | 107 | if __name__ == "__main__": 108 | img_path = "C:/Users/Administrator/Desktop/file.jpg" 109 | result = base64_api(uname='你的账号', pwd='你的密码', img=img_path, typeid=3) 110 | print(result) 111 | ``` 112 | 113 | 也可以选择不使用自动识别(自动识别稍微有一点慢,需要看运气) 114 | 115 | 如果可以抽空盯着,看到验证码弹出来手输也还可以。 116 | 117 | 但最近选课平台没开就没法贴使用截图了,但在上学期期末,已经测试好了,可用! 118 | 119 | -------------------------------------------------------------------------------- /CC.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | from selenium.webdriver.chrome.options import Options 3 | from selenium.webdriver.support.ui import WebDriverWait 4 | from selenium.common.exceptions import TimeoutException 5 | import time 6 | from PIL import Image 7 | import base64 8 | import json 9 | import requests 10 | from configparser import ConfigParser 11 | 12 | 13 | chrome_options = Options() 14 | chrome_options.add_argument('--headless') 15 | driver = webdriver.Chrome(chrome_options=chrome_options) 16 | driver = webdriver.Chrome() 17 | conf = ConfigParser() 18 | conf.read("init.conf", encoding="utf8") 19 | # client = pymongo.MongoClient('localhost',27017) 20 | # mis = client['mis'] 21 | # schedule = mis['schedule'] 22 | 23 | wait = WebDriverWait(driver, 10) 24 | url = 'https://mis.bjtu.edu.cn/home/' 25 | URL = 'http://jwc.bjtu.edu.cn' 26 | 27 | 28 | type = conf.getint("token", "type") # 1为本方案课程 2为其他方案课程 29 | type2 = conf.getint("token", "type2") # 1为搜索 0为不搜索 30 | user_id_str = conf.getint("token", "user_id_str") # 学号 31 | password_str = conf.get("token", "password_str") # 密码 32 | xpath_str = conf.get("token", "xpath_str") 33 | delta = conf.getfloat("token", "delta") 34 | course_number = conf.get("token", "course_number") 35 | # course_number = 'A101020B' 36 | 37 | 38 | def search(): 39 | try: 40 | # 进入mis 41 | driver.get('https://mis.bjtu.edu.cn/home/') 42 | time.sleep(delta) 43 | name = driver.find_element_by_xpath('//*[@id="id_loginname"]') 44 | password = driver.find_element_by_xpath('//*[@id="id_password"]') 45 | submit = driver.find_element_by_xpath( 46 | '//*[@id="login"]/dl/dd[2]/div/div[3]/button') 47 | name.send_keys(user_id_str) 48 | password.send_keys(password_str) 49 | submit.click() 50 | # 进入教务系统 51 | time.sleep(delta) 52 | driver.get('https://mis.bjtu.edu.cn/module/module/10') 53 | time.sleep(delta) 54 | step1 = driver.find_element_by_xpath( 55 | '/html/body/div[2]/div[1]/div/div[1]/ul/li[4]/a') 56 | step1.click() 57 | step2 = driver.find_element_by_xpath( 58 | '/html/body/div[2]/div[2]/div/div[1]/div[1]/div[1]/div/ul/li[2]/ul/li[1]/a' 59 | ) 60 | step2.click() 61 | time.sleep(delta) 62 | # 上面的是通用步骤 到达“网上选课”一栏 63 | if type == 1: 64 | # 本方案 65 | this_program() 66 | elif type == 2: 67 | # 其他方案 68 | other_program() 69 | XuanKe(type) 70 | 71 | except: 72 | # 进入教务系统 73 | time.sleep(delta) 74 | driver.get('https://mis.bjtu.edu.cn/module/module/10') 75 | time.sleep(delta) 76 | step1 = driver.find_element_by_xpath( 77 | '/html/body/div[2]/div[1]/div/div[1]/ul/li[4]/a') 78 | step1.click() 79 | step2 = driver.find_element_by_xpath( 80 | '/html/body/div[2]/div[2]/div/div[1]/div[1]/div[1]/div/ul/li[2]/ul/li[1]/a' 81 | ) 82 | step2.click() 83 | time.sleep(delta) 84 | # 上面的是通用步骤 到达“网上选课”一栏 85 | if type == 1: 86 | # 本方案 87 | this_program() 88 | elif type == 2: 89 | # 其他方案 90 | other_program() 91 | XuanKe(type) 92 | 93 | 94 | def alert(type): 95 | driver.switch_to.default_content() 96 | 97 | driver.find_element_by_xpath( 98 | '/html/body/div[4]/div/div/div[3]/button[1]').click() 99 | if type == 1: 100 | # 本方案 101 | driver.switch_to.frame( 102 | driver.find_element_by_xpath( 103 | '/html/body/div[2]/div[2]/div/div[2]/div[5]/div[1]/iframe')) 104 | else: 105 | # 其他方案 106 | driver.switch_to.frame( 107 | driver.find_element_by_xpath( 108 | '/html/body/div[2]/div[2]/div/div[2]/div[5]/div[2]/iframe')) 109 | 110 | 111 | def duoXuan(i): 112 | if i == 1: 113 | driver.find_element_by_xpath( 114 | '//*[@id="container"]/table/tbody/tr[3]/td[1]/input').click() 115 | alert(type) 116 | if i == 2: 117 | driver.find_element_by_xpath( 118 | '//*[@id="container"]/table/tbody/tr[4]/td[1]/input').click() 119 | elif i == 3: 120 | driver.find_element_by_xpath( 121 | '//*[@id="container"]/table/tbody/tr[5]/td[1]/input').click() 122 | elif i == 4: 123 | driver.find_element_by_xpath( 124 | '//*[@id="container"]/table/tbody/tr[6]/td[1]/input').click() 125 | elif i == 5: 126 | driver.find_element_by_xpath( 127 | '//*[@id="container"]/table/tbody/tr[2]/td[1]/input').click() 128 | elif i == 6: 129 | driver.find_element_by_xpath( 130 | '//*[@id="container"]/table/tbody/tr[7]/td[1]/input').click() 131 | elif i == 7: 132 | driver.find_element_by_xpath( 133 | '//*[@id="container"]/table/tbody/tr[8]/td[1]/input').click() 134 | else: 135 | driver.find_element_by_xpath( 136 | '//*[@id="current"]/table/tbody/tr[9]/td[1]/label').click() 137 | return True 138 | 139 | 140 | def XuanKe(type): 141 | tag = 1 142 | i = 1 143 | count = 1 144 | while tag: 145 | try: 146 | driver.find_element_by_xpath( 147 | '//*[@id="container"]/table/tbody/tr[2]/td[1]/input').click() 148 | alert(type) 149 | # duoXuan(i) 150 | tag = 0 151 | except Exception as e: 152 | count = count + 1 153 | if count == 600: 154 | main() 155 | print(count) 156 | time.sleep(delta) 157 | 158 | if type2 == 1: 159 | driver.find_element_by_xpath('/html/body/form/button').click() 160 | else: 161 | driver.refresh() 162 | if type == 1: 163 | # 本方案 164 | driver.switch_to.frame( 165 | driver.find_element_by_xpath( 166 | '/html/body/div[2]/div[2]/div/div[2]/div[5]/div[1]/iframe' 167 | )) 168 | else: 169 | # 其他方案 170 | driver.switch_to.frame( 171 | driver.find_element_by_xpath( 172 | '/html/body/div[2]/div[2]/div/div[2]/div[5]/div[2]/iframe' 173 | )) 174 | time.sleep(delta) 175 | flag = False 176 | try_cnt = 1 177 | ''' 178 | while not flag: 179 | try: 180 | flag = duoXuan(i) 181 | except Exception as e: 182 | print(i) 183 | print(e) 184 | if i == 3: 185 | i = 0 186 | i += 1 187 | driver.refresh() 188 | try_cnt += 1 189 | time.sleep(delta) 190 | ''' 191 | # 弹窗提交按钮 192 | 193 | # //*[@id="container"]/table/tbody/tr[4]/td[9]/div[1] 194 | driver.find_element_by_xpath('//*[@id="select-submit-btn"]').click() 195 | time.sleep(delta) 196 | 197 | 198 | def other_program(): 199 | step3 = driver.find_element_by_xpath( 200 | '/html/body/div[2]/div[2]/div/div[2]/div[4]/label[2]') 201 | step3.click() 202 | driver.switch_to.frame( 203 | driver.find_element_by_xpath( 204 | '/html/body/div[2]/div[2]/div/div[2]/div[5]/div[2]/iframe')) 205 | 206 | if type2 == 1: 207 | course = driver.find_element_by_xpath( 208 | '/html/body/form/input[1]').send_keys(course_number) 209 | submit_course = driver.find_element_by_xpath('/html/body/form/button') 210 | try: 211 | course.send_keys(course_number) 212 | except Exception as e: 213 | submit_course.click() 214 | # //*[@id="thepage"]//*[@id="page_go"] 215 | time.sleep(2) 216 | submit_page = driver.find_element_by_xpath('//*[@id="page_go"]') 217 | submit_page.click() 218 | 219 | 220 | def this_program(): 221 | driver.switch_to.frame( 222 | driver.find_element_by_xpath( 223 | '/html/body/div[2]/div[2]/div/div[2]/div[5]/div[1]/iframe')) 224 | if type2 == 1: 225 | course = driver.find_element_by_xpath( 226 | '/html/body/form/input[1]').send_keys(course_number) 227 | submit_course = driver.find_element_by_xpath('/html/body/form/button') 228 | try: 229 | course.send_keys(course_number) 230 | except Exception as e: 231 | submit_course.click() 232 | # //*[@id="thepage"]//*[@id="page_go"] 233 | time.sleep(2) 234 | submit_page = driver.find_element_by_xpath('//*[@id="page_go"]') 235 | submit_page.click() 236 | # driver.find_element_by_xpath('//*[@id="container"]/table/tbody/tr[2]/td[1]/input').click() 237 | 238 | 239 | def base64_api(uname, pwd, img, typeid): 240 | with open(img, 'rb') as f: 241 | base64_data = base64.b64encode(f.read()) 242 | b64 = base64_data.decode() 243 | data = {"username": uname, "password": pwd, "typeid": typeid, "image": b64} 244 | result = json.loads( 245 | requests.post("http://api.ttshitu.com/predict", json=data).text) 246 | if result['success']: 247 | return result["data"]["result"] 248 | else: 249 | return result["message"] 250 | return "" 251 | 252 | 253 | def screenshot(): 254 | driver.save_screenshot('full_baidu.png') 255 | left = 500 256 | top = 145 257 | right = left + 214 258 | bottom = top + 62 259 | photo = Image.open('full_baidu.png') 260 | photo = photo.crop((left, top, right, bottom)) 261 | photo.save('full_baidu.png') 262 | 263 | 264 | def verification_code_submit(result): 265 | driver.switch_to.default_content() 266 | verification_code = driver.find_element_by_xpath( 267 | '/html/body/div[4]/div/div/div[2]/div/div/input[2]') 268 | verification_code.send_keys(result) 269 | submit = driver.find_element_by_xpath( 270 | '/html/body/div[4]/div/div/div[3]/button[1]') 271 | submit.click() 272 | if type2 == 1: 273 | driver.find_element_by_xpath('/html/body/form/button') 274 | else: 275 | if type == 1: 276 | # 本方案 277 | driver.switch_to.frame( 278 | driver.find_element_by_xpath( 279 | '/html/body/div[2]/div[2]/div/div[2]/div[5]/div[1]/iframe') 280 | ) 281 | else: 282 | # 其他方案 283 | driver.switch_to.frame( 284 | driver.find_element_by_xpath( 285 | '/html/body/div[2]/div[2]/div/div[2]/div[5]/div[2]/iframe') 286 | ) 287 | 288 | 289 | def main(): 290 | 291 | search() 292 | # get_img() 293 | 294 | screenshot() 295 | 296 | img_path = "full_baidu.png" 297 | # 用的是图鉴的api去解验证码 298 | result = base64_api(uname=conf.get("ttpicture", "uname"), pwd=conf.get("ttpicture", "pwd"), 299 | img=img_path, typeid=16) 300 | verification_code_submit(result) 301 | 302 | # print(result) 303 | 304 | XuanKe(type) 305 | 306 | 307 | if __name__ == '__main__': 308 | main() 309 | --------------------------------------------------------------------------------