子沐教你Scrapy——淺談Python爬蟲

本章工作任務

  • 任務1:爲什麼學習Python爬蟲

  • 任務2:什麼是爬蟲

  • 任務3:urllib的應用

  • 任務4:cookie實際使用

  • 任務5:正則表達式

本章技能目標及重難點

編號 技能點描述 級別
1 爲什麼學習爬蟲
2 什麼是爬蟲 ★★
3 urllib的應用 ★★★
4 cookie實際使用 ★★
5 正則表達式 ★★

注: "★"理解級別 "★★"掌握級別 "★★★"應用級別

本章學習目標

本章開始學習Python爬蟲,需要同學們理解爲什麼使用爬蟲,它的概念、特點。最主要的是需要大家學會如何使用基礎的爬蟲庫。

本章學習建議

本章適合有Python基礎的學員學習。

本章內容(學習活動)

1.1 爲什麼學習Python爬蟲?

現在信息更新的非常快速,又迎來了大數據的時代, 各行各業如果不與時俱進,都將面臨優勝劣汰,知識是不斷的更新的,只有一技之長,才能立於不敗之地。

網絡爬蟲,即 Web Spider,是一個很形象的名字。目前爬蟲開發的語言的主要是 Python,本課程結合幾個小的爬蟲案例,幫助學員更好的學習爬蟲開發。

那麼爲什麼我們要學習Python爬蟲呢?

1.1.1 Python語言的流行程度

現在全世界大約有幾百萬以上的Python語言的用戶,大家可以看一下以下圖片:

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

IEEE發佈2016 年度編程語言排行榜

圖1-1爲2016 年 Spectrum評選出的排名前十的編程語言,Spectrum 的“交互式編程語言排行”讓用戶可以根據自己的喜好調整不同評價指標所佔的權重,從而得到所需的排名。從該圖可以看出Python在IEEE的會員用戶語言使用中排名第三。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

TIOBE 2016年1月編程語言排行榜

圖1-2 TIOBE的數據就更能說明Python語言的地位,TIOBE 編程語言社區排行榜是編程語言流行趨勢的一個指標,每月更新,這份排行榜排名基於互聯網上有經驗的程序員、 課程和第三方廠商的數量。排名使用著名的搜索引擎(諸如 Google、MSN、Yahoo!、Wikipedia、YouTube 以及 Baidu 等)進行計算。而Python語言排名第五。並趨於日益增長趨勢。

1.1.2爬蟲的強大作用

Ø 爬取數

Ø 分析並推送

Ø 資源批量下載

Ø 數據監控

Ø 社會計算方面的統計和預測

Ø 機器學習

Ø 網絡爬蟲

Ø 建立機器翻譯的語料庫

Ø 搭建大數據的數據庫

1.1.3爲什麼Python適合寫爬蟲

1.抓取網頁本身的接口

相比與其他靜態編程語言,如java,c#,C++,python抓取網頁文檔的接口更簡潔;相比其他動態腳本語言,如perl,shell,python的urllib2包提供了較爲完整的訪問網頁文檔的API。(當然ruby也是很好的選擇)

此外,抓取網頁有時候需要模擬瀏覽器的行爲,很多網站對於生硬的爬蟲抓取都是封殺的。這是我們需要模擬user agent的行爲構造合適的請求,譬如模擬用戶登陸、模擬session/cookie的存儲和設置。在python裏都有非常優秀的第三方包幫你搞定,如Requests,mechanize

2.網頁抓取後的處理

抓取的網頁通常需要處理,比如過濾html標籤,提取文本等。python的beautifulsoap提供了簡潔的文檔處理功能,能用極短的代碼完成大部分文檔的處理。

其實以上功能很多語言和工具都能做,但是用python能夠幹得最快,最乾淨。Life is short, u need python.

接下來我們來介紹什麼是爬蟲。

1.2 什麼是爬蟲?

1.2.1 爬蟲的由來

隨着網絡的迅速發展,萬維網成爲大量信息的載體,如何有效地提取並利用這些信息成爲一個巨大的挑戰。搜索引擎(Search Engine),例如傳統的通用搜索引擎AltaVista,Yahoo!和Google等,作爲一個輔助人們檢索信息的工具成爲用戶訪問萬維網的入口和指南。但是,這些通用性搜索引擎也存在着一定的侷限性,如:

(1)不同領域、不同背景的用戶往往具有不同的檢索目的和需求,通用搜索引擎所返回的結果包含大量用戶不關心的網頁。

(2)通用搜索引擎的目標是儘可能大的網絡覆蓋率,有限的搜索引擎服務器資源與無限的網絡數據資源之間的矛盾將進一步加深。

(3)萬維網數據形式的豐富和網絡技術的不斷髮展,圖片、數據庫、音頻、視頻多媒體等不同數據大量出現,通用搜索引擎往往對這些信息含量密集且具有一定結構的數據無能爲力,不能很好地發現和獲取。

(4)通用搜索引擎大多提供基於關鍵字的檢索,難以支持根據語義信息提出的查詢。

爲了解決上述問題,定向抓取相關網頁資源的聚焦爬蟲應運而生。聚焦爬蟲是一個自動下載網頁的程序,它根據既定的抓取目標,有選擇的訪問萬維網上的網頁與相關的鏈接,獲取所需要的信息。與通用爬蟲(general purpose web crawler)不同,聚焦爬蟲並不追求大的覆蓋,而將目標定爲抓取與某一特定主題內容相關的網頁,爲面向主題的用戶查詢準備數據資源。

網絡爬蟲是一個自動提取網頁的程序,它爲搜索引擎從萬維網上下載網頁,是搜索引擎的重要組成。傳統爬蟲從一個或若干初始網頁的URL開始,獲得初始網頁上的URL,在抓取網頁的過程中,不斷從當前頁面上抽取新的URL放入隊列,直到滿足系統的一定停止條件。聚焦爬蟲的工作流程較爲複雜,需要根據一定的網頁分析算法過濾與主題無關的鏈接,保留有用的鏈接並將其放入等待抓取的URL隊列。然後,它將根據一定的搜索策略從隊列中選擇下一步要抓取的網頁URL,並重覆上述過程,直到達到系統的某一條件時停止。另外,所有被爬蟲抓取的網頁將會被系統存貯,進行一定的分析、過濾,並建立索引,以便之後的查詢和檢索;對於聚焦爬蟲來說,這一過程所得到的分析結果還可能對以後的抓取過程給出反饋和指導。聚集爬蟲的邏輯結構圖,如圖1-3所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

聚集爬蟲的邏輯結構圖

相對於通用網絡爬蟲,聚焦爬蟲還需要解決三個主要問題:

(1) 對抓取目標的描述或定義;

(2) 對網頁或數據的分析與過濾;

(3) 對URL的搜索策略。

1.2.2 爬蟲的定義

網絡爬蟲,即Web Spider,是一個很形象的名字。把互聯網比喻成一個蜘蛛網,那麼Spider就是在網上爬來爬去的蜘蛛。網絡蜘蛛是通過網頁的鏈接地址來尋找網頁的。

從網站某一個頁面(通常是首頁)開始,讀取網頁的內容,找到在網頁中的其它鏈接地址,然後通過這些鏈接地址尋找下一個網頁,這樣一直循環下去,直到把這個網站所有的網頁都抓取完爲止。

如果把整個互聯網當成一個網站,那麼網絡蜘蛛就可以用這個原理把互聯網上所有的網頁都抓取下來。這樣看來,網絡爬蟲就是一個爬行程序,一個抓取網頁的程序。網絡爬蟲的基本操作是抓取網頁。

1.2.3 爬蟲的工作過程

在用戶瀏覽網頁的過程中,我們可能會看到許多好看的圖片,比如 http://image.baidu.com/ ,我們會看到幾張的圖片以及百度搜索框,這個過程其實就是用戶輸入網址之後,經過 DNS 服務器,找到服務器主機,向服務器發出一個請求,服務器經過解析之後,發送給用戶的瀏覽器 HTML、JS、CSS 等文件,瀏覽器解析出來,用戶便可以看到形形色色的圖片了。

因此,用戶看到的網頁實質是由 HTML 代碼構成的,爬蟲爬來的便是這些內容,通過分析和過濾這些 HTML 代碼,實現對圖片、文字等資源的獲取。

想象你是一隻蜘蛛,現在你被放到了互聯“網”上。那麼,你需要把所有的網頁都看一遍。怎麼辦呢?沒問題呀,你就隨便從某個地方開始,比如說人民日報的首頁,我們用$表示吧。

在人民日報的首頁,你看到那個頁面引向的各種鏈接。於是你很開心地從爬到了“國內新聞”那個頁面。太好了,這樣你就已經爬完了倆頁面(首頁和國內新聞)!暫且不用管爬下來的頁面怎麼處理的,你就想象你把這個頁面完完整整抄成了個html放到了你身上。

突然你發現, 在國內新聞這個頁面上,有一個鏈接鏈回“首頁”。作爲一隻聰明的蜘蛛,你肯定知道你不用爬回去的吧,因爲你已經看過了啊。所以,你需要用你的腦子,存下你已經看過的頁面地址。這樣,每次看到一個可能需要爬的新鏈接,你就先查查你腦子裏是不是已經去過這個頁面地址。如果去過,那就別去了。

好的,理論上如果所有的頁面可以從首頁達到的話,那麼可以證明你一定可以爬完所有的網頁。但是爲什麼爬蟲事實上是個非常複雜的東西——搜索引擎公司通常有一整個團隊來維護和開發。

因爲就現在網絡資源的大小而言,即使很大的搜索引擎也只能獲取網絡上可得到資源的一小部分。2001年由勞倫斯河蓋爾斯共同做的一項研究指出,沒有一個搜索引擎抓取的內容達到網絡的16%。網絡爬蟲通常僅僅下載網頁內容的一部分,並且不管你的帶寬有多大,只要你的機器下載網頁的速度是瓶頸的話,那麼你只有加快這個速度。那麼我們就需要提高效率——使用多線程。這就是我們爲什麼使用Scrapy的原因。

1.3Python爬蟲入門

1.3.1 Urlib庫的基本使用

1.分分鐘扒一個網頁下來

怎樣扒網頁呢?其實就是根據URL來獲取它的網頁信息,雖然我們在瀏覽器中看到的是一幅幅優美的畫面,但是其實是由瀏覽器解釋才呈現出來的,實質它是一段 HTML 代碼,加 JS、CSS,如果把網頁比作一個人,那麼 HTML 便是他的骨架,JS 便是他的肌肉,CSS 便是它的衣服。所以最重要的部分是存在於 HTML 中的,下面我們就寫個例子來扒一個網頁下來。代碼如圖1-4所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

爬取百度的基礎代碼

是的你沒看錯,真正的程序就兩行,把它保存成 demo.py,進入該文件的目錄,執行如下命令查看運行結果,感受一下,使用命令python demo.py,運行效果如圖1-5所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

爬取百度代碼運行效果

看,這個網頁的源碼已經被我們扒下來了,是不是很酸爽?

2. 分析扒網頁的方法

那麼我們來分析這兩行代碼,第一行

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

首先我們調用的是 urllib2 庫裏面的 urlopen 方法,傳入一個 URL,這個網址是百度首頁,協議是 HTTP 協議,當然你也可以把 HTTP 換做 FTP,FILE,HTTPS 等等,只是代表了一種訪問控制協議,urlopen 一般接受三個參數,它的參數如下:

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

第一個參數 url 即爲 URL,第二個參數 data 是訪問 URL 時要傳送的數據,第三個 timeout是設置超時時間。

第二三個參數是可以不傳送的,data 默認爲空 None,timeout 默認爲 socket._GLOBAL_DEFAULT_TIMEOUT

第一個參數 URL 是必須要傳送的,在這個例子裏面我們傳送了百度的 URL,執行 urlopen 方法之後,返回一個 response 對象,返回信息便保存在這裏面。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

response 對象有一個 read 方法,可以返回獲取到的網頁內容。

如果不加 read 直接打印會是什麼?答案如下:

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

直接打印出了該對象的描述,所以記得一定要加 read 方法,否則它不出來內容可就不怪我咯!

3. 構造Request

其實上面的 urlopen 參數可以傳入一個 request 請求,它其實就是一個 Request 類的實例,構造時需要傳入 Url,Data 等等的內容。比如上面的兩行代碼,我們可以這麼改寫

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

運行結果是完全一樣的,只不過中間多了一個 request 對象,推薦大家這麼寫,因爲在構建請求時還需要加入好多內容,通過構建一個 request,服務器響應請求得到應答,這樣顯得邏輯上清晰明確。

4. POST 和 GET 數據傳送

上面的程序演示了最基本的網頁抓取,不過,現在大多數網站都是動態網頁,需要你動態地傳遞參數給它,它做出對應的響應。所以,在訪問時,我們需要傳遞數據給它。最常見的情況是什麼?對了,就是登錄註冊的時候呀。

把數據用戶名和密碼傳送到一個 URL,然後你得到服務器處理之後的響應,這個該怎麼辦?下面讓我來爲小夥伴們揭曉吧!

數據傳送分爲 POST 和 GET 兩種方式,兩種方式有什麼區別呢?

最重要的區別是 GET 方式是直接以鏈接形式訪問,鏈接中包含了所有的參數,當然如果包含了密碼的話是一種不安全的選擇,不過你可以直觀地看到自己提交了什麼內容。POST 則不會在網址上顯示所有的參數,不過如果你想直接查看提交了什麼就不太方便了,大家可以酌情選擇。

POST 方式:

上面我們說了 data 參數是幹嘛的?對了,它就是用在這裏的,我們傳送的數據就是這個參數data,下面演示一下 POST 方式,代碼如圖1-6所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

POST方式代碼

我們引入了 urllib 庫,現在我們模擬登陸 CSDN,當然上述代碼可能登陸

注意上面字典的定義方式還有一種,寫法是等價的,如圖1-7所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

POST方式代碼

以上方法便實現了 POST 方式的傳送

GET 方式:

至於 GET 方式我們可以直接把參數寫到網址上面,直接構建一個帶參數的 URL 出來即可,如圖1-8所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

GET方式代碼

你可以 print geturl,打印輸出一下 url,發現其實就是原來的 url 加?然後加編碼後的參數

http://passport.csdn.net/account/login?username=1016903103%40qq.com&password=XXXX

和我們平常 GET 訪問方式一模一樣,這樣就實現了數據的 GET 方式傳送。

1.3.2 Urlib庫的高級用法

1.設置 Headers

有些網站不會同意程序直接用上面的方式進行訪問,如果識別有問題,那麼站點根本不會響應,所以爲了完全模擬瀏覽器的工作,我們需要設置一些 Headers 的屬性。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

調試操作

首先,打開我們的瀏覽器,調試瀏覽器 F12,我用的是 Chrome,打開網絡監聽,示意如下,比如知乎,點登錄之後,我們會發現登陸之後界面都變化了,出現一個新的界面,實質上這個頁面包含了許許多多的內容,這些內容也不是一次性就加載完成的,實質上是執行了好多次請求,一般是首先請求HTML文件,然後加載 JS,CSS 等等,經過多次請求之後,網頁的骨架和肌肉全了,整個網頁的效果也就出來了,操作效果如圖1-9所示。

拆分這些請求,我們只看一第一個請求,你可以看到,有個 Request URL,還有 headers,下面便是 response,圖片顯示得不全,小夥伴們可以親身實驗一下。那麼這個頭中包含了許許多多是信息,有文件編碼啦,壓縮方式啦,請求的 agent 啦等等。

其中,agent 就是請求的身份,如果沒有寫入請求身份,那麼服務器不一定會響應,所以可以在 headers 中設置agent,例如下面的例子,這個例子只是說明了怎樣設置的 headers,小夥伴們看一下設置格式就好,如圖1-10所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

設置header代碼

這樣,我們設置了一個 headers,在構建 request 時傳入,在請求時,就加入了 headers 傳送,服務器若識別了是瀏覽器發來的請求,就會得到響應。

另外,我們還有對付”反盜鏈”的方式,對付防盜鏈,服務器會識別 headers 中的 referer 是不是它自己,如果不是,有的服務器不會響應,所以我們還可以在 headers 中加入 referer

例如我們可以構建下面的headers,代碼如圖1-11所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

設置referer代碼

同上面的方法,在傳送請求時把 headers 傳入 Request 參數裏,這樣就能應付防盜鏈了。

另外 headers 的一些屬性,下面的需要特別注意一下:

Ø User-Agent : 有些服務器或 Proxy 會通過該值來判斷是否是瀏覽器發出的請求

Ø Content-Type : 在使用 REST 接口時,服務器會檢查該值,用來確定 HTTP Body 中的內容該怎樣解析。

Ø application/xml : 在 XML RPC,如 RESTful/SOAP 調用時使用

Ø application/json : 在 JSON RPC 調用時使用

Ø application/x-www-form-urlencoded : 瀏覽器提交 Web 表單時使用

在使用服務器提供的 RESTful 或 SOAP 服務時, Content-Type 設置錯誤會導致服務器拒絕服務,其他的有必要的可以審查瀏覽器的 headers 內容,在構建時寫入同樣的數據即可。

2. Proxy(代理)的設置

urllib2 默認會使用環境變量 http_proxy 來設置 HTTP Proxy。假如一個網站它會檢測某一段時間某個IP 的訪問次數,如果訪問次數過多,它會禁止你的訪問。所以你可以設置一些代理服務器來幫助你做工作,每隔一段時間換一個代理,網站君都不知道是誰在搗鬼了,這酸爽!

下面一段代碼說明了代理的設置用法,如圖1-12所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

代理設置代碼

3.Timeout設置

上一節已經說過 urlopen 方法了,第三個參數就是 timeout 的設置,可以設置等待多久超時,爲了解決一些網站實在響應過慢而造成的影響。

例如下面的代碼,如果第二個參數 data 爲空那麼要特別指定是 timeout 是多少,寫明形參,如果data已經傳入,則不必聲明,代碼如圖1-13和1-14所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

Timeout代碼設置

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

Timeout代碼設置

4.使用 HTTP 的 PUT 和 DELETE 方法

http 協議有六種請求方法,get,head,put,delete,post,options,我們有時候需要用到 PUT 方式或者 DELETE 方式請求。

PUT:這個方法比較少見。HTML 表單也不支持這個。本質上來講, PUT 和 POST 極爲相似,都是向服務器發送數據,但它們之間有一個重要區別,PUT 通常指定了資源的存放位置,而 POST 則沒有,POST 的數據存放位置由服務器自己決定。

DELETE:刪除某一個資源。基本上這個也很少見,不過還是有一些地方比如amazon的S3雲服務裏面就用的這個方法來刪除資源。 如果要使用 HTTP PUT 和 DELETE ,只能使用比較低層的 httplib 庫。雖然如此,我們還是能通過下面的方式,使 urllib2 能夠發出 PUT 或DELETE 的請求,不過用的次數的確是少,在這裏提一下。

操作代碼,如圖1-14所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

使用HTTP的PUT和DELETE方法

5.使用 DebugLog

可以通過下面的方法把 Debug Log 打開,這樣收發包的內容就會在屏幕上打印出來,方便調試,這個也不太常用,僅提一下。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

使用DebugLog

1.3.3 URLError異常處理

大家好,本節在這裏主要說的urlerror異常處理,是還有 HTTPError,以及對它們的一些處理。

1.URLError

首先解釋下 URLError 可能產生的原因:

Ø 網絡無連接,即本機無法上網

Ø 連接不到特定的服務器

Ø 服務器不存在

在代碼中,我們需要用 try-except 語句來包圍並捕獲相應的異常。下面是一個例子,先感受下它的風騷,代碼如圖1-16所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

使用try-except

我們利用了 urlopen 方法訪問了一個不存在的網址,運行結果如下圖1-17所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

異常報錯

它說明了錯誤代號是11004,錯誤原因是 getaddrinfo failed。

2.HTTPError

HTTPError 是 URLError 的子類,在你利用 urlopen 方法發出一個請求時,服務器上都會對應一個應答對象 response,其中它包含一個數字”狀態碼”。舉個例子,假如 response 是一個”重定向”,需定位到別的地址獲取文檔,urllib2 將對此進行處理。

其他不能處理的,urlopen 會產生一個 HTTPError,對應相應的狀態嗎,HTTP 狀態碼錶示HTTP 協議所返回的響應的狀態。下面將狀態碼歸結如下圖1-18所示:

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

HTTP 狀態碼

HTTPError 實例產生後會有一個 code 屬性,這就是是服務器發送的相關錯誤號。 因爲 urllib2 可以爲你處理重定向,也就是 3 開頭的代號可以被處理,並且 100-299 範圍的號碼指示成功,所以你只能看到 400-599 的錯誤號碼。

下面我們寫一個例子來感受一下,捕獲的異常是 HTTPError,它會帶有一個 code 屬性,就是錯誤代號,另外我們又打印了 reason 屬性,這是它的父類 URLError 的屬性,代碼如圖1-19所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

參考代碼

運行結果如下圖1-20所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

參考代碼運行效果

錯誤代號是 403,錯誤原因是 Forbidden,說明服務器禁止訪問。

我們知道,HTTPError 的父類是 URLError,根據編程經驗,父類的異常應當寫到子類異常的後面,如果子類捕獲不到,那麼可以捕獲父類的異常,所以上述的代碼可以這麼改寫,如圖1-21所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

參考代碼改進

首先對異常的屬性進行判斷,以免出現屬性輸出報錯的現象。

以上,就是對 URLError 和 HTTPError 的相關介紹,以及相應的錯誤處理辦法。

1.3.4Cookie的使用

大家好哈,上一節我們研究了一下爬蟲的異常處理問題,那麼接下來我們一起來看一下 Cookie 的使用。

爲什麼要使用 Cookie 呢?

Cookie,指某些網站爲了辨別用戶身份、進行 session 跟蹤而儲存在用戶本地終端上的數據(通常經過加密)

比如說有些網站需要登錄後才能訪問某個頁面,在登錄之前,你想抓取某個頁面內容是不允許的。那麼我們可以利用 Urllib2 庫保存我們登錄的 Cookie,然後再抓取其他頁面就達到目的了。

在此之前呢,我們必須先介紹一個 opener 的概念。

1. Opener

當你獲取一個 URL 你使用一個 opener(一個 urllib2.OpenerDirector 的實例)。在前面,我們都是使用的默認的 opener,也就是 urlopen。它是一個特殊的 opener,可以理解成opener 的一個特殊實例,傳入的參數僅僅是 url,data,timeout。

如果我們需要用到 Cookie,只用這個 opener 是不能達到目的的,所以我們需要創建更一般的opener 來實現對 Cookie 的設置。

2. Cookielib

cookielib 模塊的主要作用是提供可存儲 cookie 的對象,以便於與 urllib2 模塊配合使用來訪問 Internet 資源。Cookielib 模塊非常強大,我們可以利用本模塊的 CookieJar 類的對象來捕獲 cookie 並在後續連接請求時重新發送,比如可以實現模擬登錄功能。該模塊主要的對象有 CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。

它們的關係:CookieJar —-派生—->FileCookieJar —-派生—–>MozillaCookieJar 和LWPCookieJar

3. 獲取 Cookie 保存到變量

首先,我們先利用 CookieJar 對象實現獲取 cookie 的功能,存儲到變量中,參考代碼如下,如圖1-22所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

CookielJar操作代碼

我們使用以上方法將 cookie 保存到變量中,然後打印出了 cookie 中的值,運行結果如下,如圖1-23所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

運行結果

4. 保存 Cookie 到文件

在上面的方法中,我們將 cookie 保存到了 cookie 這個變量中,如果我們想將 cookie 保存到文件中該怎麼做呢?這時,我們就要用到FileCookieJar 這個對象了,在這裏我們使用它的子類 MozillaCookieJar 來實現 Cookie的保存,實現代碼如圖1-24所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

4.保存 Cookie 到文件

由此可見,ignore_discard 的意思是即使 cookies 將被丟棄也將它保存下來,ignore_expires 的意思是如果在該文件中 cookies 已經存在,則覆蓋原文件寫入,在這裏,我們將這兩個全部設置爲 True。運行之後,cookies 將被保存到 cookie.txt文件中,我們查看一下內容,如下圖1-25所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

cookie文件內容

5. 從文件中獲取 Cookie 並訪問

那麼我們已經做到把 Cookie 保存到文件中了,如果以後想使用,可以利用下面的方法來讀取cookie 並訪問網站,感受一下,代碼如圖1-26所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

從文件讀取cookie再訪問

設想,如果我們的 cookie.txt 文件中保存的是某個人登錄百度的 cookie,那麼我們提取出這個 cookie 文件內容,就可以用以上方法模擬這個人的賬號登錄百度。

6. 利用 cookie 模擬網站登錄

下面我們以我們學校的教育系統爲例,利用 cookie 實現模擬登錄,並將 cookie 信息保存到文本文件中,來感受一下 cookie 大法吧!實現代碼如下圖1-27所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

從文件讀取cookie再訪問

以上程序的原理如下

創建一個帶有 cookie 的 opener,在訪問登錄的 URL 時,將登錄後的 cookie 保存下來,然後利用這個 cookie 來訪問其他網址。

如登錄之後才能查看的成績查詢呀,本學期課表呀等等網址,模擬登錄就這麼實現啦,是不是很酷炫?

好,小夥伴們要加油哦!我們現在可以順利獲取網站信息了,接下來就是把網站裏面有效內容提取出來,下一節我們去會會正則表達式!

1.3.5正則表達式

在前面我們已經搞定了怎樣獲取頁面的內容,不過還差一步,這麼多雜亂的代碼夾雜文字我們怎樣把它提取出來整理呢?下面就開始介紹一個十分強大的工具,正則表達式!

1. 瞭解正則表達式

正則表達式是對字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個“規則字符串”,這個“規則字符串”用來表達對字符串的一種過濾邏輯。 正則表達式是用來匹配字符串非常強大的工具,在其他編程語言中同樣有正則表達式的概念,Python同樣不例外,利用了正則表達式,我們想要從返回的頁面內容提取出我們想要的內容就易如反掌了。

正則表達式的大致匹配過程是:

1) 依次拿出表達式和文本中的字符比較,

2) 如果每一個得到字符都能匹配,則匹配9功;一旦有匹配不成功的字符則匹配失敗。

3) 如果表達式中有量詞或邊界,這個過程會稍微有一些不同。

2. 正則表達式的語法規則

下面是 Python 中正則表達式的一些匹配規則,如圖1-28所示

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

正則表達式

3. 數量詞的貪婪模式與非貪婪模式

正則表達式通常用於在文本中查找匹配的字符串。Python 裏數量詞默認是貪婪的(在少數語言裏也可能是默認非貪婪),總是嘗試匹配儘可能多的字符;非貪婪的則相反,總是嘗試匹配儘可能少的字符。例如:正則表達式 ”ab” 如果用於查找 ”abbbc”,將找到 ”abbb”。而如果使用非貪婪的數量詞 ”ab?”,將找到 ”a”。

注:我們一般使用非貪婪模式來提取。

4. 反斜槓問題

與大多數編程語言相同,正則表達式裏使用”\”作爲轉義字符,這就可能造成反斜槓困擾。假如你需要匹配文本中的字符”\”,那麼使用編程語言表示的正則表達式裏將需要4個反斜槓”\\”:前兩個和後兩個分別用於在編程語言裏轉義成反斜槓,轉換成兩個反斜槓後再在正則表達式裏轉義成一個反斜槓。

Python 裏的原生字符串很好地解決了這個問題,這個例子中的正則表達式可以使用 r”\” 表示。同樣,匹配一個數字的 ”\d” 可以寫成 r”\d”。有了原生字符串,媽媽也不用擔心是不是漏寫了反斜槓,寫出來的表達式也更直觀勒。

5. Python Re 模塊

Python 自帶了 re 模塊,它提供了對正則表達式的支持。主要用到的方法列舉如下:

1.返回pattern對象

re.compile(string[,flag])

2.以下爲匹配所用函數

re.match(pattern, string[, flags])

re.search(pattern, string[, flags])

re.split(pattern, string[, maxsplit])

re.findall(pattern, string[, flags])

re.finditer(pattern, string[, flags])

re.sub(pattern, repl, string[, count])

re.subn(pattern, repl, string[, count])

在介紹這幾個方法之前,我們先來介紹一下 pattern 的概念,pattern 可以理解爲一個匹配模式,那麼我們怎麼獲得這個匹配模式呢?很簡單,我們需要利用 re.compile 方法就可以。例如

pattern = re.compile(r'hello')

在參數中我們傳入了原生字符串對象,通過 compile 方法編譯生成一個 pattern 對象,然後我們利用這個對象來進行進一步的匹配。

另外大家可能注意到了另一個參數 flags,在這裏解釋一下這個參數的含義:

參數 flag 是匹配模式,取值可以使用按位或運算符’|’表示同時生效,比如 re.I | re.M。

可選值有:

Ø re.I(全拼:IGNORECASE): 忽略大小寫(括號內是完整寫法,下同)

Ø re.M(全拼:MULTILINE): 多行模式,改變'^'和'$'的行爲(參見上圖)

Ø re.S(全拼:DOTALL): 點任意匹配模式,改變'.'的行爲

Ø re.L(全拼:LOCALE): 使預定字符類 \w \W \b \B \s \S 取決於當前區域設定

Ø re.U(全拼:UNICODE): 使預定字符類 \w \W \b \B \s \S \d \D 取決於unicode定義的字符屬性

Ø re.X(全拼:VERBOSE): 詳細模式。這個模式下正則表達式可以是多行,忽略空白字符,並可以加入註釋。

在剛纔所說的另外幾個方法例如 re.match 裏我們就需要用到這個 pattern 了,下面我們一一介紹。

(1) re.match(pattern, string[, flags])

這個方法將會從 string(我們要匹配的字符串)的開頭開始,嘗試匹配 pattern,一直向後匹配,如果遇到無法匹配的字符,立即返回 None,如果匹配未結束已經到達 string 的末尾,也會返回 None。兩個結果均表示匹配失敗,否則匹配 pattern 成功,同時匹配終止,不再對string 向後匹配。下面我們通過一個例子理解一下。如圖1-29所示

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

match應用代碼

運行結果,如圖1-30所示

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

match代碼運行結果

匹配分析

1) 第一個匹配,pattern 正則表達式爲 ’hello’,我們匹配的目標字符串 string 也爲hello,從頭至尾完全匹配,匹配成功。

2) 第二個匹配,string 爲 helloo CQC,從 string 頭開始匹配 pattern 完全可以匹配,pattern 匹配結束,同時匹配終止,後面的 o CQC 不再匹配,返回匹配成功的信息。

3) 第三個匹配,string爲helo CQC,從 string 頭開始匹配 pattern,發現到 ‘o’ 時無法完成匹配,匹配終止,返回 None

4) 第四個匹配,同第二個匹配原理,即使遇到了空格符也不會受影響。

我們還看到最後打印出了 result.group(),這個是什麼意思呢?下面我們說一下關於 match 對象的的屬性和方法 Match 對象是一次匹配的結果,包含了很多關於此次匹配的信息,可以使用 Match 提供的可讀屬性或方法來獲取這些信息,如圖1-31所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

match 對象的的屬性和方法

下面我們用一個例子來體會一下,代碼如圖1-32所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

match 對象的實際應用代碼

運行結果如圖1-33所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

match 對象代碼運行結果

(2) re.search(pattern, string[, flags])

search 方法與 match 方法極其類似,區別在於 match() 函數只檢測 re 是不是在 string的開始位置匹配,search() 會掃描整個 string 查找匹配,match()只有在0位置匹配成功的話纔有返回,如果不是開始位置匹配成功的話,match() 就返回 None。同樣,search 方法的返回對象同樣 match() 返回對象的方法和屬性。我們用一個例子感受一下,代碼如圖1-34所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

serach應用代碼

輸入出結果爲world。

(3) re.split(pattern, string[, flags])

按照能夠匹配的子串將 string 分割後返回列表。maxsplit 用於指定最大分割次數,不指定將全部分割。我們通過下面的例子感受一下。

import re

pattern = re.compile(r'\d+')

print re.split(pattern,'one1two2three3four4')

輸出結果爲:['one', 'two', 'three', 'four', '']

(4) re.findall(pattern, string[, flags])

搜索 string,以列表形式返回全部能匹配的子串。我們通過這個例子來感受一下。

import re

pattern = re.compile(r'\d+')

print re.findall(pattern,'one1two2three3four4')

輸出結果爲:['1', '2', '3', '4']

(5) re.finditer(pattern, string[, flags])

搜索 string,返回一個順序訪問每一個匹配結果(Match對象)的迭代器。我們通過下面的例子來感受一下。

import re

pattern = re.compile(r'\d+')

for m in re.finditer(pattern,'one1two2three3four4'):

print m.group(),

輸出結果爲:1 2 3 4

(6) re.sub(pattern, string[, flags])

使用 repl 替換 string 中每一個匹配的子串後返回替換後的字符串。 當 repl 是一個字符串時,可以使用 \id 或 \g、\g 引用分組,但不能使用編號0。 當 repl 是一個方法時,這個方法應當只接受一個參數(Match對象),並返回一個字符串用於替換(返回的字符串中不能再引用分組)。 count 用於指定最多替換次數,不指定時全部替換。

import re

pattern = re.compile(r'(\w+) (\w+)')

s = 'i say, hello world!'

print re.sub(pattern,r'\2 \1', s)

def func(m):

return m.group(1).title() + ' ' + m.group(2).title()

print re.sub(pattern,func, s)

輸出結果爲:

say i, world hello!

I Say, Hello World!

(7) re.subn(pattern, string[, flags])

返回 (sub(repl, string[, count]), 替換次數)。

import re

pattern = re.compile(r'(\w+) (\w+)')

s = 'i say, hello world!'

print re.subn(pattern,r'\2 \1', s)

def func(m):

return m.group(1).title() + ' ' + m.group(2).title()

print re.subn(pattern,func, s)

輸出結果爲:

('say i, world hello!', 2)

('I Say, Hello World!', 2)

(8) Python Re 模塊的另一種使用方式

在上面我們介紹了7個工具方法,例如 match,search 等等,不過調用方式都是 re.match,re.search 的方式,其實還有另外一種調用方式,可以通過 pattern.match,pattern.search 調用,這樣調用便不用將 pattern 作爲第一個參數傳入了,大家想怎樣調用皆可。

函數 API 列表,代碼如圖1-35所示。

跟我學系列,走進Scrapy爬蟲(一)淺談Python爬蟲

函數API列表

具體的調用方法不必詳說了,原理都類似,只是參數的變化不同。小夥伴們嘗試一下吧~

小夥伴們加油,即使這一節看得雲裏霧裏的也沒關係,接下來我們會通過一些實戰例子來幫助大家熟練掌握正則表達式的。


發佈了18 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章