如何爬取asp.net動態網頁?搞定可惡的動態參數,這一文告訴你!

這個asp網站是個人學校的電費查詢系統,須要學校的內網才能查詢,因此這文說下思路和我遇到的一些坑。我搞這個網站主要是爲了方便查電費而已,其實也方便不了多少。並且這個asp網站還不是很容易爬,由於裏面有兩個可變的參數,會根據頁面來變化。好了,先看看頁面html

這個網站須要先登錄進本身的宿舍才能進去,還有很爛的驗證碼,不過我實現到驗證碼寫入的時候發現這個驗證碼是能夠隨便填的,這個就感受有點垃圾。python

這個登錄頁面有不少坑,下面說下git

1.github

上面右邊所指的就是兩個動態變化的參數,怎麼來的呢?是根據上一個頁面來的,每一個頁面都會帶有這兩個參數,因此咱們須要每次訪問一次都須要匹配下這兩個值就行動態更換,若是不跟換的話,會得不到數據,還會出現下面這個錯誤。ajax

'236|error|500|回發或回調參數無效。在配置中使用 <pages enableEventValidation="true"/> 或在頁面中使用 <%@ Page EnableEventValidation="true" %> 啓用了事件驗證。出於安全目的,此功能驗證回發或回調事件的參數是否來源於最初呈現這些事件的服務器控件。若是數據有效而且是預期的,則使用 ClientScriptManager.RegisterForEventValidation 方法來註冊回發或回調數據以進行驗證。|'

這個就說明你沒有更換好上面所說的兩個參數安全

注意:第一次訪問這個網站是不會有宿舍樓層宿舍號這些數據的,須要進行匹配上面的兩個可變參數再進行post纔會有數據。服務器

2.app

在你選好你的宿舍樓層號以後表單數據就會出現變化ide

能夠看到表單的參數順序和上面的不同了,因此在選好宿舍樓層以後咱們須要把變單順序改變後再把參數post出去,要不還會出現上面那個坑,就是回調參數無效post

第一個箭頭所指的參數也須要改變,不過第二個參數是txtname2,也就是每層樓的默認宿舍值,這個固定也沒事,不會出錯,時間的話仍是須要根據本身訪問時間來進行變化的,要不也會出現錯誤,仍是一樣的錯誤,也就是下面的這個錯誤,可想而知asp網站對這些參數是有很挑剔的要求。

236|error|500|回發或回調參數無效。在配置中使用 <pages enableEventValidation="true"/> 或在頁面中使用 <%@ Page EnableEventValidation="true" %> 啓用了事件驗證。出於安全目的,此功能驗證回發或回調事件的參數是否來源於最初呈現這些事件的服務器控件。若是數據有效而且是預期的,則使用 ClientScriptManager.RegisterForEventValidation 方法來註冊回發或回調數據以進行驗證。|

3.

這個電費查詢按鈕,不是ajax,會有新的請求,並且是對同一個網址的不一樣請求方式,第一次請求時get請求,用於獲取asp網頁的那兩個動態參數,第二次是將動態參數就行post發送出去,這樣就會有數據了,若是你是第一次就post的話,會沒有數據,網頁仍是會報錯誤,一樣仍是那個錯誤哈。下面是表單數據

self.data = {
           '__EVENTTARGET''RegionPanel2$Region1$Toolbar1$ContentPanel1$btnSelect',
           '__EVENTARGUMENT''',
           '__VIEWSTATE'self.data['__VIEWSTATE'],
           '__EVENTVALIDATION'self.data['__EVENTVALIDATION'],
           'hidJZ''jz'+name,
           'RegionPanel2$Region1$Toolbar1$ContentPanel1$TextBox1': (datetime.now()-timedelta(days=30)).strftime('%Y-%m-%d'),
           'RegionPanel2$Region1$Toolbar1$ContentPanel1$TextBox2': datetime.now().strftime('%Y-%m-%d'),
           'RegionPanel2$Region1$Toolbar1$ContentPanel1$txtDBBH''',
           'RegionPanel2$Region1$Toolbar1$ContentPanel1$ddlCZFS''----所有----',
           'RegionPanel2$Region1$toolbarButtom$pagesize''1',
           '__box_page_state_changed''false',
           '__2_collapsed''false',
           '__6_selectedRows''',
           '__box_disabled_control_before_postbac''__10',
           '__box_ajax_mark''true'
       }複製代碼


坑說完了,說說部分代碼的做用吧

def __get_value(self, html):  # 獲取表單的兩個參數__VIEWSTATE和__EVENTVALIDATION
       try:
           soup = BeautifulSoup(html, 'lxml')
           value = soup.select('input[type="hidden"]')
           values = [v for v in value if '/w' in str(v)]
           state = values[0]['value']
           action = values[1]['value']
           self.data['__VIEWSTATE'] = state
           self.data['__EVENTVALIDATION'] = action
       except IndexError as e:  # 證實這個不是首頁,須要另外的規則
           match = re.search('__VIEWSTATE\|(.*?)\|.*?__EVENTVALIDATION\|(.*?)\|', html)
           self.data['__VIEWSTATE'] = match.group(1)
           self.data['__EVENTVALIDATION'] = match.group(2)
       except Exception as e:
           print('get_value', e)複製代碼

這個就是獲取兩個動態參數的方法,每次根據html元素來獲取

def __get_name(self, jz, html=None):  # 輸入宿舍號
       if html:
           # 表單順序須要改變
           self.data = {
               'ScriptManager1''UpdatePanel1|txtjz2',
               'hidtime': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
               'Radio1''1',
               'txtjz2': jz,
               'txtname2''001001001001001',  # 這個初始化值能夠隨意,但不能爲空
               'txtpwd2''',
               'txtyzm2''',
               '__EVENTTARGET''txtjz2',
               '__EVENTARGUMENT''',
               '__LASTFOCUS''',
               '__VIEWSTATE''',
               '__EVENTVALIDATION''',
               '__ASYNCPOST''true'
           }
           self.__get_value(html)  # 換下參數
           html = self.__get_html()
           if html:
               soup = BeautifulSoup(html, 'lxml')
               dormitory_num = soup.select('select[name="txtname2"] option')
               dormitory_num = [(p.text, p['value']) for p in dormitory_num]
               for index, p in enumerate(dormitory_num):
                   print(index, '宿舍號:', p[0])
               self.__get_value(html)
       while True:
           num = input('請輸入你的宿舍,輸入左邊的編號便可')
           num = re.match('\d+', num)
           if num and int(num.group()) < len(dormitory_num):
               num = int(num.group())
               break
           print('請輸入正確的宿舍編號')
       return dormitory_num[num][1]複製代碼

這個是獲取宿舍號,表單順序須要改變

def __get_chapter(self):
       # 獲取驗證碼
       url = 'http://172.18.2.42:8000/ValidateCode.aspx'
       response = requests.get(url, headers=self.headers)
       with open('code.jpg''wb'as f:
           f.write(response.content)
       image = Image.open('code.jpg')
       image.show()
       code = input('請輸入驗證碼')
       return code複製代碼

這個是獲取驗證碼的方法,獲取驗證碼是很簡單的,就是找到請求的url進行請求就能夠了。至於識別,我這裏是手動輸入,你也能夠選擇接入打碼平臺或者用深度學習模型來識別。

其餘的就很少說了。

須要源碼的能夠在個人GitHub上找:https://github.com/SergioJune/gongzhonghao_code/blob/master/python_play/query.py

寫在最後

若是這篇文章對你用的話,但願不要吝嗇你的點贊哈!點贊和轉發就是對個人最大支持,這樣纔有動力輸出質量高的原創文章。

「點贊是一種態度!」

推薦文章:

我爬取了37000條球迷評論,知道了這場比賽的重要信息爬取《The Hitchhiker’s Guide to Python!》python進階書並製成pdf


平常學python

代碼不止bug,還有美和樂趣

相關文章
相關標籤/搜索