? 前幾天聽到朋友說自己選課事情,突發(fā)奇想想要搞這樣一個東西,但是由于各種原因只做到以下的完成度,具體的情況也會在解釋的最后留下。這個只適用于曲師大的教務(wù)系統(tǒng),因?yàn)橛玫倪@個系統(tǒng)來進(jìn)行的一個調(diào)試,對于其他的系統(tǒng),思路都是一樣的,代碼也只適用于學(xué)習(xí),請不要用以其他用途!代碼放在最后。
在金湖等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都網(wǎng)站設(shè)計、成都網(wǎng)站制作 網(wǎng)站設(shè)計制作按需定制開發(fā),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),成都營銷網(wǎng)站建設(shè),成都外貿(mào)網(wǎng)站建設(shè),金湖網(wǎng)站建設(shè)費(fèi)用合理。
? 對于想要做到的這個需求呢,我選擇的是python + selenium庫進(jìn)行一個瀏覽器自動化操作,在寫的過程中因?yàn)榘l(fā)現(xiàn)了一個驗(yàn)證碼的問題所以又用到了一個ddddocr庫,如果想要定時操作的話再加上一個time庫。之后就是理清操作的順序就好了,想到于人工操作一遍的過程。
大的一個方向、思路就是上面這四步,具體的細(xì)化之后再談及。
? 這一步就很簡單,直接用selenium庫打開chormedriver就好了
self.driver = webdriver.Chrome()
self.driver.maximize_window() # 最大化
? 這一步就是登錄,要完成的就是把賬號,密碼輸入對應(yīng)的框,然后輸入驗(yàn)證碼,點(diǎn)擊登錄。
? 首先把賬號密碼輸入到框里很簡單
self.driver.find_element(By.ID, 'userAccount').send_keys(self.user_account)
self.driver.find_element(By.ID, 'userPassword').send_keys(self.user_password)
? 直接調(diào)用selenium庫中的函數(shù)就可以進(jìn)行該操作
? 接下來是這一步驟的一個問題,就是如何過驗(yàn)證碼,因?yàn)樵撓到y(tǒng)的驗(yàn)證碼圖片并不復(fù)雜,我想到的一個解決措施就是把驗(yàn)證碼截圖,然后識別圖片上的信息,然后重復(fù)上述操作就好了。
? 如何截圖,我首先想到的是指定位置然后用某個庫截圖或者是打開圖片的鏈接保存圖片,后來發(fā)現(xiàn)每次點(diǎn)開鏈接圖片都是不一樣的(應(yīng)該是JS的原因),最后發(fā)現(xiàn)原來selenium庫自帶一個元素截圖的函數(shù)。
ocr = ddddocr.DdddOcr()
img = self.driver.find_element(By.ID, 'SafeCodeImg') # 定位到驗(yàn)證碼圖片
img.screenshot('code.png') # 給驗(yàn)證碼元素截圖并保存
with open('code.png', 'rb') as f:
img_bytes = f.read() # 讀取圖片編碼
return ocr.classification(img_bytes) # 返回圖片中的驗(yàn)證碼
? 這樣的話只需要定位到這個圖片元素,然后保存下來,再讀取編碼信息,使用ddddocr庫來進(jìn)行一個文字識別,返回圖片的驗(yàn)證碼模擬登陸就好了
? 最后登錄也就是找到元素然后調(diào)用函數(shù)模擬點(diǎn)擊就好了
self.driver.find_element(By.XPATH, "http://*[@class='btn btn-primary login_btn']").click()
? 這一部分本來難度不算很高,但是因?yàn)镴S的原因,有一些地方需要注意。
? 首先就是模擬點(diǎn)擊一些摁扭可以轉(zhuǎn)到選課界面的地方。因?yàn)檫@個選課系統(tǒng)轉(zhuǎn)到一個頁面以后會產(chǎn)生一些新的東西(框架),這時候我們要再找上面的元素就要分清楚在哪一個框架上。
self.driver.switch_to.frame("Frame1") # !!
? 通過F12開發(fā)者選項可以找到這個元素所在的框架不是初始的框架(frame)而是在JS產(chǎn)生的一個新框架中,那么就需要用這個函數(shù)來轉(zhuǎn)到新的框架Frame1(通過開發(fā)者選項找到的frame id)
? 只有這一點(diǎn)需要特別注意?。?!
? 首先一點(diǎn),進(jìn)入這個界面的時候,瀏覽器的界面是切換了的,因此我們也需要將selenium的定位切換到我們所看到的界面上。
new_window = self.driver.window_handles[-1]
self.driver.switch_to.window(new_window)
? 之后通過點(diǎn)擊又轉(zhuǎn)產(chǎn)生了一個新的框架,因此在進(jìn)行一個轉(zhuǎn)框架的操作。
? 最后就是通過課程id、上課老師名字、上課是星期幾三個來作為鍵確定唯一的課程,進(jìn)行一個選擇,并重復(fù)上述操作直到完成全部選課。
for my_course in self.user_course:
self.driver.find_element(By.ID, 'kcxx').send_keys(my_course[1]) # 通過課程信息查找
self.driver.find_element(By.ID, 'skls').send_keys(my_course[2]) # 通過上課老師查找
self.driver.find_element(By.XPATH, f"http://*[@id='skxq']/option[{my_course[3]+1}]").click()
# 選擇星期(一 - 2, 二 - 3, 三 - 4, 四 - 5, 五 - 6)
self.driver.find_element(By.XPATH, "html/body/div[3]/input[6]").click()
self.driver.find_element(By.ID, 'kcxx').clear() # 清空課程查詢框
self.driver.find_element(By.ID, 'skls').clear() # 清空上課老師框
time.sleep(1)
"""
沒刷新出來加一個等待1秒
"""
course_remain = self.driver.find_element(By.XPATH, "http://*[@class='odd']/td[9]").text # 查看課余量
if int(course_remain) > 0:
self.driver.find_element(By.XPATH, "http://*[@class='odd']/td[11]/div/a").click()
"""
這里缺少了一部分確定的代碼
"""
else:
print(f'{my_course[1]}選課失敗')
time.sleep(3) # 3秒的暫停
? 使用time庫來進(jìn)行一個定時開始執(zhí)行
run_time_h = 9 # 定時小時
run_time_m = 0 # 定時分鐘
while True:
current_time = time.localtime(time.time())
print(str(current_time.tm_hour) + '-' + str(current_time.tm_min) + '-' + str(current_time.tm_sec))
if current_time.tm_hour == run_time_h and current_time.tm_min == run_time_m:
break
? 因?yàn)槲冶旧聿皇乔鷰煷蟮男S阉哉f我沒有進(jìn)行一個完全的操作,對系統(tǒng)的認(rèn)識也不是很充分這樣寫出來的代碼當(dāng)然也完成度也不能說是很高的,下面我就大概說一下這個代碼可能產(chǎn)生的問題。
import time
import ddddocr
from selenium import webdriver
from selenium.webdriver.common.by import By
class CClassSelect:
def __init__(self, i_account, i_password, i_course):
self.user_account = i_account
self.user_password = i_password
self.user_course = i_course
self.login_url = 'http://202.194.188.38/'
self.account_url = 'http://202.194.188.38/jsxsd/framework/xsMain.jsp'
self.driver = webdriver.Chrome()
self.driver.maximize_window()
def LoginAccount(self):
self.driver.get(self.login_url)
self.driver.find_element(By.ID, 'userAccount').send_keys(self.user_account)
self.driver.find_element(By.ID, 'userPassword').send_keys(self.user_password)
identify_code = self.Ocr()
self.driver.find_element(By.ID, 'RANDOMCODE').send_keys(identify_code)
self.driver.find_element(By.XPATH, "http://*[@class='btn btn-primary login_btn']").click()
def LoginClassSelect(self):
time.sleep(1)
self.driver.find_element(By.XPATH, "http://*[@id='onesidebar']/div/ul/li[3]/span").click()
self.driver.find_element(By.XPATH, "http://*[@class='sidebar-menu']/li[7]/a").click()
time.sleep(1)
self.driver.find_element(By.XPATH, "http://*[@class='treeview-menu menu-open']/li[1]/a").click()
self.driver.switch_to.frame("Frame1") # !!
"""
iframe問題,卡了一段時間這個地方,可以百度到是不在一個frame的原因
定位不到這個‘進(jìn)入選課’元素,
"""
self.driver.find_element(By.ID, "jrxk").click()
self.driver.find_element(By.XPATH, "http://*[@class='Nsb_pw']/div/center/input[1]").click()
def ClassSelect(self):
new_window = self.driver.window_handles[-1]
self.driver.switch_to.window(new_window)
"""
切換到新的窗口
"""
self.driver.find_element(By.XPATH, "http://*[@id='topmenu']/li[4]/a").click()
self.driver.switch_to.frame("mainFrame") # 換frame
"""
選課代碼 ↓
"""
for my_course in self.user_course:
self.driver.find_element(By.ID, 'kcxx').send_keys(my_course[1]) # 通過課程信息查找
self.driver.find_element(By.ID, 'skls').send_keys(my_course[2]) # 通過上課老師查找
self.driver.find_element(By.XPATH, f"http://*[@id='skxq']/option[{my_course[3]+1}]").click()
# 選擇星期(一 - 2, 二 - 3, 三 - 4, 四 - 5, 五 - 6)
self.driver.find_element(By.XPATH, "html/body/div[3]/input[6]").click()
self.driver.find_element(By.ID, 'kcxx').clear() # 清空課程查詢框
self.driver.find_element(By.ID, 'skls').clear() # 清空上課老師框
time.sleep(1)
"""
沒刷新出來加一個等待1秒
"""
course_remain = self.driver.find_element(By.XPATH, "http://*[@class='odd']/td[9]").text # 查看課余量
if int(course_remain) > 0:
self.driver.find_element(By.XPATH, "http://*[@class='odd']/td[11]/div/a").click()
"""
這里缺少了一部分確定的代碼
"""
else:
print(f'{my_course[1]}選課失敗')
time.sleep(3) # 3秒的暫停
def Ocr(self):
ocr = ddddocr.DdddOcr()
img = self.driver.find_element(By.ID, 'SafeCodeImg') # 定位到驗(yàn)證碼圖片
img.screenshot('code.png') # 給驗(yàn)證碼元素截圖并保存
with open('code.png', 'rb') as f:
img_bytes = f.read() # 讀取圖片編碼
return ocr.classification(img_bytes) # 返回圖片中的驗(yàn)證碼
def Run(self):
self.LoginAccount()
self.LoginClassSelect()
self.ClassSelect()
self.driver.quit()
if __name__ == '__main__':
# 定時運(yùn)行
run_time_h = 9 # 定時小時
run_time_m = 0 # 定時分鐘
while True:
current_time = time.localtime(time.time())
print(str(current_time.tm_hour) + '-' + str(current_time.tm_min) + '-' + str(current_time.tm_sec))
if current_time.tm_hour == run_time_h and current_time.tm_min == run_time_m:
break
# 主程序
input_account = "" # 用戶賬號
input_password = "abcde" # 用戶密碼
input_course = [['', '張三', 3], ['', '李四', 5]] # 要選的課(ID,上課老師,星期)
app = CClassSelect(input_account, input_password, input_course)
app.Run()