[Python]網絡爬蟲(十):一個爬蟲的誕生全過程(以山東大學績點運算爲例)

轉載自 http://blog.csdn.net/wxg694175346/article/list/1


 

[Python]網絡爬蟲(十):一個爬蟲的誕生全過程(以山東大學績點運算爲例)

分類: 爬蟲 Python 36561人閱讀 評論(87) 收藏 舉報

先來說一下我們學校的網站:

http://jwxt.sdu.edu.cn:7777/zhxt_bks/zhxt_bks.html

查詢成績需要登錄,然後顯示各學科成績,但是隻顯示成績而沒有績點,也就是加權平均分。

顯然這樣手動計算績點是一件非常麻煩的事情。所以我們可以用python做一個爬蟲來解決這個問題。



1.決戰前夜

先來準備一下工具:HttpFox插件。

這是一款http協議分析插件,分析頁面請求和響應的時間、內容、以及瀏覽器用到的COOKIE等。

以我爲例,安裝在火狐上即可,效果如圖:

可以非常直觀的查看相應的信息。

點擊start是開始檢測,點擊stop暫停檢測,點擊clear清除內容。

一般在使用之前,點擊stop暫停,然後點擊clear清屏,確保看到的是訪問當前頁面獲得的數據。



2.深入敵後

下面就去山東大學的成績查詢網站,看一看在登錄的時候,到底發送了那些信息。

先來到登錄頁面,把httpfox打開,clear之後,點擊start開啓檢測:


輸入完了個人信息,確保httpfox處於開啓狀態,然後點擊確定提交信息,實現登錄。

這個時候可以看到,httpfox檢測到了三條信息:

這時點擊stop鍵,確保捕獲到的是訪問該頁面之後反饋的數據,以便我們做爬蟲的時候模擬登陸使用。



3.庖丁解牛

乍一看我們拿到了三個數據,兩個是GET的一個是POST的,但是它們到底是什麼,應該怎麼用,我們還一無所知。

所以,我們需要挨個查看一下捕獲到的內容。

先看POST的信息:


既然是POST的信息,我們就直接看PostData即可。

可以看到一共POST兩個數據,stuid和pwd。

並且從Type的Redirect to可以看出,POST完畢之後跳轉到了bks_login2.loginmessage頁面。

由此看出,這個數據是點擊確定之後提交的表單數據。

點擊cookie標籤,看看cookie信息:


沒錯,收到了一個ACCOUNT的cookie,並且在session結束之後自動銷燬。

那麼提交之後收到了哪些信息呢?

我們來看看後面的兩個GET數據。

先看第一個,我們點擊content標籤可以查看收到的內容,是不是有一種生吞活剝的快感-。-HTML源碼暴露無疑了:


看來這個只是顯示頁面的html源碼而已,點擊cookie,查看cookie的相關信息:



啊哈,原來html頁面的內容是發送了cookie信息之後才接受到的。

再來看看最後一個接收到的信息:

大致看了一下應該只是一個叫做style.css的css文件,對我們沒有太大的作用。




4.冷靜應戰

既然已經知道了我們向服務器發送了什麼數據,也知道了我們接收到了什麼數據,基本的流程如下:

  • 首先,我們POST學號和密碼--->然後返回cookie的值
  • 然後發送cookie給服務器--->返回頁面信息。
  • 獲取到成績頁面的數據,用正則表達式將成績和學分單獨取出並計算加權平均數。

OK,看上去好像很簡單的樣紙。那下面我們就來試試看吧。

但是在實驗之前,還有一個問題沒有解決,就是POST的數據到底發送到了哪裏?

再來看一下當初的頁面:

很明顯是用一個html框架來實現的,也就是說,我們在地址欄看到的地址並不是右邊提交表單的地址。

那麼怎樣才能獲得真正的地址-。-右擊查看頁面源代碼:

嗯沒錯,那個name="w_right"的就是我們要的登錄頁面。

網站的原來的地址是:

http://jwxt.sdu.edu.cn:7777/zhxt_bks/zhxt_bks.html

所以,真正的表單提交的地址應該是:

http://jwxt.sdu.edu.cn:7777/zhxt_bks/xk_login.html

輸入一看,果不其然:


靠居然是清華大學的選課系統。。。目測是我校懶得做頁面了就直接借了。。結果連標題都不改一下。。。

但是這個頁面依舊不是我們需要的頁面,因爲我們的POST數據提交到的頁面,應該是表單form的ACTION中提交到的頁面。

也就是說,我們需要查看源碼,來知道POST數據到底發送到了哪裏:



嗯,目測這個纔是提交POST數據的地址。

整理到地址欄中,完整的地址應該如下:

http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login

(獲取的方式很簡單,在火狐瀏覽器中直接點擊那個鏈接就能看到這個鏈接的地址了)


5.小試牛刀

接下來的任務就是:用python模擬發送一個POST的數據並取到返回的cookie值。

關於cookie的操作可以看看這篇博文:

http://blog.csdn.net/wxg694175346/article/details/8925978

我們先準備一個POST的數據,再準備一個cookie的接收,然後寫出源碼如下:

[python] view plaincopy
  1. # -*- coding: utf-8 -*-  
  2. #---------------------------------------  
  3. #   程序:山東大學爬蟲  
  4. #   版本:0.1  
  5. #   作者:why  
  6. #   日期:2013-07-12  
  7. #   語言:Python 2.7  
  8. #   操作:輸入學號和密碼  
  9. #   功能:輸出成績的加權平均值也就是績點  
  10. #---------------------------------------  
  11.   
  12. import urllib    
  13. import urllib2  
  14. import cookielib  
  15.   
  16. cookie = cookielib.CookieJar()    
  17. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))  
  18.   
  19. #需要POST的數據#  
  20. postdata=urllib.urlencode({    
  21.     'stuid':'201100300428',    
  22.     'pwd':'921030'    
  23. })  
  24.   
  25. #自定義一個請求#  
  26. req = urllib2.Request(    
  27.     url = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login',    
  28.     data = postdata  
  29. )  
  30.   
  31. #訪問該鏈接#  
  32. result = opener.open(req)  
  33.   
  34. #打印返回的內容#  
  35. print result.read()     

如此這般之後,再看看運行的效果:


ok,如此這般,我們就算模擬登陸成功了。


6.偷天換日

接下來的任務就是用爬蟲獲取到學生的成績。

再來看看源網站。

開啓HTTPFOX之後,點擊查看成績,發現捕獲到了如下的數據:


點擊第一個GET的數據,查看內容可以發現Content就是獲取到的成績的內容。


而獲取到的頁面鏈接,從頁面源代碼中右擊查看元素,可以看到點擊鏈接之後跳轉的頁面(火狐瀏覽器只需要右擊,“查看此框架”,即可):


從而可以得到查看成績的鏈接如下:

http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre


7.萬事俱備

現在萬事俱備啦,所以只需要把鏈接應用到爬蟲裏面,看看能否查看到成績的頁面。

從httpfox可以看到,我們發送了一個cookie才能返回成績的信息,所以我們就用python模擬一個cookie的發送,以此來請求成績的信息:

[python] view plaincopy
  1. # -*- coding: utf-8 -*-  
  2. #---------------------------------------  
  3. #   程序:山東大學爬蟲  
  4. #   版本:0.1  
  5. #   作者:why  
  6. #   日期:2013-07-12  
  7. #   語言:Python 2.7  
  8. #   操作:輸入學號和密碼  
  9. #   功能:輸出成績的加權平均值也就是績點  
  10. #---------------------------------------  
  11.   
  12. import urllib    
  13. import urllib2  
  14. import cookielib  
  15.   
  16. #初始化一個CookieJar來處理Cookie的信息#  
  17. cookie = cookielib.CookieJar()  
  18.   
  19. #創建一個新的opener來使用我們的CookieJar#  
  20. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))  
  21.   
  22. #需要POST的數據#  
  23. postdata=urllib.urlencode({    
  24.     'stuid':'201100300428',    
  25.     'pwd':'921030'    
  26. })  
  27.   
  28. #自定義一個請求#  
  29. req = urllib2.Request(    
  30.     url = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login',    
  31.     data = postdata  
  32. )  
  33.   
  34. #訪問該鏈接#  
  35. result = opener.open(req)  
  36.   
  37. #打印返回的內容#  
  38. print result.read()  
  39.   
  40. #打印cookie的值  
  41. for item in cookie:    
  42.     print 'Cookie:Name = '+item.name    
  43.     print 'Cookie:Value = '+item.value  
  44.   
  45.       
  46. #訪問該鏈接#  
  47. result = opener.open('http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre')  
  48.   
  49. #打印返回的內容#  
  50. print result.read()  

按下F5運行即可,看看捕獲到的數據吧:


既然這樣就沒有什麼問題了吧,用正則表達式將數據稍稍處理一下,取出學分和相應的分數就可以了。



8.手到擒來

這麼一大堆html源碼顯然是不利於我們處理的,下面要用正則表達式來摳出必須的數據。

關於正則表達式的教程可以看看這個博文:

http://blog.csdn.net/wxg694175346/article/details/8929576

我們來看看成績的源碼:



既然如此,用正則表達式就易如反掌了。


我們將代碼稍稍整理一下,然後用正則來取出數據:

[python] view plaincopy
  1. # -*- coding: utf-8 -*-  
  2. #---------------------------------------  
  3. #   程序:山東大學爬蟲  
  4. #   版本:0.1  
  5. #   作者:why  
  6. #   日期:2013-07-12  
  7. #   語言:Python 2.7  
  8. #   操作:輸入學號和密碼  
  9. #   功能:輸出成績的加權平均值也就是績點  
  10. #---------------------------------------  
  11.   
  12. import urllib    
  13. import urllib2  
  14. import cookielib  
  15. import re  
  16.   
  17. class SDU_Spider:    
  18.     # 申明相關的屬性    
  19.     def __init__(self):      
  20.         self.loginUrl = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login'   # 登錄的url  
  21.         self.resultUrl = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre' # 顯示成績的url  
  22.         self.cookieJar = cookielib.CookieJar()                                      # 初始化一個CookieJar來處理Cookie的信息  
  23.         self.postdata=urllib.urlencode({'stuid':'201100300428','pwd':'921030'})     # POST的數據  
  24.         self.weights = []   #存儲權重,也就是學分  
  25.         self.points = []    #存儲分數,也就是成績  
  26.         self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))  
  27.   
  28.     def sdu_init(self):  
  29.         # 初始化鏈接並且獲取cookie  
  30.         myRequest = urllib2.Request(url = self.loginUrl,data = self.postdata)   # 自定義一個請求  
  31.         result = self.opener.open(myRequest)            # 訪問登錄頁面,獲取到必須的cookie的值  
  32.         result = self.opener.open(self.resultUrl)       # 訪問成績頁面,獲得成績的數據  
  33.         # 打印返回的內容  
  34.         # print result.read()  
  35.         self.deal_data(result.read().decode('gbk'))  
  36.         self.print_data(self.weights);  
  37.         self.print_data(self.points);  
  38.   
  39.     # 將內容從頁面代碼中摳出來    
  40.     def deal_data(self,myPage):    
  41.         myItems = re.findall('<TR>.*?<p.*?<p.*?<p.*?<p.*?<p.*?>(.*?)</p>.*?<p.*?<p.*?>(.*?)</p>.*?</TR>',myPage,re.S)     #獲取到學分  
  42.         for item in myItems:  
  43.             self.weights.append(item[0].encode('gbk'))  
  44.             self.points.append(item[1].encode('gbk'))  
  45.   
  46.               
  47.     # 將內容從頁面代碼中摳出來  
  48.     def print_data(self,items):    
  49.         for item in items:    
  50.             print item  
  51.               
  52. #調用    
  53. mySpider = SDU_Spider()    
  54. mySpider.sdu_init()    

水平有限,,正則是有點醜,。運行的效果如圖:

ok,接下來的只是數據的處理問題了。。




9.凱旋而歸

完整的代碼如下,至此一個完整的爬蟲項目便完工了。

[python] view plaincopy
  1. # -*- coding: utf-8 -*-  
  2. #---------------------------------------  
  3. #   程序:山東大學爬蟲  
  4. #   版本:0.1  
  5. #   作者:why  
  6. #   日期:2013-07-12  
  7. #   語言:Python 2.7  
  8. #   操作:輸入學號和密碼  
  9. #   功能:輸出成績的加權平均值也就是績點  
  10. #---------------------------------------  
  11.   
  12. import urllib    
  13. import urllib2  
  14. import cookielib  
  15. import re  
  16. import string  
  17.   
  18.   
  19. class SDU_Spider:    
  20.     # 申明相關的屬性    
  21.     def __init__(self):      
  22.         self.loginUrl = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login'   # 登錄的url  
  23.         self.resultUrl = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre' # 顯示成績的url  
  24.         self.cookieJar = cookielib.CookieJar()                                      # 初始化一個CookieJar來處理Cookie的信息  
  25.         self.postdata=urllib.urlencode({'stuid':'201100300428','pwd':'921030'})     # POST的數據  
  26.         self.weights = []   #存儲權重,也就是學分  
  27.         self.points = []    #存儲分數,也就是成績  
  28.         self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))  
  29.   
  30.     def sdu_init(self):  
  31.         # 初始化鏈接並且獲取cookie  
  32.         myRequest = urllib2.Request(url = self.loginUrl,data = self.postdata)   # 自定義一個請求  
  33.         result = self.opener.open(myRequest)            # 訪問登錄頁面,獲取到必須的cookie的值  
  34.         result = self.opener.open(self.resultUrl)       # 訪問成績頁面,獲得成績的數據  
  35.         # 打印返回的內容  
  36.         # print result.read()  
  37.         self.deal_data(result.read().decode('gbk'))  
  38.         self.calculate_date();  
  39.   
  40.     # 將內容從頁面代碼中摳出來    
  41.     def deal_data(self,myPage):    
  42.         myItems = re.findall('<TR>.*?<p.*?<p.*?<p.*?<p.*?<p.*?>(.*?)</p>.*?<p.*?<p.*?>(.*?)</p>.*?</TR>',myPage,re.S)     #獲取到學分  
  43.         for item in myItems:  
  44.             self.weights.append(item[0].encode('gbk'))  
  45.             self.points.append(item[1].encode('gbk'))  
  46.   
  47.     #計算績點,如果成績還沒出來,或者成績是優秀良好,就不運算該成績  
  48.     def calculate_date(self):  
  49.         point = 0.0  
  50.         weight = 0.0  
  51.         for i in range(len(self.points)):  
  52.             if(self.points[i].isdigit()):  
  53.                 point += string.atof(self.points[i])*string.atof(self.weights[i])  
  54.                 weight += string.atof(self.weights[i])  
  55.         print point/weight  
  56.   
  57.               
  58. #調用    
  59. mySpider = SDU_Spider()    
  60. mySpider.sdu_init()    



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章