天天看點

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

點選檢視第一章 點選檢視第二章

第3章

靜态網頁抓取

在網站設計中,純粹HTML格式的網頁通常被稱為靜态網頁,早期的網站一般都是由靜态網頁制作的。在網絡爬蟲中,靜态網頁的資料比較容易擷取,因為所有資料都呈現在網頁的 HTML代碼中。相對而言,使用AJAX動态加載網頁的資料不一定會出現在HTML代碼中,這就給爬蟲增加了困難。本章先從簡單的靜态網頁抓取開始介紹,第4章再介紹動态網頁抓取。

在靜态網頁抓取中,有一個強大的Requests庫能夠讓你輕易地發送HTTP請求,這個庫功能完善,而且操作非常簡單。本章首先介紹如何安裝Requests庫,然後介紹如何使用Requests庫擷取響應内容,最後可以通過定制Requests的一些參數來滿足我們的需求。

3.1 安裝Requests

Requests庫能通過pip安裝。打開Windows 的cmd或Mac的終端,鍵入:

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

就安裝完成了。

3.2 擷取響應内容

在Requests中,常用的功能是擷取某個網頁的内容。現在我們使用Requests擷取個人部落格首頁的内容。

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

這樣就傳回了一個名為r的response響應對象,其存儲了伺服器響應的内容,我們可以從中擷取需要的資訊。上述代碼的結果如圖3-1所示。

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

上例的說明如下:

(1)r.text是伺服器響應的内容,會自動根據響應頭部的字元編碼進行解碼。

(2)r.encoding是伺服器内容使用的文本編碼。

(3)r.status_code用于檢測響應的狀态碼,如果傳回200,就表示請求成功了;如果傳回的是4xx,就表示用戶端錯誤;傳回5xx則表示伺服器錯誤響應。我們可以用r.status_code來檢測請求是否正确響應。

(4)r.content是位元組方式的響應體,會自動解碼gzip和deflate編碼的響應資料。

(5)r.json()是Requests中内置的JSON解碼器。

3.3 定制Requests

在3.2節中,我們使用Requests庫擷取了網頁資料,但是有些網頁需要對Requests的參數進行設定才能擷取需要的資料,這包括傳遞URL參數、定制請求頭、發送POST請求、設定逾時等。

3.3.1 傳遞URL參數

為了請求特定的資料,我們需要在URL的查詢字元串中加入某些資料。如果你是自己建構URL,那麼資料一般會跟在一個問号後面,并且以鍵/值的形式放在URL中,如

http://httpbin.org/get?key1=value1

在Requests中,你可以直接把這些參數儲存在字典中,用params(參數)建構至URL中。例如,傳遞key1 = value1和key2=value2到

http://httpbin.org/get

,可以這樣編寫:

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

通過上述代碼的輸出結果可以發現URL已經正确編碼:

URL已經正确編碼:

http://httpbin.org/get?key1=value1&key2=value2

字元串方式的響應體:

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章
帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

3.3.2 定制請求頭

請求頭Headers提供了關于請求、響應或其他發送實體的資訊。對于爬蟲而言,請求頭十分重要,盡管在上一個示例中并沒有制定請求頭。如果沒有指定請求頭或請求的請求頭和實際網頁不一緻,就可能無法傳回正确的結果。

Requests并不會基于定制的請求頭Headers的具體情況改變自己的行為,隻是在最後的請求中,所有的請求頭資訊都會被傳遞進去。

那麼,我們如何找到正确的Headers呢?

還是用到第2章提到過的Chrome浏覽器的“檢查”指令。使用Chrome浏覽器打開要請求的網頁,右擊網頁的任意位置,在彈出的快捷菜單中單擊“檢查”指令。

如圖3-2所示,在随後打開的頁面中單擊Network選項。

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

如圖3-3所示,在左側的資源中找到需要請求的網頁,本例為www.santostang.com。單擊需要請求的網頁,在Headers中可以看到Requests Headers的詳細資訊。

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

是以,我們可以看到請求頭的資訊為:

GET / HTTP/1.1

Host: www.santostang.com

Connection: keep-alive

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8 Accept-Encoding: gzip, deflate, sdch

Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4,zh-TW;q=0.2

提取請求頭中重要的部分,可以把代碼改為:

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

3.3.3 發送POST請求

除了GET請求外,有時還需要發送一些編碼為表單形式的資料,如在登入的時候請求就為POST,因為如果用GET請求,密碼就會顯示在URL中,這是非常不安全的。如果要實作POST請求,隻需要簡單地傳遞一個字典給Requests中的data參數,這個資料字典就會在送出請求的時候自動編碼為表單形式。

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

輸出的結果為:

{

"args": {},

"data": "",

"form": {

"key1": "value1", 
"key2": "value2"           

},

}

可以看到,form變量的值為key_dict輸入的值,這樣一個POST請求就發送成功了。

3.3.4 逾時

有時爬蟲會遇到伺服器長時間不傳回,這時爬蟲程式就會一直等待,造成爬蟲程式沒有順利地執行。是以,可以用Requests在timeout參數設定的秒數結束之後停止等待響應。意思就是,如果伺服器在timeout秒内沒有應答,就傳回異常。

我們把這個秒數設定為0.001秒,看看會抛出什麼異常。這是為了讓大家體驗timeout異常的效果而設定的值,一般會把這個值設定為20秒。

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

傳回的異常為:ConnectTimeout: HTTPConnectionPool(host='www.santostang.com ',

port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(connection.HTTPConnection object at 0x0000000005B85B00>, 'Connection to www.santostang.com timed out. (connect timeout=0.001)'))。

異常值的意思是,時間限制在0.001秒内,連接配接到位址為www.santostang.com 的時間已到。

3.4 Requests爬蟲實踐:TOP250電影資料

本章實踐項目的目的是擷取豆瓣電影TOP250的所有電影的名稱,網頁位址為:

https://movie.douban.com/top250

。在此爬蟲中,将請求頭定制為實際浏覽器的請求頭。

3.4.1 網站分析

打開豆瓣電影TOP250的網站,使用“檢查”功能檢視該網頁的請求頭,如圖3-4所示。

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

按照3.3.2中的方法提取其中重要的請求頭:

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

第一頁隻有25個電影,如果要擷取所有的250頁電影,就需要擷取總共10頁的内容。

通過單擊第二頁可以發現網頁位址變成了:

https://movie.douban.com/top250?start=25

第三頁的位址為:

https://movie.douban.com/top250?start=50

,這就很容易了解了,每多一頁,就給網頁位址的start參數加上25。

3.4.2 項目實踐

通過以上分析發現,可以使用requests擷取電影網頁的代碼,并利用for循環翻頁。其代碼如下:

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

運作上述代碼,得到的結果是:

1 頁響應狀态碼: 200

lang="zh-cmn-Hans" class="ua-windows ua-webkit">

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="renderer" content="webkit">
<meta name="referrer" content="always">
<title>           

豆瓣電影TOP250

...

這時,得到的結果隻是網頁的HTML代碼,我們需要從中提取需要的電影名稱。接下來會涉及第5章解析網頁的内容,讀者可以先使用下面的代碼,至于對代碼的了解,可以等到第5章再學習。

帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章
帶你讀《Python網絡爬蟲從入門到實踐(第2版)》之三:靜态網頁抓取第3章

在上述代碼中,使用BeautifulSoup對網頁進行解析并擷取其中的電影名稱資料。運作代碼,得到的結果是:

2 頁響應狀态碼: 200

3 頁響應狀态碼: 200

4 頁響應狀态碼: 200

5 頁響應狀态碼: 200

6 頁響應狀态碼: 200

7 頁響應狀态碼: 200

8 頁響應狀态碼: 200

9 頁響應狀态碼: 200

10 頁響應狀态碼: 200

['肖申克的救贖', '這個殺手不太冷', '霸王别姬', '阿甘正傳', '美麗人生', '千與千尋', '辛德勒的名單', '泰坦尼克号', '盜夢空間', '機器人總動員', '海上鋼琴師', '三傻大鬧寶萊塢', '忠犬八公的故事', '放牛班的春天', '大話西遊之大聖娶親', '教父', '龍貓', '楚門的世界', '亂世佳人', '天堂電影院', '當幸福來敲門', '觸不可及', '搏擊俱樂部', '十二怒漢', '無間道', '熔爐', '指環王3:王者無敵', '怦然心動', '天空之城', '羅馬假日', ...]

3.4.3 自我實踐題

讀者若有時間,可以實踐進階問題:擷取TOP 250電影的英文名、港台名、導演、主演、上映年份、電影分類以及評分。