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

來源:互聯網
上載者:User

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

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

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

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



1.決戰前夜

先來準備一下工具:HttpFox外掛程式。

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

以我為例,安裝在Firefox上即可,效果

可以非常直觀的查看相應的資訊。

點擊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給伺服器--->返回頁面資訊。
  • 擷取到成績頁面的資料,用Regex將成績和學分單獨取出並計算加權平均數。

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

(擷取的方式很簡單,在Firefox瀏覽器中直接點擊那個連結就能看到這個連結的地址了)


5.小試牛刀

接下來的任務就是:用python類比發送一個POST的資料並取到返回的cookie值。

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

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

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

# -*- coding: utf-8 -*-#---------------------------------------#   程式:山東大學爬蟲#   版本:0.1#   作者:why#   日期:2013-07-12#   語言:Python 2.7#   操作:輸入學號和密碼#   功能:輸出成績的加權平均值也就是績點#---------------------------------------import urllib  import urllib2import cookielibcookie = cookielib.CookieJar()  opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))#需要POST的資料#postdata=urllib.urlencode({      'stuid':'201100300428',      'pwd':'921030'  })#自訂一個請求#req = urllib2.Request(      url = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login',      data = postdata)#訪問該連結#result = opener.open(req)#列印返回的內容#print result.read()   

如此這般之後,再看看啟動並執行效果:

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


6.偷天換日

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

再來看看源網站。

開啟HTTPFOX之後,點擊查看成績,發現捕獲到了如下的資料:


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


而擷取到的頁面連結,從頁面原始碼中右擊查看元素,可以看到點選連結之後跳轉的頁面(Firefox瀏覽器只需要右擊,“查看此架構”,即可):


從而可以得到查看成績的連結如下:

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


7.萬事俱備

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

從httpfox可以看到,我們發送了一個cookie才能返回成績的資訊,所以我們就用python類比一個cookie的發送,以此來請求成績的資訊:

# -*- coding: utf-8 -*-#---------------------------------------#   程式:山東大學爬蟲#   版本:0.1#   作者:why#   日期:2013-07-12#   語言:Python 2.7#   操作:輸入學號和密碼#   功能:輸出成績的加權平均值也就是績點#---------------------------------------import urllib  import urllib2import cookielib#初始化一個CookieJar來處理Cookie的資訊#cookie = cookielib.CookieJar()#建立一個新的opener來使用我們的CookieJar#opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))#需要POST的資料#postdata=urllib.urlencode({      'stuid':'201100300428',      'pwd':'921030'  })#自訂一個請求#req = urllib2.Request(      url = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login',      data = postdata)#訪問該連結#result = opener.open(req)#列印返回的內容#print result.read()#列印cookie的值for item in cookie:      print 'Cookie:Name = '+item.name      print 'Cookie:Value = '+item.value    #訪問該連結#result = opener.open('http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre')#列印返回的內容#print result.read()

按下F5運行即可,看看捕獲到的資料吧:


既然這樣就沒有什麼問題了吧,用Regex將資料稍稍處理一下,取出學分和相應的分數就可以了。

8.手到擒來

這麼一大堆html源碼顯然是不利於我們處理的,下面要用Regex來摳出必須的資料。

關於Regex的教程可以看看這個博文:

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

我們來看看成績的源碼:

既然如此,用Regex就易如反掌了。


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

# -*- coding: utf-8 -*-#---------------------------------------#   程式:山東大學爬蟲#   版本:0.1#   作者:why#   日期:2013-07-12#   語言:Python 2.7#   操作:輸入學號和密碼#   功能:輸出成績的加權平均值也就是績點#---------------------------------------import urllib  import urllib2import cookielibimport reclass SDU_Spider:      # 申明相關的屬性      def __init__(self):            self.loginUrl = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login'   # 登入的url        self.resultUrl = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre' # 顯示成績的url        self.cookieJar = cookielib.CookieJar()                                      # 初始化一個CookieJar來處理Cookie的資訊        self.postdata=urllib.urlencode({'stuid':'201100300428','pwd':'921030'})     # POST的資料        self.weights = []   #儲存權重,也就是學分        self.points = []    #儲存分數,也就是成績        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))    def sdu_init(self):        # 初始化連結並且擷取cookie        myRequest = urllib2.Request(url = self.loginUrl,data = self.postdata)   # 自訂一個請求        result = self.opener.open(myRequest)            # 訪問登入頁面,擷取到必須的cookie的值        result = self.opener.open(self.resultUrl)       # 訪問成績頁面,獲得成績的資料        # 列印返回的內容        # print result.read()        self.deal_data(result.read().decode('gbk'))        self.print_data(self.weights);        self.print_data(self.points);    # 將內容從頁面代碼中摳出來      def deal_data(self,myPage):          myItems = re.findall('<TR>.*?<p.*?<p.*?<p.*?<p.*?<p.*?>(.*?)</p>.*?<p.*?<p.*?>(.*?)</p>.*?</TR>',myPage,re.S)     #擷取到學分        for item in myItems:            self.weights.append(item[0].encode('gbk'))            self.points.append(item[1].encode('gbk'))                # 將內容從頁面代碼中摳出來    def print_data(self,items):          for item in items:              print item            #調用  mySpider = SDU_Spider()  mySpider.sdu_init()  

水平有限,,正則是有點醜,。啟動並執行效果

ok,接下來的只是資料的處理問題了。。




9.凱旋而歸

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

# -*- coding: utf-8 -*-#---------------------------------------#   程式:山東大學爬蟲#   版本:0.1#   作者:why#   日期:2013-07-12#   語言:Python 2.7#   操作:輸入學號和密碼#   功能:輸出成績的加權平均值也就是績點#---------------------------------------import urllib  import urllib2import cookielibimport reimport stringclass SDU_Spider:      # 申明相關的屬性      def __init__(self):            self.loginUrl = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login'   # 登入的url        self.resultUrl = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre' # 顯示成績的url        self.cookieJar = cookielib.CookieJar()                                      # 初始化一個CookieJar來處理Cookie的資訊        self.postdata=urllib.urlencode({'stuid':'201100300428','pwd':'921030'})     # POST的資料        self.weights = []   #儲存權重,也就是學分        self.points = []    #儲存分數,也就是成績        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))    def sdu_init(self):        # 初始化連結並且擷取cookie        myRequest = urllib2.Request(url = self.loginUrl,data = self.postdata)   # 自訂一個請求        result = self.opener.open(myRequest)            # 訪問登入頁面,擷取到必須的cookie的值        result = self.opener.open(self.resultUrl)       # 訪問成績頁面,獲得成績的資料        # 列印返回的內容        # print result.read()        self.deal_data(result.read().decode('gbk'))        self.calculate_date();    # 將內容從頁面代碼中摳出來      def deal_data(self,myPage):          myItems = re.findall('<TR>.*?<p.*?<p.*?<p.*?<p.*?<p.*?>(.*?)</p>.*?<p.*?<p.*?>(.*?)</p>.*?</TR>',myPage,re.S)     #擷取到學分        for item in myItems:            self.weights.append(item[0].encode('gbk'))            self.points.append(item[1].encode('gbk'))    #計算績點,如果成績還沒出來,或者成績是優秀良好,就不運算該成績    def calculate_date(self):        point = 0.0        weight = 0.0        for i in range(len(self.points)):            if(self.points[i].isdigit()):                point += string.atof(self.points[i])*string.atof(self.weights[i])                weight += string.atof(self.weights[i])        print point/weight            #調用  mySpider = SDU_Spider()  mySpider.sdu_init()  


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.