鍍金池/ 教程/ Python/ 計(jì)算大學(xué)本學(xué)期績(jī)點(diǎn)
綜述
Cookie 的使用
爬蟲(chóng)基礎(chǔ)了解
計(jì)算大學(xué)本學(xué)期績(jī)點(diǎn)
抓取淘寶 MM 照片
爬蟲(chóng)框架 Scrapy 安裝配置
模擬登錄淘寶并獲取所有訂單
Urllib 庫(kù)的高級(jí)用法
URLError 異常處理
正則表達(dá)式
Beautiful Soup 的用法
爬取糗事百科段子
爬取百度貼吧帖子
Urllib 庫(kù)的基本使用

計(jì)算大學(xué)本學(xué)期績(jī)點(diǎn)

大家好,本次為大家?guī)?lái)的項(xiàng)目是計(jì)算大學(xué)本學(xué)期績(jī)點(diǎn)。首先說(shuō)明的是,博主來(lái)自山東大學(xué),有屬于個(gè)人的學(xué)生成績(jī)管理系統(tǒng),需要學(xué)號(hào)密碼才可以登錄,不過(guò)可能廣大讀者沒(méi)有這個(gè)學(xué)號(hào)密碼,不能實(shí)際進(jìn)行操作,所以最主要的還是獲取它的原理。最主要的是了解cookie的相關(guān)操作。

本篇目標(biāo)

  1. 模擬登錄學(xué)生成績(jī)管理系統(tǒng)

  2. 抓取本學(xué)期成績(jī)界面

  3. 計(jì)算打印本學(xué)期成績(jī)

URL 的獲取

恩,博主來(lái)自山東大學(xué)~

先貼一個(gè) URL,讓大家知道我們學(xué)校學(xué)生信息系統(tǒng)的網(wǎng)站構(gòu)架,主頁(yè)是 http://jwxt.sdu.edu.cn:7890/zhxt_bks/zhxt_bks.html,山東大學(xué)學(xué)生個(gè)人信息系統(tǒng),進(jìn)去之后,Oh 不,他竟然用了frame,一個(gè)多么古老的而又任性的寫(xiě)法,真是驚出一身冷汗~

算了,就算他是frame又能拿我怎么樣?我們點(diǎn)到登錄界面,審查一下元素,先看看登錄界面的URL 是怎樣的?

http://wiki.jikexueyuan.com/project/python-crawler-guide/images/14.png" alt="" />

恩,看到了右側(cè)的 frame 名稱(chēng),src=”xk_login.html”,可以分析出完整的登錄界面的網(wǎng)址為 http://jwxt.sdu.edu.cn:7890/zhxt_bks/xk_login.html,點(diǎn)進(jìn)去看看,真是棒棒噠,他喵的竟然是清華大學(xué)選課系統(tǒng),醉了,你說(shuō)你抄襲就抄襲吧,改改名字也不錯(cuò)啊~

算了,就不和他計(jì)較了。現(xiàn)在,我們登錄一下,用瀏覽器監(jiān)聽(tīng)網(wǎng)絡(luò)。

我用的是獵豹瀏覽器,審查元素時(shí)會(huì)有一個(gè)網(wǎng)絡(luò)的選項(xiàng),如果大家用的 Chrome,也有相對(duì)應(yīng)的功能,F(xiàn)irefox 需要裝插件 HttpFox,同樣可以實(shí)現(xiàn)。

這個(gè)網(wǎng)絡(luò)監(jiān)聽(tīng)功能可以監(jiān)聽(tīng)表單的傳送以及請(qǐng)求頭,響應(yīng)頭等等的信息。截個(gè)圖看一下,恩,我偷偷把密碼隱藏了,你看不到~

大家看到的是登錄之后出現(xiàn)的信息以及 NetWork 監(jiān)聽(tīng),顯示了 hearders 的詳細(xì)信息。

http://wiki.jikexueyuan.com/project/python-crawler-guide/images/15.png" alt="" />

最主要的內(nèi)容,我們可以發(fā)現(xiàn)有一個(gè)表單提交的過(guò)程,提交方式為 POST,兩個(gè)參數(shù)分別為 stuid 和 pwd。

請(qǐng)求的URL為 http://jwxt.sdu.edu.cn:7890/pls/wwwbks/bks_login2.login,沒(méi)錯(cuò),找到表單數(shù)據(jù)和目標(biāo)地址就是這么簡(jiǎn)單。

在這里注意,剛才的 http://jwxt.sdu.edu.cn:7890/zhxt_bks/xk_login.html 只是登錄界面的地址,剛剛得到的這個(gè)地址才是登錄索要提交到的真正的URL。希望大家這里不要混淆。

不知道山大這個(gè)系統(tǒng)有沒(méi)有做headers的檢查,我們先不管這么多,先嘗試一下模擬登錄并保存Cookie。

模擬登錄

好,通過(guò)以上信息,我們已經(jīng)找到了登錄的目標(biāo)地址為 http://jwxt.sdu.edu.cn:7890/pls/wwwbks/bks_login2.login

有一個(gè)表單提交到這個(gè)URL,表單的兩個(gè)內(nèi)容分別為 stuid 和 pwd,學(xué)號(hào)和密碼,沒(méi)有其他的隱藏信息,提交方式為 POST。

好,現(xiàn)在我們首先構(gòu)造以下代碼來(lái)完成登錄??纯磿?huì)不會(huì)獲取到登錄之后的提示頁(yè)面。

__author__ = 'CQC'
\# -*- coding:utf-8 -*-

import urllib
import urllib2
import cookielib
import re

\#山東大學(xué)績(jī)點(diǎn)運(yùn)算
class SDU:

    def __init__(self):
        self.loginUrl = 'http://jwxt.sdu.edu.cn:7890/pls/wwwbks/bks_login2.login'
        self.cookies = cookielib.CookieJar()
        self.postdata = urllib.urlencode({
            'stuid':'201200131012',
            'pwd':'xxxxxx'
         })
        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookies))

    def getPage(self):
        request  = urllib2.Request(
            url = self.loginUrl,
            data = self.postdata)
        result = self.opener.open(request)
        #打印登錄內(nèi)容
        print result.read().decode('gbk')

sdu = SDU()
sdu.getPage()  

測(cè)試一下,竟然成功了,山大這網(wǎng)竟然沒(méi)有做 headers 檢查,很順利就登錄進(jìn)去了。

說(shuō)明一下,在這里我們利用了前面所說(shuō)的 cookie,用到了 CookieJar 這個(gè)對(duì)象來(lái)保存cookies,另外通過(guò)構(gòu)建 opener,利用 open 方法實(shí)現(xiàn)了登錄。如果大家覺(jué)得這里有疑惑,請(qǐng)看 Python爬蟲(chóng)入門(mén)六之Cookie的使用,這篇文章說(shuō)得比較詳細(xì)。

好,我們看一下運(yùn)行結(jié)果

http://wiki.jikexueyuan.com/project/python-crawler-guide/images/16.png" alt="" />

酸爽啊,接下來(lái)我們只要再獲取到本學(xué)期成績(jī)界面然后把成績(jī)抓取出來(lái)就好了。

抓取本學(xué)期成績(jī)

讓我們先在瀏覽器中找到本學(xué)期成績(jī)界面,點(diǎn)擊左邊的本學(xué)期成績(jī)。

http://wiki.jikexueyuan.com/project/python-crawler-guide/images/17.png" alt="" />

重新審查元素,你會(huì)發(fā)現(xiàn)這個(gè) frame 的 src 還是沒(méi)有變,仍然是 xk_login.html,引起這個(gè)頁(yè)面變化的原因是在左邊的本學(xué)期成績(jī)這個(gè)超鏈接設(shè)置了一個(gè)目標(biāo) frame,所以,那個(gè)頁(yè)面就顯示在右側(cè)了。

所以,讓我們?cè)賹彶橐幌卤緦W(xué)期成績(jī)這個(gè)超鏈接的內(nèi)容是什么~

http://wiki.jikexueyuan.com/project/python-crawler-guide/images/18.png" alt="" />

恩,找到它了,本學(xué)期成績(jī)。

那么,完整的URL就是 http://jwxt.sdu.edu.cn:7890/pls/wwwbks/bkscjcx.curscopre,好,URL已經(jīng)找到了,我們繼續(xù)完善一下代碼,獲取這個(gè)頁(yè)面。

__author__ = 'CQC'
\# -*- coding:utf-8 -*-

import urllib
import urllib2
import cookielib
import re

\#山東大學(xué)績(jī)點(diǎn)運(yùn)算
class SDU:

    def __init__(self):
        \#登錄URL
        self.loginUrl = 'http://jwxt.sdu.edu.cn:7890/pls/wwwbks/bks_login2.login'
        \#本學(xué)期成績(jī)URL
        self.gradeUrl = 'http://jwxt.sdu.edu.cn:7890/pls/wwwbks/bkscjcx.curscopre'
        self.cookies = cookielib.CookieJar()
        self.postdata = urllib.urlencode({
            'stuid':'201200131012',
            'pwd':'xxxxxx'
         })
        \#構(gòu)建opener
        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookies))

    \#獲取本學(xué)期成績(jī)頁(yè)面
    def getPage(self):
        request  = urllib2.Request(
            url = self.loginUrl,
            data = self.postdata)
        result = self.opener.open(request)
        result = self.opener.open(self.gradeUrl)
        \#打印登錄內(nèi)容
        print result.read().decode('gbk')

sdu = SDU()
sdu.getPage()  

上面的代碼,我們最主要的是增加了

result = self.opener.open(self.gradeUrl)  

這句代碼,用原來(lái)的 opener 訪(fǎng)問(wèn)一個(gè)本學(xué)期成績(jī)的 URL 即可。運(yùn)行結(jié)果如下

http://wiki.jikexueyuan.com/project/python-crawler-guide/images/19.png" alt="" />

恩,本學(xué)期成績(jī)的頁(yè)面已經(jīng)被我們抓取下來(lái)了,接下來(lái)用正則表達(dá)式提取一下,然后計(jì)算學(xué)分即可

抓取有效信息

接下來(lái)我們就把頁(yè)面內(nèi)容提取一下,最主要的便是學(xué)分以及分?jǐn)?shù)了。

平均績(jī)點(diǎn) = ∑(每科學(xué)分*每科分?jǐn)?shù))/總學(xué)分

所以我們把每科的學(xué)分以及分?jǐn)?shù)抓取下來(lái)就好了,對(duì)于有些課打了良好或者優(yōu)秀等級(jí)的,我們不進(jìn)行抓取。

我們可以發(fā)現(xiàn)每一科都是TR標(biāo)簽,然后是一系列的td標(biāo)簽

<TR>
<td bgcolor="#EAE2F3"><p align="center"><INPUT TYPE="checkbox" NAME="p_pm" VALUE="013320131012015011294 面向?qū)ο蠹夹g(shù)"></p></td>
<td bgcolor="#EAE2F3"><p align="center">0133201310</p></td>
<td bgcolor="#EAE2F3"><p align="center">面向?qū)ο蠹夹g(shù)</p></td>
<td bgcolor="#EAE2F3"><p align="center">1</p></td>
<td bgcolor="#EAE2F3"><p align="center">2.5</p></td>
<td bgcolor="#EAE2F3"><p align="center">20150112</p></td>
<td bgcolor="#EAE2F3"><p align="center">94</p></td>
<td bgcolor="#EAE2F3"><p align="center">必修</p></td>
</TR>  

我們用下面的正則表達(dá)式進(jìn)行提取即可,部分代碼如下

page = self.getPage()
myItems = re.findall('<TR>.*?<p.*?<p.*?<p.*?<p.*?<p.*?>(.*?)</p>.*?<p.*?<p.*?>(.*?)</p>.*?</TR>',page,re.S) 
for item in myItems:
   self.credit.append(item[0].encode('gbk'))
   self.grades.append(item[1].encode('gbk'))  

主要利用了 findall 方法,這個(gè)方法在此就不多介紹了,前面我們已經(jīng)用過(guò)多次了。

得到的學(xué)分和分?jǐn)?shù)我們都用列表 list 進(jìn)行存儲(chǔ),所以用了 append 方法,每獲取到一個(gè)信息就把它加進(jìn)去。

整理計(jì)算最后績(jī)點(diǎn)

恩,像上面那樣把學(xué)分績(jī)點(diǎn)都保存到列表 list 中了,所以我們最后用一個(gè)公式來(lái)計(jì)算學(xué)分績(jī)點(diǎn)就好了,最后整理后的代碼如下:

\# -*- coding: utf-8 -*-  

import urllib
import urllib2
import cookielib
import re
import string

\#績(jī)點(diǎn)運(yùn)算
class SDU:

   \#類(lèi)的初始化
   def __init__(self):
      \#登錄URL
      self.loginUrl = 'http://jwxt.sdu.edu.cn:7890/pls/wwwbks/bks_login2.login'
      \#成績(jī)URL
      self.gradeUrl = 'http://jwxt.sdu.edu.cn:7890/pls/wwwbks/bkscjcx.curscopre'
      \#CookieJar對(duì)象
      self.cookies = cookielib.CookieJar()
      \#表單數(shù)據(jù)
      self.postdata = urllib.urlencode({
            'stuid':'201200131012',
            'pwd':'xxxxx'
         })
      \#構(gòu)建opener
      self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookies))
      \#學(xué)分list
      self.credit = []
      \#成績(jī)list
      self.grades = []

   def getPage(self):
      req  = urllib2.Request(
            url = self.loginUrl,
            data = self.postdata)
      result = self.opener.open(req)
      result = self.opener.open(self.gradeUrl)
      \#返回本學(xué)期成績(jī)頁(yè)面
      return result.read().decode('gbk')

   def getGrades(self):
      \#獲得本學(xué)期成績(jī)頁(yè)面
      page = self.getPage()
      \#正則匹配
      myItems = re.findall('<TR>.*?<p.*?<p.*?<p.*?<p.*?<p.*?>(.*?)</p>.*?<p.*?<p.*?>(.*?)</p>.*?</TR>',page,re.S) 
      for item in myItems:
         self.credit.append(item[0].encode('gbk'))
         self.grades.append(item[1].encode('gbk'))
      self.getGrade()

   def getGrade(self):
      \#計(jì)算總績(jī)點(diǎn)
      sum = 0.0
      weight = 0.0
      for i in range(len(self.credit)):
         if(self.grades[i].isdigit()):
            sum += string.atof(self.credit[i])*string.atof(self.grades[i])
            weight += string.atof(self.credit[i])

      print u"本學(xué)期績(jī)點(diǎn)為:",sum/weight

sdu = SDU()
sdu.getGrades()  

好,最后就會(huì)打印輸出本學(xué)期績(jī)點(diǎn)是多少,小伙伴們最主要的了解上面的編程思路就好。

最主要的內(nèi)容就是 Cookie 的使用,模擬登錄的功能。

本文思路參考來(lái)源:汪海的爬蟲(chóng)

上一篇:綜述下一篇:爬取百度貼吧帖子