學校教務處網站
登陸窗口
表單數據
觀察登陸窗口和提交的表單數據可知只要將賬號、密碼、驗證碼正確賦值提交即可模擬登陸。
賬號和密碼都有,問題的關鍵就在驗證碼上。
右鍵驗證碼圖片審查觀察源碼如下圖:
剛開始很糾結random那段隨機數,以為是確定的隨機數對應確定的驗證碼,可是一直沒有解決獲取這個隨機數的方法(直接抓取的話src總為空),然后去網上各種查發現這句話
一般驗證碼只是判斷cookie 后面的隨機值是為了防止瀏覽器讀取圖片緩存,造成驗證碼輸入錯誤
然后自己就復制了一個帶random的驗證碼網址刷新了兩下結果發現驗證碼真的會變,不是根據random,於是從網上查找得知只輸入random參數前的地址即可,於是繼續向下開展。
具體的思路是登陸將驗證碼下載下來,然后手動輸入,提交賬號、密碼、驗證碼三個數據進行模擬登陸。
模擬登陸
# coding:utf8 import re import urllib import urllib2 import cookielib loginUrl = 'http://115.24.160.162/loginAction.do' #cookie cookie = cookielib.CookieJar() handler = urllib2.HTTPCookieProcessor(cookie) opener = urllib2.build_opener(handler) #postdata values = { 'zjh':'xxxxxx', 'mm':'xxxxxx', 'v_yzm':'' } postdata = urllib.urlencode(values) #headers header = { 'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', 'Referer':'http://115.24.160.162/loginAction.do' } #第一次請求網頁得到cookie request = urllib2.Request(loginUrl,postdata,headers=header) response = opener.open(request) print '第一次請求網頁得到cookie:' print response.getcode() #獲取驗證碼----------------!!!問題一直出在這,要用帶cookie的方法訪問驗證碼的網頁---這樣的話進入的驗證碼的頁面對應的驗證碼就是登陸頁面的驗證碼了哈哈哈哈哈(之前用的是不帶cookie的urlopen()方法...) yzm = opener.open('http://115.24.160.162/validateCodeAction.do') yzm_data = yzm.read() yzm_pic = file('yzm.jpg','wb') yzm_pic.write(yzm_data) yzm_pic.close() #用戶輸入驗證碼 print '請輸入驗證碼:' values['v_yzm'] = raw_input() #帶驗證碼模擬登陸 postdata = urllib.urlencode(values) request = urllib2.Request(loginUrl,postdata,header) response = opener.open(request) print 'Response of loginAction.do' print response.read().decode('gbk')
爬取成績
根據最后打印出的網址源代碼可知成功登陸。現在我們來爬取成績。
成績頁面:
剛開始以為相應的按鈕會有對應的超鏈接,比如有一個專門的成績網址,然后就去源代碼里苦苦尋找,半天無獲,而且點擊不同按鈕瀏覽器顯示的連接根本不變。后來F12看了看網絡那一欄發現了玄機
再看這個鏈接的響應正文,完美獲得成績頁面。
接下來就是正則表達式匹配得到課程名稱和成績了
#bingo top_url = 'http://115.24.160.162/gradeLnAllAction.do?type=ln&oper=qbinfo&lnxndm=2016-2017學年秋(兩學期)' response = opener.open(top_url) print 'Response of top.jsp' content = response.read().decode('gbk') pattern = re.compile('<tr.*?class="odd".*?</td>.*?</td>.*?<td align="center">(.*?)</td>.*?<p align="center">(.*?) </P>', re.S) grades = re.findall(pattern, content) for grade in grades: print grade[0], grade[1]
正則表達式的說明(引用自http://cuiqingcai.com/990.html)
1).*? 是一個固定的搭配,.和*代表可以匹配任意無限多個字符,加上?表示使用非貪婪模式進行匹配,也就是我們會盡可能短地做匹配,以后我們還會大量用到 .*? 的搭配。
2)(.*?)代表一個分組,在這個正則表達式中我們匹配了兩個分組,在后面的遍歷grades中,grade[0]就代表第一個(.*?)所指代的內容,grade[1]就代表第二個(.*?)所指代的內容,以此類推。
3)re.S 標志代表在匹配時為點任意匹配模式,點 . 也可以代表換行符。
抓取結果
結語
感謝攀哥(他的csdn:http://m.blog.csdn.net/blog/index?username=E80FA)