1. 程式人生 > >爬蟲利器:Requests庫使用

爬蟲利器:Requests庫使用

Requests:讓HTTP服務人類。

本文中的有些內容來自官方網站,也有一部分是我的理解,算是個筆記版本吧。

1、requests是什麼

寫了一些爬蟲,從urllib庫轉到requests庫,到目前為止,個人感覺requests庫是最簡單易用的HTTP庫,以下這段話來自requests官網:

Requests 唯一的一個非轉基因的 Python HTTP 庫,人類可以安全享用。

警告:非專業使用其他 HTTP 庫會導致危險的副作用,包括:安全缺陷症、冗餘程式碼症、重新發明輪子症、啃文件症、抑鬱、頭疼、甚至死亡。

字裡行間透露著requests庫的自信,它確實做到了。

以下為Requests庫的功能特性,完全滿足今日web的需求:

  • Keep-Alive & 連線池
  • 國際化域名和 URL
  • 帶持久 Cookie 的會話
  • 瀏覽器式的 SSL 認證
  • 自動內容解碼
  • 基本/摘要式的身份認證
  • 優雅的 key/value Cookie
  • 自動解壓
  • Unicode 響應體
  • HTTP(S) 代理支援
  • 檔案分塊上傳
  • 流下載
  • 連線超時
  • 分塊請求
  • 支援 .netrc

2、安裝及更新

2.1 安裝

最簡單的安裝方式是pip安裝,只需執行以下一條指令:


pip install requests

也可以通過git使用原始碼安裝,需要執行以下兩條指令:

git clone git://github.com
/kennethreitz/requests.git python setup.py install

2.2 更新

使用pip進行更新:

pip install --upgrade requests

3、使用

3.1 傳送請求

我們以http://httpbin.org/網站作為測試目標,該網站專門為HTTP客戶端提高測試服務。

使用該庫要在檔案開始部分匯入Requests模組:

import requests

HTTP的請求型別有POST,GET,PUT,DELETE,HEAD 以及 OPTIONS,其中POST和GET是最常使用的,用requests實現這幾種請求程式碼如下:

r = requests.get('https://httpbin.org/get')
r = requests.put("http://httpbin.org/put")
r = requests.delete("http://httpbin.org/delete")
r = requests.head("http://httpbin.org/get")
r = requests.options("http://httpbin.org/get")

我們得到了一個名為rResponse物件,我們可以從這個物件中獲取想要的資訊,例如狀態碼(r.status_code)、文字內容(r.text)等。

3.2 傳遞URL引數

經常可以看到一些網址中有一個?, 後面還跟著幾個引數,這種URL其實傳遞了某種資料,例如http://httpbin.org/get?key=val。Requests允許使用params 關鍵字引數,以一個字串字典來提供這些引數。如果想傳遞key1=val1key2=val2httpbin.org/get,那麼可以使用如下程式碼:

payload = {'key1': 'val1', 'key2': 'val2', 'key3': None}
r = requests.get("http://httpbin.org/get", params=payload)
print(r.url)

執行結果為:http://httpbin.org/get?key1=val1&key2=val2

注:字典中值為None的鍵不會被新增到URL的查詢字串中。

還可以將一個列表作為值傳入:

payload = {'key1': 'val1', 'key2': ['val2', 'val3']}
r = requests.get("http://httpbin.org/get", params=payload)
print(r.url)

執行結果為:http://httpbin.org/get?key1=val1&key2=val2&key2=val3

3.3 響應內容

3.3.1 文字響應內容

在3.1中已經提到Response物件包含很多資訊,其中r.text為伺服器響應內容:

r = requests.get("http://httpbin.org/get")
print(r.text)

執行結果為:

{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Connection": "close", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.18.4"
  }, 
  "origin": "114.244.178.208", 
  "url": "http://httpbin.org/get"
}

Requests可以自動對大多數unicode字符集無縫解碼。

請求發出後,Requests會基於HTTP頭部對響應的編碼做出有根據的推測。我們可以通過r.encoding得到編碼,也可以使用r.encoding屬性改變編碼。

3.3.2 二進位制響應內容

上面r.text獲得的是響應內容的文字,我們也可以以位元組的方式訪問請求響應體,對於非文字請求r.content,Requests會自動解碼gzipdeflate傳輸編碼的響應內容。

3.3.3 JSON響應內容

Requests內建一個JSON解碼器,使用方法如下:

r = requests.get("http://httpbin.org/get")
print(r.json())

如果JSON解碼失敗,r.json()會丟擲一個異常。需要注意的是,成功呼叫r.json()並不意味著響應成功,因為某些伺服器會在失敗的響應中包含一個JSON物件,這種JSON會被解碼返回。如果要判斷請求是否成功,我們可以使用r.raise_for_status()或者檢查r.status_code是否和預期相同。

3.3.4 原始響應內容

有時候我們可能需要獲取伺服器的原始套接字響應,那麼我們應該使用r.raw,使用時要確保在初始請求中設定了stream=True

r = requests.get("http://httpbin.org/get", stream=True)
print(r.raw)
print(r.raw.read(10))

執行結果如下:

<urllib3.response.HTTPResponse object at 0x0000021D55814320>
b'{\n  "args"'

4、定製請求頭

請求某些伺服器時需要加上請求頭,Requests的請求介面有一個名為headers的引數,只需傳給它一個字典即可:

headers = {'user-agent': 'my-app/0.0.1'}
r = requests.get("http://httpbin.org/get", headers=headers)

注意: 定製 header 的優先順序低於某些特定的資訊源,例如:

  • 如果在 .netrc 中設定了使用者認證資訊,使用 headers= 設定的授權就不會生效。而如果設定了 auth= 引數,.netrc 的設定就無效了。
  • 如果被重定向到別的主機,授權 header 就會被刪除。
  • 代理授權 header 會被 URL 中提供的代理身份覆蓋掉。
  • 在我們能判斷內容長度的情況下,header 的 Content-Length 會被改寫。

更進一步講,Requests 不會基於定製 header 的具體情況改變自己的行為。只不過在最後的請求中,所有的 header 資訊都會被傳遞進去。

注意: 所有的 header 值必須是 string、bytestring 或者 unicode。儘管傳遞 unicode header 也是允許的,但不建議這樣做。

5、響應狀態碼

我們可以響應狀態碼得知此次請求的結果,一般200為請求成功, Requests還附帶了一個內建的狀態碼查詢物件requests.codes

r = requests.get('http://httpbin.org/get')
print(r.status_code)
print(r.status_code == requests.codes.ok)

執行結果為:

200
True

如果傳送了一個錯誤請求(一個 4XX 客戶端錯誤,或者 5XX 伺服器錯誤響應),我們可以通過 Response.raise_for_status()來丟擲異常:

r = requests.get('http://httpbin.org/status/404')
print(r.status_code)
r.raise_for_status()

執行結果為:

404
---------------------------------------------------------------------------
HTTPError                                 Traceback (most recent call last)
<ipython-input-19-351ffd673854> in <module>()
      1 r = requests.get('http://httpbin.org/status/404')
      2 print(r.status_code)
----> 3 r.raise_for_status()

E:\Anaconda3\lib\site-packages\requests\models.py in raise_for_status(self)
    933 
    934         if http_error_msg:
--> 935             raise HTTPError(http_error_msg, response=self)
    936 
    937     def close(self):

HTTPError: 404 Client Error: NOT FOUND for url: http://httpbin.org/status/404

6、響應頭

不只請求會有請求頭,響應也有響應頭:

r = requests.get('http://httpbin.org/get')
print(r.headers)
print(r.headers['Connection'])
print(r.headers['connection'])
print(r.headers['conNecTion'])

執行結果:

{
    "Connection": "keep-alive", 
    "Server": "meinheld/0.6.1", 
    "Date": "Thu, 25 Jan 2018 13:47:59 GMT", 
    "Content-Type": "application/json", 
    "Access-Control-Allow-Origin": "*", 
    "Access-Control-Allow-Credentials": "true", 
    "X-Powered-By": "Flask", 
    "X-Processed-Time": "0.00102591514587", 
    "Content-Length": "268", 
    "Via": "1.1 vegur"
}
keep-alive
keep-alive
keep-alive

可以看出該伺服器響應頭為Python字典形式,但是這個字典比較特殊:它是僅為HTTP頭部而生的,是大小寫不敏感的。我們可以以任意大小寫形式來訪問響應頭欄位,由上面的例子也可以看出。

7、超時

requests在傳送請求時可以附帶一個timeout引數,如果伺服器在timeout秒內沒有應答,將會引發一個異常,更精確地說,是在timeout秒內沒有從基礎套接字上接收到任何位元組的資料時。如果我們不使用這個引數,我們的程式可能會永遠失去響應。

r = requests.get('http://httpbin.org/get', timeout=0.01)

這樣就可以得到一個超時異常:

timeout  Traceback (most recent call last)
ConnectTimeout: HTTPConnectionPool(host='httpbin.org', port=80): Max retries exceeded with url: /get (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x000002BADB2A40F0>, 'Connection to httpbin.org timed out. (connect timeout=0.01)'))

8、錯誤與異常

遇到網路問題(如:DNS 查詢失敗、拒絕連線等)時,Requests 會丟擲一個ConnectionError 異常。

若請求超時,則丟擲一個 Timeout 異常。

若請求超過了設定的最大重定向次數,則會丟擲一個 TooManyRedirects 異常。

所有Requests顯式丟擲的異常都繼承自 requests.exceptions.RequestException

9、 代理

某些網站對同一IP的訪問頻率和次數做了限制,如果想要突破這些限制,頻繁替換代理是一種最簡單的解決辦法。Requests庫也為我們提供了代理的使用,只要在傳送請求時指定proxies引數即可:

proxies = {
  "http": "http://10.111.1.14:1212",
  "https": "http://10.110.1.10:1213",
}

r = requests.get("http://httpbin.org/get", proxies=proxies)

如果使用的代理需要使用HTTP Basic Auth,可以使用http://user:[email protected]/語法:

proxies = {
    "http": "http://user:[email protected]:3128/",
}

如果要為某個特定主機設定代理,使用scheme://hostname作為key,它會為指定的主機進行匹配代理:

proxies = {'http://10.20.1.128': 'http://10.10.1.10:5323'}

至此,Requests庫的常用功能介紹完畢,如果想要進階功能的使用教程,請移步官方網站:

微信公眾號