零基礎(chǔ)寫python爬蟲之爬蟲編寫全記錄
先來說一下我們學(xué)校的網(wǎng)站:
http://jwxt.sdu.edu.cn:7777/zhxt_bks/zhxt_bks.html
查詢成績需要登錄,然后顯示各學(xué)科成績,但是只顯示成績而沒有績點(diǎn),也就是加權(quán)平均分。
顯然這樣手動(dòng)計(jì)算績點(diǎn)是一件非常麻煩的事情。所以我們可以用python做一個(gè)爬蟲來解決這個(gè)問題。
1.決戰(zhàn)前夜
先來準(zhǔn)備一下工具:HttpFox插件。
這是一款http協(xié)議分析插件,分析頁面請求和響應(yīng)的時(shí)間、內(nèi)容、以及瀏覽器用到的COOKIE等。
以我為例,安裝在火狐上即可,效果如圖:
可以非常直觀的查看相應(yīng)的信息。
點(diǎn)擊start是開始檢測,點(diǎn)擊stop暫停檢測,點(diǎn)擊clear清除內(nèi)容。
一般在使用之前,點(diǎn)擊stop暫停,然后點(diǎn)擊clear清屏,確??吹降氖窃L問當(dāng)前頁面獲得的數(shù)據(jù)。
2.深入敵后
下面就去山東大學(xué)的成績查詢網(wǎng)站,看一看在登錄的時(shí)候,到底發(fā)送了那些信息。
先來到登錄頁面,把httpfox打開,clear之后,點(diǎn)擊start開啟檢測:
輸入完了個(gè)人信息,確保httpfox處于開啟狀態(tài),然后點(diǎn)擊確定提交信息,實(shí)現(xiàn)登錄。
這個(gè)時(shí)候可以看到,httpfox檢測到了三條信息:
這時(shí)點(diǎn)擊stop鍵,確保捕獲到的是訪問該頁面之后反饋的數(shù)據(jù),以便我們做爬蟲的時(shí)候模擬登陸使用。
3.庖丁解牛
乍一看我們拿到了三個(gè)數(shù)據(jù),兩個(gè)是GET的一個(gè)是POST的,但是它們到底是什么,應(yīng)該怎么用,我們還一無所知。
所以,我們需要挨個(gè)查看一下捕獲到的內(nèi)容。
先看POST的信息:
既然是POST的信息,我們就直接看PostData即可。
可以看到一共POST兩個(gè)數(shù)據(jù),stuid和pwd。
并且從Type的Redirect to可以看出,POST完畢之后跳轉(zhuǎn)到了bks_login2.loginmessage頁面。
由此看出,這個(gè)數(shù)據(jù)是點(diǎn)擊確定之后提交的表單數(shù)據(jù)。
點(diǎn)擊cookie標(biāo)簽,看看cookie信息:
沒錯(cuò),收到了一個(gè)ACCOUNT的cookie,并且在session結(jié)束之后自動(dòng)銷毀。
那么提交之后收到了哪些信息呢?
我們來看看后面的兩個(gè)GET數(shù)據(jù)。
先看第一個(gè),我們點(diǎn)擊content標(biāo)簽可以查看收到的內(nèi)容,是不是有一種生吞活剝的快感-。-HTML源碼暴露無疑了:
看來這個(gè)只是顯示頁面的html源碼而已,點(diǎn)擊cookie,查看cookie的相關(guān)信息:
啊哈,原來html頁面的內(nèi)容是發(fā)送了cookie信息之后才接受到的。
再來看看最后一個(gè)接收到的信息:
大致看了一下應(yīng)該只是一個(gè)叫做style.css的css文件,對我們沒有太大的作用。
4.冷靜應(yīng)戰(zhàn)
既然已經(jīng)知道了我們向服務(wù)器發(fā)送了什么數(shù)據(jù),也知道了我們接收到了什么數(shù)據(jù),基本的流程如下:
首先,我們POST學(xué)號(hào)和密碼--->然后返回cookie的值然后發(fā)送cookie給服務(wù)器--->返回頁面信息。獲取到成績頁面的數(shù)據(jù),用正則表達(dá)式將成績和學(xué)分單獨(dú)取出并計(jì)算加權(quán)平均數(shù)。
OK,看上去好像很簡單的樣紙。那下面我們就來試試看吧。
但是在實(shí)驗(yàn)之前,還有一個(gè)問題沒有解決,就是POST的數(shù)據(jù)到底發(fā)送到了哪里?
再來看一下當(dāng)初的頁面:
很明顯是用一個(gè)html框架來實(shí)現(xiàn)的,也就是說,我們在地址欄看到的地址并不是右邊提交表單的地址。
那么怎樣才能獲得真正的地址-。-右擊查看頁面源代碼:
嗯沒錯(cuò),那個(gè)name="w_right"的就是我們要的登錄頁面。
網(wǎng)站的原來的地址是:
http://jwxt.sdu.edu.cn:7777/zhxt_bks/zhxt_bks.html
所以,真正的表單提交的地址應(yīng)該是:
http://jwxt.sdu.edu.cn:7777/zhxt_bks/xk_login.html
輸入一看,果不其然:
靠居然是清華大學(xué)的選課系統(tǒng)。。。目測是我校懶得做頁面了就直接借了。。結(jié)果連標(biāo)題都不改一下。。。
但是這個(gè)頁面依舊不是我們需要的頁面,因?yàn)槲覀兊腜OST數(shù)據(jù)提交到的頁面,應(yīng)該是表單form的ACTION中提交到的頁面。
也就是說,我們需要查看源碼,來知道POST數(shù)據(jù)到底發(fā)送到了哪里:
嗯,目測這個(gè)才是提交POST數(shù)據(jù)的地址。
整理到地址欄中,完整的地址應(yīng)該如下:
http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login
(獲取的方式很簡單,在火狐瀏覽器中直接點(diǎn)擊那個(gè)鏈接就能看到這個(gè)鏈接的地址了)
5.小試牛刀
接下來的任務(wù)就是:用python模擬發(fā)送一個(gè)POST的數(shù)據(jù)并取到返回的cookie值。
關(guān)于cookie的操作可以看看這篇博文:
http://chabaoo.cn/article/57144.htm
我們先準(zhǔn)備一個(gè)POST的數(shù)據(jù),再準(zhǔn)備一個(gè)cookie的接收,然后寫出源碼如下:
# -*- coding: utf-8 -*-
#---------------------------------------
# 程序:山東大學(xué)爬蟲
# 版本:0.1
# 作者:why
# 日期:2013-07-12
# 語言:Python 2.7
# 操作:輸入學(xué)號(hào)和密碼
# 功能:輸出成績的加權(quán)平均值也就是績點(diǎn)
#---------------------------------------
import urllib
import urllib2
import cookielib
cookie = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
#需要POST的數(shù)據(jù)#
postdata=urllib.urlencode({
'stuid':'201100300428',
'pwd':'921030'
})
#自定義一個(gè)請求#
req = urllib2.Request(
url = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login',
data = postdata
)
#訪問該鏈接#
result = opener.open(req)
#打印返回的內(nèi)容#
print result.read()
如此這般之后,再看看運(yùn)行的效果:
ok,如此這般,我們就算模擬登陸成功了。
6.偷天換日
接下來的任務(wù)就是用爬蟲獲取到學(xué)生的成績。
再來看看源網(wǎng)站。
開啟HTTPFOX之后,點(diǎn)擊查看成績,發(fā)現(xiàn)捕獲到了如下的數(shù)據(jù):
點(diǎn)擊第一個(gè)GET的數(shù)據(jù),查看內(nèi)容可以發(fā)現(xiàn)Content就是獲取到的成績的內(nèi)容。
而獲取到的頁面鏈接,從頁面源代碼中右擊查看元素,可以看到點(diǎn)擊鏈接之后跳轉(zhuǎn)的頁面(火狐瀏覽器只需要右擊,“查看此框架”,即可):
從而可以得到查看成績的鏈接如下:
http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre
7.萬事俱備
現(xiàn)在萬事俱備啦,所以只需要把鏈接應(yīng)用到爬蟲里面,看看能否查看到成績的頁面。
從httpfox可以看到,我們發(fā)送了一個(gè)cookie才能返回成績的信息,所以我們就用python模擬一個(gè)cookie的發(fā)送,以此來請求成績的信息:
# -*- coding: utf-8 -*-
#---------------------------------------
# 程序:山東大學(xué)爬蟲
# 版本:0.1
# 作者:why
# 日期:2013-07-12
# 語言:Python 2.7
# 操作:輸入學(xué)號(hào)和密碼
# 功能:輸出成績的加權(quán)平均值也就是績點(diǎn)
#---------------------------------------
import urllib
import urllib2
import cookielib
#初始化一個(gè)CookieJar來處理Cookie的信息#
cookie = cookielib.CookieJar()
#創(chuàng)建一個(gè)新的opener來使用我們的CookieJar#
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
#需要POST的數(shù)據(jù)#
postdata=urllib.urlencode({
'stuid':'201100300428',
'pwd':'921030'
})
#自定義一個(gè)請求#
req = urllib2.Request(
url = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login',
data = postdata
)
#訪問該鏈接#
result = opener.open(req)
#打印返回的內(nèi)容#
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')
#打印返回的內(nèi)容#
print result.read()
按下F5運(yùn)行即可,看看捕獲到的數(shù)據(jù)吧:
既然這樣就沒有什么問題了吧,用正則表達(dá)式將數(shù)據(jù)稍稍處理一下,取出學(xué)分和相應(yīng)的分?jǐn)?shù)就可以了。
8.手到擒來
這么一大堆html源碼顯然是不利于我們處理的,下面要用正則表達(dá)式來摳出必須的數(shù)據(jù)。
關(guān)于正則表達(dá)式的教程可以看看這個(gè)博文:
http://chabaoo.cn/article/57150.htm
我們來看看成績的源碼:
既然如此,用正則表達(dá)式就易如反掌了。
我們將代碼稍稍整理一下,然后用正則來取出數(shù)據(jù):
# -*- coding: utf-8 -*-
#---------------------------------------
# 程序:山東大學(xué)爬蟲
# 版本:0.1
# 作者:why
# 日期:2013-07-12
# 語言:Python 2.7
# 操作:輸入學(xué)號(hào)和密碼
# 功能:輸出成績的加權(quán)平均值也就是績點(diǎn)
#---------------------------------------
import urllib
import urllib2
import cookielib
import re
class SDU_Spider:
# 申明相關(guān)的屬性
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() # 初始化一個(gè)CookieJar來處理Cookie的信息
self.postdata=urllib.urlencode({'stuid':'201100300428','pwd':'921030'}) # POST的數(shù)據(jù)
self.weights = [] #存儲(chǔ)權(quán)重,也就是學(xué)分
self.points = [] #存儲(chǔ)分?jǐn)?shù),也就是成績
self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))
def sdu_init(self):
# 初始化鏈接并且獲取cookie
myRequest = urllib2.Request(url = self.loginUrl,data = self.postdata) # 自定義一個(gè)請求
result = self.opener.open(myRequest) # 訪問登錄頁面,獲取到必須的cookie的值
result = self.opener.open(self.resultUrl) # 訪問成績頁面,獲得成績的數(shù)據(jù)
# 打印返回的內(nèi)容
# print result.read()
self.deal_data(result.read().decode('gbk'))
self.print_data(self.weights);
self.print_data(self.points);
# 將內(nèi)容從頁面代碼中摳出來
def deal_data(self,myPage):
myItems = re.findall('<TR>.*?<p.*?<p.*?<p.*?<p.*?<p.*?>(.*?)</p>.*?<p.*?<p.*?>(.*?)</p>.*?</TR>',myPage,re.S) #獲取到學(xué)分
for item in myItems:
self.weights.append(item[0].encode('gbk'))
self.points.append(item[1].encode('gbk'))
# 將內(nèi)容從頁面代碼中摳出來
def print_data(self,items):
for item in items:
print item
#調(diào)用
mySpider = SDU_Spider()
mySpider.sdu_init()
水平有限,,正則是有點(diǎn)丑,。運(yùn)行的效果如圖:
ok,接下來的只是數(shù)據(jù)的處理問題了。。
9.凱旋而歸
完整的代碼如下,至此一個(gè)完整的爬蟲項(xiàng)目便完工了。
# -*- coding: utf-8 -*-
#---------------------------------------
# 程序:山東大學(xué)爬蟲
# 版本:0.1
# 作者:why
# 日期:2013-07-12
# 語言:Python 2.7
# 操作:輸入學(xué)號(hào)和密碼
# 功能:輸出成績的加權(quán)平均值也就是績點(diǎn)
#---------------------------------------
import urllib
import urllib2
import cookielib
import re
import string
class SDU_Spider:
# 申明相關(guān)的屬性
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() # 初始化一個(gè)CookieJar來處理Cookie的信息
self.postdata=urllib.urlencode({'stuid':'201100300428','pwd':'921030'}) # POST的數(shù)據(jù)
self.weights = [] #存儲(chǔ)權(quán)重,也就是學(xué)分
self.points = [] #存儲(chǔ)分?jǐn)?shù),也就是成績
self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))
def sdu_init(self):
# 初始化鏈接并且獲取cookie
myRequest = urllib2.Request(url = self.loginUrl,data = self.postdata) # 自定義一個(gè)請求
result = self.opener.open(myRequest) # 訪問登錄頁面,獲取到必須的cookie的值
result = self.opener.open(self.resultUrl) # 訪問成績頁面,獲得成績的數(shù)據(jù)
# 打印返回的內(nèi)容
# print result.read()
self.deal_data(result.read().decode('gbk'))
self.calculate_date();
# 將內(nèi)容從頁面代碼中摳出來
def deal_data(self,myPage):
myItems = re.findall('<TR>.*?<p.*?<p.*?<p.*?<p.*?<p.*?>(.*?)</p>.*?<p.*?<p.*?>(.*?)</p>.*?</TR>',myPage,re.S) #獲取到學(xué)分
for item in myItems:
self.weights.append(item[0].encode('gbk'))
self.points.append(item[1].encode('gbk'))
#計(jì)算績點(diǎn),如果成績還沒出來,或者成績是優(yōu)秀良好,就不運(yùn)算該成績
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
#調(diào)用
mySpider = SDU_Spider()
mySpider.sdu_init()
以上便是此爬蟲誕生的全部過程的詳細(xì)記錄了,有沒有很神奇的趕腳??哈哈,開個(gè)玩笑,需要的朋友參考下吧,自由擴(kuò)展
相關(guān)文章
分析python并發(fā)網(wǎng)絡(luò)通信模型
隨著互聯(lián)網(wǎng)和物聯(lián)網(wǎng)的高速發(fā)展,使用網(wǎng)絡(luò)的人數(shù)和電子設(shè)備的數(shù)量急劇增長,其也對互聯(lián)網(wǎng)后臺(tái)服務(wù)程序提出了更高的性能和并發(fā)要求。本文主要分析比較了一些模型的優(yōu)缺點(diǎn),并且用python來實(shí)現(xiàn)2021-06-06使用Python做定時(shí)任務(wù)及時(shí)了解互聯(lián)網(wǎng)動(dòng)態(tài)
這篇文章主要介紹了使用Python做定時(shí)任務(wù)及時(shí)了解互聯(lián)網(wǎng)動(dòng)態(tài),需要的朋友可以參考下2019-05-05為python爬蟲docker鏡像添加nodejs環(huán)境實(shí)現(xiàn)方法
這篇文章主要為大家介紹了為python爬蟲docker鏡像添加nodejs環(huán)境實(shí)現(xiàn)方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09python 自動(dòng)識(shí)別并連接串口的實(shí)現(xiàn)
這篇文章主要介紹了python 自動(dòng)識(shí)別并連接串口的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01Python基礎(chǔ)學(xué)習(xí)之函數(shù)和代碼復(fù)用詳解
函數(shù)能提高應(yīng)用的模塊性,和代碼的重復(fù)利用率,下面這篇文章主要給大家介紹了關(guān)于Python基礎(chǔ)學(xué)習(xí)之函數(shù)和代碼復(fù)用的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08Python中實(shí)現(xiàn)文本預(yù)處理的方法小結(jié)
文本數(shù)據(jù)是數(shù)據(jù)科學(xué)和自然語言處理領(lǐng)域的關(guān)鍵組成部分,本文將深入探討Python中文本預(yù)處理的關(guān)鍵步驟,并提供豐富的示例代碼,希望對大家有所幫助2023-12-12