成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

用Python實現模擬登錄正方教務系統搶課

開發 后端
最近學校開始選課,但是如果選課時間與自己的事情沖突,這時候就可以使用Python腳本自助搶課,搶課的第一步即是模擬登錄,需要模擬登錄后保存登錄信息然后再進行操作。

最近學校開始選課,但是如果選課時間與自己的事情沖突,這時候就可以使用Python腳本自助搶課,搶課的***步即是模擬登錄,需要模擬登錄后保存登錄信息然后再進行操作。

而且整個流程是比較簡單,這是因為正方教務系統是比較舊的,全文的IP地址部分遮擋,請換成你們學校的IP地址。

嘗試登錄

首先我們打開學校的教務系統,隨便輸入,然后提交表單,打開Chrome的開發者工具中的Network準備抓包

 


把css 圖片之類的過濾掉,發現了default.aspx這個東西

如果你們學校教務系統不使用Cookie則會是這樣

 

我們可以發現,真實的請求地址為http://110.65.10.xxx/(bdq1aj45lpd42o55vqpfgpie)/default2.aspx

隨后我們發現這個網址括號圍起來的一串信息有點詭異,而且每次進入的時候信息都不一樣,經過資料查詢,這是一種ASP.NET不使用Cookie會話管理的技術。

那這樣就很好辦了,我們只需要登錄時記錄下這個數據即可保持登錄狀態。

經過測試發現,我們可以隨便偽造一個會話信息即可一直保持登錄狀態,但是為了體現模擬登錄的科學性,我們需要先獲取該會話信息。

如果你們學校教務系統使用Cookie則會是這樣

 

服務器會返回一個Cookie值,然后在本地保存,這與下面的會不相同。

獲取會話信息(不使用Cookie)

這里我們要使用requests庫,并且要偽造header的UA信息

經過測試發現,我們只訪問學校的IP地址,會自動重定向至有會話信息的網址,所以我們先訪問一下IP地址。

  1. class Spider: 
  2.     def __init__(self, url): 
  3.         self.__uid = '' 
  4.         self.__real_base_url = '' 
  5.         self.__base_url = url 
  6.         self.__headers = { 
  7.             'User-Agent''Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36'
  8.         } 
  9.     def __set_real_url(self): 
  10.         request = requests.get(self.__base_url, headers=self.__headers) 
  11.         real_url = request.url 
  12.         self.__real_base_url = real_url[:len(real_url) - len('default2.aspx')] 
  13.         return request 

上面獲取的url即為帶有會話信息的網址,保存的url格式為http://110.65.10.xxx/(bdq1aj45lpd42o55vqpfgpie)/

保存為這樣的格式是因為我們要訪問其他地址

獲取會話信息(使用Cookie)

有些學校的教務系統是使用Cookie的,我們只需要***get請求時保存Cookie即可,然后此后一直使用該cookie

  1. def get_cookie(): 
  2.     request = requests.get('http://xxx.xxx.xxx.xxx') #以某教務系統為例子 
  3.     cookie = requets.cookie 
  4.     return cookie 

而requests中使用Cookie很簡單

只需要這樣

  1. def use_cookie(cookie): 
  2.     request = requests.get('http://xxx.xxx.xxx.xxx',cookie=cookie) 

由于我們學校采用的是無Cookie方案,所以下面的代碼均沒有發送Cookie,如果你的學校采用了Cookie,只需要像我上面這樣發送Cookie就行了。

而如果你們學校使用Cookie,就不必獲取帶有會話信息的地址了,直接存儲Cookie即可。

驗證碼的處理

分析r返回的文本信息

發現驗證碼的標簽的資源地址為 src=”CheckCode.aspx” ,我們可以直接requests然后下載驗證碼圖片,下載圖片的一種優雅的方式如下

  1. def __get_code(self): 
  2.     request = requests.get(self.__real_base_url + 'CheckCode.aspx', headers=self.__headers) 
  3.     with open('code.jpg''wb')as f: 
  4.         f.write(request.content) 
  5.     im = Image.open('code.jpg'
  6.     im.show() 
  7.     print('Please input the code:'
  8.     code = input() 
  9.     return code 

上面的代碼把圖片保存為code.jpg,Python有一個Image模塊,可以實現自動打開圖片

這樣驗證碼就展示出來了,我們人工輸入或者轉入打碼平臺皆可

登錄數據的構造

這是上面抓的登錄post的數據包,

 

發現有信息無法被解碼,應該是gb2312編碼,查看解碼前的編碼

 

然后將不能解碼的代碼復制能夠解碼的地方

發現%D1%A7%C9%FA編碼解碼后為學生

這也就對應了學生選項的登錄

學號和密碼和驗證碼能夠顯而易見地知道是哪些信息,但是我們發現有__VIEWSTATE這一項

查找一下,這是一個表單隱藏信息,我們可以用BeautifulSoup庫解析可以得出該一項數據的值

 

這是完整的登錄數據包,

  1. def __get_login_data(self, uid, password): 
  2.     self.__uid = uid 
  3.     request = self.__set_real_url() 
  4.     soup = BeautifulSoup(request.text, 'lxml'
  5.     form_tag = soup.find('input'
  6.     __VIEWSTATE = form_tag['value'
  7.     code = self.__get_code() 
  8.     data = { 
  9.         '__VIEWSTATE': __VIEWSTATE, 
  10.         'txtUserName': self.__uid, 
  11.         'TextBox2'password
  12.         'txtSecretCode': code, 
  13.         'RadioButtonList1''學生'.encode('gb2312'), 
  14.         'Button1'''
  15.         'lbLanguage'''
  16.         'hidPdrs'''
  17.         'hidsc'''
  18.     } 
  19.     return data 

登錄

如果登錄完成了,如何判斷是否登錄成功呢?我們從登錄成功返回的界面發現有姓名這一標簽,而我們等一下也是需要學生姓名,所以我們用這個根據來判斷是否登錄成功。

 

代碼如下,進行了驗證碼用戶名和密碼的提示信息判別

  1. def login(self,uid,password): 
  2.     while True
  3.         data = self.__get_login_data(uid, password
  4.         request = requests.post(self.__real_base_url + 'default2.aspx', headers=self.__headers, data=data) 
  5.         soup = BeautifulSoup(request.text, 'lxml'
  6.         try: 
  7.             name_tag = soup.find(id='xhxm'
  8.             self.__name = name_tag.string[:len(name_tag.string) - 2] 
  9.             print('歡迎'+self.__name) 
  10.         except
  11.             print('Unknown Error,try to login again.'
  12.             time.sleep(0.5) 
  13.             continue 
  14.         finally: 
  15.             return True 

獲取選課信息

接下來就是獲取選課信息了,這里我們以校公選課為例子,點擊進去,進行抓包,headers沒有什么好注意的,我們只用關注get發送的包即可

 

 

發現有學號與姓名與gnmkdm這一項,姓名我們需要編碼為gb2312的形式才能進行傳送

這里我們注意headers需要新增Referer項也就是當前訪問的網址,才能進行請求

  1. def __enter_lessons_first(self): 
  2.     data = { 
  3.         'xh': self.__uid, 
  4.         'xm': self.__name.encode('gb2312'), 
  5.         'gnmkdm''N121103'
  6.     } 
  7.     self.__headers['Referer'] = self.__real_base_url + 'xs_main.aspx?xh=' + self.__uid 
  8.     request = requests.get(self.__real_base_url + 'xf_xsqxxxk.aspx', params=data, headers=self.__headers) 
  9.     self.__headers['Referer'] = request.url 
  10.     soup = BeautifulSoup(request.text, 'lxml'
  11.     self.__set__VIEWSTATE(soup) 

注意到上面有一個設置VIEWSTATE值的函數,這里等下在選課構造數據包的時候會講

模擬選課

隨便選一門課,然后提交,抓包,看一下有什么數據發送

 

前三個值可以在原網頁中input標簽中找到,由于前兩項為空,就不獲取了,而第三項我們使用soup解析獲取即可,由于這個操作是每請求一次就變化的,我們寫成一個函數,每次請求完成就設置一次。

 


  1. def __set__VIEWSTATE(self, soup): 
  2.     __VIEWSTATE_tag = soup.find('input', attrs={'name''__VIEWSTATE'}) 
  3.     self.__base_data['__VIEWSTATE'] = __VIEWSTATE_tag['value'

而其他數據,我們通過搜索響應網頁就可以知道他們是干什么用的,這里我只說明我們要用的數據。

TextBox1為搜索框數據,我們可以用這個來搜索課程,dpkcmcGrid:txtPageSize為一頁顯示多少數據,經過測試,服務器最多響應200條。

值得注意的是ddl_xqbs這個校區數據信息,我所在的校區的數字代號為2,也許不同學校設置有所不同,需要自己設置一下,也可以從網頁中獲取

下面是基礎數據包,由于我們搜索課程與選擇課程都要使用這個基礎數據包,所以我們直接在init函數里面新增

  1. self.__base_data = { 
  2.     '__EVENTTARGET'''
  3.     '__EVENTARGUMENT'''
  4.     '__VIEWSTATE'''
  5.     'ddl_kcxz'''
  6.     'ddl_ywyl'''
  7.     'ddl_kcgs'''
  8.     'ddl_xqbs''2'
  9.     'ddl_sksj'''
  10.     'TextBox1'''
  11.     'dpkcmcGrid:txtChoosePage''1'
  12.     'dpkcmcGrid:txtPageSize''200'

然后我們關注一下這條數據,我們搜索一下,發現這是課程的提交選課的代碼,所以我們也可以直接從網頁中獲取,而on表示選項被選上

 

  1. kcmcGrid:_ctl2:xk:'on' 

搜索課程

課程有很多信息,比如名字,上課時間,地點,這些東西確定好了才知道選的是哪門課,所以我們先新建一個類來存儲信息

  1. class Lesson: 
  2.     def __init__(self, name, code, teacher_name, Time, number): 
  3.         self.name = name 
  4.         self.code = code 
  5.         self.teacher_name = teacher_name 
  6.         self.time = Time 
  7.         self.number = number 
  8.     def show(self): 
  9.         print('name:' + self.name + 'code:' + self.code + 'teacher_name:' + self.teacher_name + 'time:' + self.time

有了這個類,我們就可以進行搜索課程了,具體代碼看下面代碼,解析網頁內容就不細講了。

  1. def __search_lessons(self, lesson_name=''): 
  2.     self.__base_data['TextBox1'] = lesson_name.encode('gb2312'
  3.     request = requests.post(self.__headers['Referer'], data=self.__base_data, headers=self.__headers) 
  4.     soup = BeautifulSoup(request.text, 'lxml'
  5.     self.__set__VIEWSTATE(soup) 
  6.     return self.__get_lessons(soup) 
  7. def __get_lessons(self, soup): 
  8.     lesson_list = [] 
  9.     lessons_tag = soup.find('table', id='kcmcGrid'
  10.     lesson_tag_list = lessons_tag.find_all('tr')[1:] 
  11.     for lesson_tag in lesson_tag_list: 
  12.         td_list = lesson_tag.find_all('td'
  13.         code = td_list[0].input['name'
  14.         name = td_list[1].string 
  15.         teacher_name = td_list[3].string 
  16.         Time = td_list[4]['title'
  17.         number = td_list[10].string 
  18.         lesson = self.Lesson(name, code, teacher_name, Time, number) 
  19.         lesson_list.append(lesson) 
  20.     return lesson_list 

進行選課

選課我們只要將lesson_list傳入即可,這就是我們之前創建的Lesson類的實例的列表,’Button’的內容為’ 提交 ‘,這兩邊各有一個空格,完事后我們可以進行發送請求進行選課。

這里我們用正則提取了錯誤信息,比如選課時間未到、上課時間沖突這些錯誤信息來提示用戶,我們還解析了網頁的已選課程,這里也不細講了,都是基礎的網頁解析。

  1. def __select_lesson(self, lesson_list): 
  2.     data = copy.deepcopy(self.__base_data) 
  3.     data['Button1'] = '  提交  '.encode('gb2312'
  4.     for lesson in lesson_list: 
  5.         code = lesson.code 
  6.         data[code] = 'on' 
  7.     request = requests.post(self.__headers['Referer'], data=data, headers=self.__headers) 
  8.     soup = BeautifulSoup(request.text, 'lxml'
  9.     self.__set__VIEWSTATE(soup) 
  10.     error_tag = soup.html.head.script 
  11.     if not error_tag is None: 
  12.         error_tag_text = error_tag.string 
  13.         r = "alert\('(.+?)'\);" 
  14.         for s in re.findall(r, error_tag_text): 
  15.             print(s) 
  16.     print('已選課程:'
  17.     selected_lessons_pre_tag = soup.find('legend', text='已選課程'
  18.     selected_lessons_tag = selected_lessons_pre_tag.next_sibling 
  19.     tr_list = selected_lessons_tag.find_all('tr')[1:] 
  20.     for tr in tr_list: 
  21.         td = tr.find('td'
  22.         print(td.string) 

總結

這次我們完成了模擬正方教務系統選課的過程,由于這個教務系統技術比較陳舊,所以比較好弄,事實上搶課的時候用Fiddler即可完成操作,因為我們只需要提前登錄然后記錄網址即可。

本文代碼Github地址:https://github.com/vhyz/ZF_Spider

責任編輯:未麗燕 來源: whyz's Blog
相關推薦

2024-01-12 18:26:44

2023-03-09 08:12:08

免登錄實Python腳本

2021-08-02 12:29:15

Python爬蟲網站

2020-08-19 17:14:26

Python數據函數

2018-01-02 09:56:04

Python12306火車票

2012-08-21 11:26:17

Winform

2020-02-11 16:10:44

Redis分布式鎖Java

2025-04-02 07:22:19

2021-01-06 10:09:05

Spring Boothttps sslhttps

2023-07-02 14:05:13

2020-02-24 10:29:24

數據庫系統肺炎

2021-05-25 10:05:39

Python模擬導彈代碼

2016-09-12 14:05:27

PythonPython解釋器Web

2025-05-19 07:39:45

2022-02-25 14:04:56

TS前端代碼

2024-06-19 10:48:31

ChatGPTGPT項目

2020-12-18 08:55:20

Python火車票代碼

2015-06-30 15:14:54

2021-07-26 07:47:37

前端自動搶票

2019-01-09 09:35:41

搶票Python軟件
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人精品视频免费 | 鲁视频| 色站综合 | 亚洲一在线 | 中文字幕日韩一区 | 国产精品视频免费看 | 青青草社区 | 九九色综合| 久久九| 丁香久久 | 日韩一区二区三区精品 | 精品免费在线 | 欧美 日韩 视频 | 国产伊人久久久 | 亚洲一一在线 | 99热热精品 | 国产日韩免费视频 | 99精品久久99久久久久 | 日韩视频在线免费观看 | 成年人的视频免费观看 | 国产精品美女www | 九九热在线免费观看 | 狠狠干影院| 久久曰视频 | 亚洲激情在线视频 | 日韩精品四区 | 久久综合一区 | a级大片 | 免费一级做a爰片久久毛片潮喷 | 欧美高清视频一区 | 精品国产乱码久久久 | 成人性视频在线播放 | 国产精品国产成人国产三级 | 天天视频成人 | 中文字字幕一区二区三区四区五区 | 尤物在线精品视频 | 成av在线 | 久久夜视频| 久久精品久久久 | 91久久国产| 色偷偷噜噜噜亚洲男人 |