Python爬蟲實戰---抓取圖書館借閱信息

来源:http://www.cnblogs.com/KGoing/archive/2016/12/10/6150555.html
-Advertisement-
Play Games

Python爬蟲實戰 抓取圖書館借閱信息 原創作品,引用請表明出處:Python爬蟲實戰 抓取圖書館借閱信息 前段時間在圖書館借了很多書,借得多了就容易忘記每本書的應還日期,老是擔心自己會違約,影響日後借書,而自己又懶得總是登錄到學校圖書館借閱系統查看,於是就打算寫一個爬蟲來抓取自己的借閱信息,把每 ...


Python爬蟲實戰---抓取圖書館借閱信息


原創作品,引用請表明出處:Python爬蟲實戰---抓取圖書館借閱信息 

 

  前段時間在圖書館借了很多書,借得多了就容易忘記每本書的應還日期,老是擔心自己會違約,影響日後借書,而自己又懶得總是登錄到學校圖書館借閱系統查看,於是就打算寫一個爬蟲來抓取自己的借閱信息,把每本書的應還日期給爬下來,並寫入txt文件,這樣每次忘了就可以打開該txt文件查看,每次借閱信息改變了,只要再重新運行一遍該程式,原txt文件就會被新文件覆蓋,裡面的內容得到更新。

用到的技術:  

  Python版本是 2.7 ,同時用到了urllib2、cookielib、re三個模塊。urllib2用於創建請求(request),並抓取網頁信息,返回一個類似於文件類型的response對象;cookielib用於儲存cookie對象,以實現模擬登錄功能;re模塊提供對正則表達式的支持,用於對抓取到的頁面信息進行匹配,以得到自己想要的信息

抓取一個頁面:  

  使用urllib2簡單抓取一個網頁的過程非常簡單:

1 import urllib2
2 response = urllib2.urlopen("http://www.baidu.com")
3 html = response.read()

   urllib2中的urlopen()方法,看其字面意思就知道是打開一個URL(uniform resource locator)地址,上面例子傳入的時百度首頁的地址,遵循HTTP協議,除了http協議外,urlopen()方法還可以打開遵循ftp、file協議的地址,如:

1 response = urllib2.urlopen("ftp://example.com")

  除URL參數外,urlopen()方法還接受data和timeout參數:

1 response = urllib2.urlopen(url ,data ,timeout)

  其中data是打開一個網頁時需要傳入的數據,比如打開一個登錄界面時往往需要傳入用戶名和密碼等信息,在下文登錄圖書館系統時將會看到其用法;timeout是設置超時時間,即超過一定時間頁面無響應即報錯;在urlopen()方法中,data和timeout不是必須的,即可填可不填,註意:當頁面需要有數據傳入時,data是必需的。

  可以看到,在打開一個網頁時,有時往往需要傳入多個參數,再加上HTTP協議是基於請求(request)和應答(response)的,即客戶端發出請求(request),伺服器端返回應答(response),所以在使用urlopen()方法時,往往是構造一個request對象作為參數傳入,該request對象包括url、data、timeout、headers等信息:

1 import urllib2
2 request = urllib2.Request("http://www.baidu.com")
3 response = urllib2.urlopen(request)
4 html = response.read()

  這段代碼得到的結果和上面得到的結果一樣,但是在邏輯上顯得更明確、清晰。

Cookie的使用:  

  在訪問某些網站時,該網站需要在客戶端本地儲存一些數據、信息(經過加密),併在接下來的請求(request)中返回給伺服器,否則伺服器將拒絕該請求,這些數據即存儲在本地的cookie中。例如,訪問學校圖書館系統時,需進行登錄,等登錄完成之後,伺服器端將會在本地儲存一些經過加密的數據在cookie中,當客戶端發送查詢借閱信息的請求(request)時,會連帶cookie裡面的數據一起發送給伺服器,伺服器確定cookie信息後允許訪問,否則拒絕該請求。

  Cookielib模塊提供了CookieJar類用於捕捉和儲存HTTP 的cookie數據,所以要創建一個cookie只要創建一個CookieJar實例即可:

1 import cookielib
2 cookie = coolielib.CookieJar()

   創建cookie了就萬事大吉了嗎?沒那麼簡單,我們要完成的操作是發送登錄請求、記錄cookie、再發送讀取借閱信息的請求並向伺服器反饋cookie信息,要完成這一系列的操作,原來的urlopen()方法已不能勝任,幸運的是,urllib2模塊還提供了一個OpenerDirector類,可以接受一個cookie處理器為參數,實現上述功能,而這個cookie處理器則可以通過HTTPCookieProcessor類接受一個cookie對象實例化後得到。即先通過HTTPCookieProcessor實例化得到一個cookie處理器handler,再將此處理器headler作為參數傳入OpenDirector實例化得到一個能捕捉cookie數據的opener,代碼如下:

1 import urllib2
2 import cookielib
3 
4 cookie = cookielib.CookieJar()
5 handler = urllib2.HTTPCookieProcessor(cookie)
6 opener = urllib2.build_opener(handler)
7 response = opener.open("http://www.baidu.com")

 登錄圖書館系統:

  至此,我們就可以進行圖書館借閱信息的抓取了。來看看hit圖書館登錄界面

                                       

  首先,在Firefox瀏覽器下,藉助httpfox插件進行網路監聽,看看登錄此頁面需要向伺服器發送哪些數據:

                                                 

  輸入登錄賬號和密碼,打開httpfox插件,點擊start開始監聽,然後點擊登陸按鈕進行登陸:

                                                  

  上圖便是登陸之後的頁面,以及整個登陸過程捕捉到的信息。選擇第一條捕捉到的信息,點擊下方數據頭(Headers)選項卡,可以看見登錄此頁面需要發送的一些數據。有一些網站,對於訪問它們的請求需要檢查數據頭(Headers),只有數據頭信息符合要求才允許訪問。在登錄圖書館系統時,可以先嘗試不發數據頭,如果能順利訪問則說明沒有Headers檢查這一環節。數據發送的方法為GET,即只需要將要發送的數據信息加在登陸請求的後面。在Headers選項卡的Request-Line屬性中,問號前面的即為登陸請求"GET /lib/opacAction.do",加上IP地址之後真實的請求URL為"http://202.118.250.131/lib/opacAction.do",問號後面的即為登陸需要的數據,包括賬號、密碼等信息。

  接下來點開QueryString選項卡,查看由GET方法傳送的數據:

             

  需要傳送的數據包括5項,以字典類型將其儲存,經過urlencode()方法編碼之後直接加在登陸URL之後即可,所以最後向伺服器發送的請求(request)為:

 1 import urllib
 2 
 3 loginURL = 'http://202.118.250.131/lib/opacAction.do'
 4 queryString = urllib.urlencode({
 5             'method':'DoAjax',
 6             'dispatch':'login',
 7             'registerName':'',
 8             'rcardNo':'16S137028 0',
 9             'pwd':'******'
10         })
11 requestURL = self.loginURL + '?' + self.queryString

  得到請求URL之後就可以模擬登陸圖書館系統了,在模擬登陸的過程中需要用到前面講到的cookie,否則無法進行後續的訪問。在編代碼過程中,定義一個library類,使訪問過程變成一個面向對象的過程,可以根據需要實例化多個library對象,分別對多個實例進行操作。首先分析,該library類應該有一個初始化方法(__init__)以及一個獲取頁面的方法(getPage),在打開網頁是,應使用上文提到opener實例,自動捕獲並儲存cookie:

 

 1 import urllib
 2 import urllib2
 3 import cookielib
 4 import re
 5 
 6 class library:
 7     def __init__(self):
 8         self.loginURL='http://202.118.250.131/lib/opacAction.do'
 9         self.queryString = urllib.urlencode({
10             'method':'DoAjax',
11             'dispatch':'login',
12             'registerName':'',
13             'rcardNo':'16S137028 0',
14             'pwd':'******'
15         })
16         self.requestURL = self.loginURL + '?' + self.queryString
17         self.cookies=cookielib.CookieJar()
18         self.handler=urllib2.HTTPCookieProcessor(self.cookies)
19         self.opener=urllib2.build_opener(self.handler)
20     def getPage(self):
21         request1 = urllib2.Request(self.requestURL)
22         request2 = urllib2.Request(' http://202.118.250.131/lib/opacAction.do?method=init&seq=301 ')
23         result = self.opener.open(request1)
24         result = self.opener.open(request2)
25         return result.read()
26 
27 lib = library()
28 print lib.getPage()

 

  上述代碼中,先是進行登錄 result = self.opener.open(request1) ,登錄沒有異常,說明登錄過程不用檢查數據頭;然後再用此 self.opener 打開借閱查詢頁面
 http://202.118.250.131/lib/opacAction.do?method=init&seq=301 ,所以這段代碼將列印借閱查詢界面的HTML代碼,下圖是部分列印結果:

                

獲取借閱信息:

  抓取了頁面信息之後,接下來就是根據自己的需要匹配、儲存信息了。在匹配頁面信息時,這裡用的是正則表達式的方式進行匹配,正則表達式的支持由Python的Re模塊提供支持,關於如何使用正則表達式,可以參考這裡:Python正則表達式指南

  使用Re模塊進行匹配時,往往先將正則表達式字元串編譯(compile)成一個Pattern實例,再利用Re模塊中的re.findall(pattern , string),將字元串string中和正則表達式匹配的數據以列表的形式返回。如果在pattern中有超過一個組(group),則返回的結果將是一個元組列表,如此正則表達式: <table.*?id="tb.*?width="50%"><font size=2>(.*?)</font>.*?<tr>.*?<tr>.*?<font size=2>(.*?)</font>.*?<font size=2>(.*?)</font>.*?</TABLE> ,式中,每一個 (.*?) 代表一個組,即此式中有3個組,則匹配時,返回一個元組列表,其中每一個元組又有3個數據。

  在library類中,定義一個獲取信息的方法(getInformation),以通過正則表達式匹配的方式獲取所需數據:

1 def getInformation(self):
2         page = self.getPage()
3         pattern = re.compile('<table.*?id="tb.*?width="50%"><font size=2>(.*?)</font>.*?<tr>.*?<tr>.*?'+
4                         '<font size=2>(.*?)</font>.*?<font size=2>(.*?)</font>.*?</TABLE>',re.S)
5         items = re.findall(pattern,page)

  獲取所需數據之後,接下來就是將數據寫入文本文件(txt)儲存,以讀寫模式(W+)打開一個文件(library.txt),然後通過write()方法將數據一條一條的寫入文件。不過,在信息寫入之前,需要對抓取到的信息做一些小處理,剛纔說過了,findall()方法返回的是一個元組列表,即[[a,b,c],[d,e,f],[g,h,i]]的形式,write()方法是不能對元組進行操作的,所以需要手動將元組翻譯成一條條字元串,再保存到一個列表裡,通過遍歷將每條字元串寫入文件:

 1 def getInformation(self):
 2         page = self.getPage()
 3         pattern = re.compile('<table.*?id="tb.*?width="50%"><font size=2>(.*?)</font>.*?<tr>.*?<tr>.*?'+
 4                         '<font size=2>(.*?)</font>.*?<font size=2>(.*?)</font>.*?</TABLE>',re.S)
 5         items = re.findall(pattern,page)
 6 
 7         contents = []
 8         for item in items:
 9             content = item[0]+'    from   '+item[1]+'   to   '+item[2]+'\n'
10             contents.append(content)
11         self.writeData(contents)
12 def writeData(self,contents):
13         file = open('libraryBooks.txt','w+')
14         for content in contents:
15             file.write(content)
16         file.close()

  至此,整個爬蟲就算完成了,下麵貼上完整代碼:

大功告成:  

 1 __author__='Victor'
 2 #_*_ coding:'utf-8' _*_
 3 import urllib
 4 import urllib2
 5 import cookielib
 6 import re
 7 
 8 class library:
 9     def __init__(self):
10         self.loginURL='http://202.118.250.131/lib/opacAction.do'
11         self.queryString = urllib.urlencode({
12             'method':'DoAjax',
13             'dispatch':'login',
14             'registerName':'',
15             'rcardNo':'16S137028 0',
16             'pwd':'******'
17         })
18         self.requestURL = self.loginURL + '?' + self.queryString
19         self.cookies=cookielib.CookieJar()
20         self.handler=urllib2.HTTPCookieProcessor(self.cookies)
21         self.opener=urllib2.build_opener(self.handler)
22     def getPage(self):
23         request1 = urllib2.Request(self.requestURL)
24         request2 = urllib2.Request('http://202.118.250.131/lib/opacAction.do?method=init&seq=301')
25         result = self.opener.open(request1)
26         result = self.opener.open(request2)
27         return result.read()
28     def getInformation(self):
29         page = self.getPage()
30         pattern = re.compile('<table.*?id="tb.*?width="50%"><font size=2>(.*?)</font>.*?<tr>.*?<tr>.*?'+
31                         '<font size=2>(.*?)</font>.*?<font size=2>(.*?)</font>.*?</TABLE>',re.S)
32         items = re.findall(pattern,page)
33 
34         contents = []
35         for item in items:
36             content = item[0]+'    from   '+item[1]+'   to   '+item[2]+'\n'
37             contents.append(content)
38         self.writeData(contents)
39     def writeData(self,contents):
40         file = open('libraryBooks.txt','w+')
41         for content in contents:
42             file.write(content)
43         file.close()
44 
45 lib = library()
46 lib.getInformation()

  下麵就是抓到的借閱信息,不得不說效果不怎麼樣,不過還是湊合著看把:

                

 

 

原創作品,引用請表明出處:Python爬蟲實戰---抓取圖書館借閱信息

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ...
  • 前段時間寫了幾個PHP的腳本,但是因為腳本的項目是基於composer安裝的,給別人使用的時候不太方便,就希望能夠打包成一個能直接使用的文件。 搜索了一下,發現可以使用phar打包。 假設我們有如下一個項目 入口文件是index.php,打包前的命令如下: 再添加打包腳本之前,需要先修改一下PHP的 ...
  • 緩存的意思是中間存儲,相當於中轉站,積累一定的貨物,再往目的地運送。如果沒有中轉站,就會出現一件一件的運送,耗費大量的人力物力。 緩存的基類是:Buffer 緩存的基本子類有:Char/Byte/Short/Int/Long/Float/Double + Buffer 緩存一般用一個數組做存儲,ar ...
  • 實在搞不定博客園的排版,排版更佳的版本在:https://zhuanlan.zhihu.com/p/24162430 Life is short, you need Python 人生苦短,我用Python -- Bruce Eckel 5.1 Python簡介 本章將介紹Python的最基本語法, ...
  • 這裡使用了 python 的基本代碼實現了 Linux 系統下 wc 命令程式的基本功能。 ...
  • Maven的一個核心的作用就是管理項目的依賴,引入我們所需的各種jar包等。為了能自動化的解析任何一個Java構件,Maven必須將這些Jar包或者其他資源進行唯一標識,這是管理項目的依賴的基礎,也就是我們要說的坐標。包括我們自己開發的項目,也是要通過坐標進行唯一標識的,這樣才能才其它項目中進行依賴 ...
  • MCSDK簡介 BIOS MCSDK是為TI的高性能多核DSP提供的一套組件,包括: SYS/BIOS實時操作系統 Chip support libraries, drivers, and basic platform utilities Run-time libraries (OpenMP, Op ...
  • 線程的記憶體結構圖 一、主記憶體與工作記憶體 1.Java記憶體模型的主要目標是定義程式中各個變數的訪問規則。此處的變數與Java編程時所說的變數不一樣,指包括了實例欄位、靜態欄位和構成數組對象的元素,但是不包括局部變數與方法參數,因為它們是線程私有的,不會被共用。 2.Java記憶體模型中規定了所有的變數都 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...