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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...