如果你把上篇多線程和多進程的文章搞定了,那么要恭喜你了 。你編寫爬蟲的能力上了一個嶄新的臺階。不過,我們還不能沾沾自喜,因為任重而道遠。那么接下來就關注下本文的主要內容。本文主要介紹 urllib 庫的代替品 ——
Requests
。
1 Requests 簡介
引用 Requests 官網的說明:
Requests is the only Non-GMO HTTP library for Python, safe for human consumption.
Requests 官方的介紹語是多么霸氣。之所以能夠這么霸氣,是因為 Requests 相比 urllib 在使用方面上會讓開發者感到更加人性化、更加簡潔、更加舒服。并且國外一些知名的公司也在使用該庫,例如 Google、Microsoft、Amazon、Twitter 等。因此,我們就更加有必要來學習 Request 庫了。在學習之前,我們來看下它究竟具有哪些特性?
具體如下:
- Keep-Alive & 連接池
- 國際化域名和 URL
- 帶持久 Cookie 的會話
- 瀏覽器式的 SSL 認證
- 自動內容解碼
- 基本/摘要式的身份認證
- 優雅的 key/value Cookie
- 自動解壓
- Unicode 響應體
- HTTP(S) 代理支持
- 文件分塊上傳
- 流下載
- 連接超時
- 分塊請求
- 支持 .netrc
2 安裝 Requests
古人云:“工欲善其事,必先利其器”。在學習 Requests 之前,我們應先將庫安裝好。安裝它有兩種辦法。
- 方法1:通過 pip 安裝
比較推薦使用這種方式,既簡單又方便管理。
pip install requests
- 方法2:通過源碼安裝
先通過 git 克隆源碼庫:
git clone git://github.com/kennethreitz/requests.git
接著進入到 requests 目錄中執行以下命令:
python setup.py install
3 發起請求
有了前面學習 urllib 庫的經驗,現在我們學習 Requests 應該會更加容易上手。
3.1 簡單抓取網頁
我們使用 Requests 向百度貼吧發起一個 HTTP 請求,并獲取到它頁面的源代碼。
import requests
# 使用 get 方式請求
response = requests.get('https://tieba.baidu.com/')
print(response.text)
那么使用 POST 請求網頁,代碼又該怎么寫呢?相信答案已經浮現在你腦海中了。沒錯,就是將 get 換成 post 即可。
import requests
# 使用 post 方式請求
response = requests.post('https://tieba.baidu.com/')
print(response.text)
3.2 傳遞 URL 參數
我們在請求網頁時,經常需要攜帶一些參數。Requests 提供了params
關鍵字參數來滿足我們的需求。params 是一個字符串字典,我們只要將字典構建并賦給 params 即可。我們也無須關心參數的編碼問題,因為 Requests 很人性化,會將我們需要傳遞的參數正確編碼。它的具體用法如下:
import requests
url = 'http://httpbin.org/get'
params = {'name': 'Numb', 'author': 'Linkin Park'}
# params 支持列表作為值
# params = {'name': 'Good Time', 'author': ['Owl City', 'Carly Rae Jepsen']}
response = requests.get(url, params=params)
print(response.url)
print(response.text)
如果字典為空是不會被拼接到 URL中的。另外,params 的拼接順序是隨機的,而不是寫在前面就優先拼接。
#運行結果如下:
http://httpbin.org/get?name=Numb&author=Linkin+Park
http://httpbin.org/get?name=Good+Time&author=Owl+City&author=Carly+Rae+Jepsen
你也許會疑問,為什么會有多了個"+"號呢?這個是 Requests 為了替代空格,它在請求時會自動轉化為空格的。
3.3 構造請求頭
為了將 Requests 發起的 HTTP 請求偽裝成瀏覽器,我們通常是使用headers
關鍵字參數。headers 參數同樣也是一個字典類型。具體用法見以下代碼:
import requests
url = 'https://tieba.baidu.com/'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'
# 還可以設置其他字段。
}
response = requests.get(url, headers=headers)
print(response.url)
print(response.text)
3.4 使用 data 參數提交數據
data 參數通常結合 POST 請求方式一起使用。如果我們需要用 POST 方式提交表單數據或者JSON數據,我們只需要傳遞一個字典給 data 參數。
- 提交表單數據
我們使用測試網頁http://httpbin.org/post
來提交表單數據作為例子進行展示。
import requests
url = 'http://httpbin.org/post'
data = {
'user': 'admin',
'pass': 'admin'
}
response = requests.post(url, data=data)
print(response.text)
運行結果如下:我們會看到http://httpbin.org/post
頁面打印我們的請求內容中,有form
字段。
{
"args": {},
"data": "",
"files": {},
"form": {
"pass": "admin",
"user": "admin"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Cache-Control": "max-age=259200",
"Connection": "close",
"Content-Length": "21",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.11.1"
},
"json": null,
"origin": "14.*.*.*",
"url": "http://httpbin.org/post"
}
- 提交 JSON 數據
在HTTP 請求中,JSON 數據是被當作字符串文本。所以,我們使用 data 參數的傳遞 JSON 數據時,需要將其轉為為字符串。我們繼續使用上文的代碼做演示。
import json
import requests
url = 'http://httpbin.org/post'
data = {
'user': 'admin',
'pass': 'admin'
}
response = requests.post(url, data=json.dumps(data))
print(response.text)
你可以拿下面的運行結果和提交表單數據的運行結果做下對比,你會了解更加清楚兩者的差異。
{
"args": {},
"data": "{\"pass\": \"admin\", \"user\": \"admin\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Cache-Control": "max-age=259200",
"Connection": "close",
"Content-Length": "34",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.11.1"
},
"json": {
"pass": "admin",
"user": "admin"
},
"origin": "14.*.*.*",
"url": "http://httpbin.org/post"
}
那是否有更加簡便的方法來傳遞 JSON 數據?Requests 在 2.4.2 版本新增該功能。我們可以使用 json 參數直接傳遞,然后它會被自動編碼。
import requests
url = 'http://httpbin.org/post'
data = {
'user': 'admin',
'pass': 'admin'
}
response = requests.post(url, json=data)
print(response.text)
3.5 使用代理
有些網站做了瀏覽頻率限制。如果我們請求該網站頻率過高,該網站會被封掉我們的 IP,禁止我們的訪問。所以我們需要使用代理來突破這“枷鎖”。這里需要用到proxies
參數,proxies 也是一個字典類型。具體用法如下:
import requests
url = 'https://tieba.baidu.com/'
proxies = {
'http':"web-proxy.oa.com:8080",
'https':"web-proxy.oa.com:8080"
# 若你的代理需要使用HTTP Basic Auth,可以使用 http://user:password@host/ 語法:
# "http": "http://user:pass@27.154.181.34:43353/"
}
response = requests.get(url, proxies=proxies)
print(response.url)
print(response.text)
除了支持 HTTP 代理,Requests 在 2.10 版本新增支持 SOCKS 協議的代理。
使用 SOCKS 代理,需要額外安裝一個第三方庫,我們就使用 pip 來安裝。
pip install requests[socks]
安裝成功之后,就可以正常使用了,用法跟 HTTP 代理相關。具體見代碼:
proxies = {
'http': 'socks5://user:pass@host:port',
'https': 'socks5://user:pass@host:port'
}
3.6 設置請求超時
我們使用代理發起請求,經常會碰到因代理失效導致請求失敗的情況。因此,我們對請求超時做下設置。當發現請求超時,更換代理再重連。
response = requests.get(url, timeout=3)
如果你要同時設置 connect 和 read 的超時時間,可以傳入一個元組進行設置。
response = requests.get(url, timeout=(3, 30))
3.7 使用 Cookie
想在響應結果中獲取 cookie 的一些值,可以直接訪問。
response.cookies['key'] # key 為 Cookie 字典中鍵
想發送 cookies 到服務器,可以使用cookies
參數。同樣該參數也是字典類型
url = 'http://httpbin.org/cookies'
# cookies = dict(domain='httpbin.org')
cookies = {
'domain':'httpbin.org',
}
response = requests.get(url, cookies=cookies)
print(response.text)
4 響應結果
我們跟Python 打交道,擺脫不了編碼的問題。使用 Requests 請求,我們無需擔心編碼問題。感覺 Requests 真的是太人性化了。請求發出后,Requests 會基于 HTTP 頭部對響應的編碼作出有根據的推測。當你訪問 response .text 之時,Requests 會使用其推測的文本編碼。
response = requests.get(url)
print(response.text)
如果你想改變 response 的編碼格式,可以這么做:
response.encoding = 'UTF-8'
4.1 二進制響應內容
對于非文本請求, 我們能以字節的方式訪問請求響應體。Requests 會自動為我們解碼 gzip 和 deflate 傳輸編碼的響應數據。
例如,以請求返回的二進制數據創建一張圖片,你可以使用如下代碼:
from PIL import Image
from io import BytesIO
i = Image.open(BytesIO(response.content))
4.2 JSON 響應內容
Requests 中也有一個內置的 JSON 解碼器,助我們處理 JSON 數據:
import requests
url = 'https://github.com/timeline.json'
response = requests.get(url)
print(response.json())
如果 JSON 解碼失敗, response .json() 就會拋出一個異常。例如,響應內容是 401 (Unauthorized),嘗試訪問 response .json() 將會拋出 ValueError: No JSON object could be decoded 異常。
4.3 響應狀態碼
我們需要根據響應碼來判斷請求的結果,具體是這樣獲取狀態碼:
response.status_code
Requests 內部提供了一個狀態表,如果有需要對狀態碼進行判斷,可以看下requests.codes
的源碼。
5 高級用法
5.1 重定向與請求歷史
有些頁面會做一些重定向的處理。Requests 又發揮人性化的特性。它在默認情況下,會幫我們自動處理所有重定向,包括 301 和 302 兩種狀態碼。我們可以使用
response .history
來追蹤重定向。
Response.history
是一個 Response 對象的列表,為了完成請求而創建了這些對象。這個對象列表按照從最老到最近的請求進行排序。
如果我們要禁用重定向處理,可以使用allow_redirects
參數:
response = requests.get(url, allow_redirects=False)
5.2 會話
Requests 支持 session 來跟蹤用戶的連接。例如我們要來跨請求保持一些 cookie,我們可以這么做:
s = requests.Session()
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get("http://httpbin.org/cookies")
print(r.text)
# '{"cookies": {"sessioncookie": "123456789"}}'
5.3 身份認證
有些 web 站點都需要身份認證成功之后才能訪問。urllib 具備這樣的功能,Requests 也不例外。Requests 支持基本身份認證(HTTP Basic Auth)、netrc 認證、摘要式身份認證、OAuth 1 認證等。
- 基本身份認證
許多要求身份認證的web服務都接受 HTTP Basic Auth。這是最簡單的一種身份認證,并且 Requests 對這種認證方式的支持是直接開箱即可用。HTTP Basic Auth 用法如下:
from requests.auth import HTTPBasicAuth
url = 'http://httpbin.org/basic-auth/user/passwd'
requests.get(url, auth=HTTPBasicAuth('user', 'pass'))
# 簡寫的使用方式
requests.get(url, auth=('user', 'pass'))
- 摘要式身份認證
摘要式是 HTTP 1.1 必需的第二種身份驗證機制。這種身份驗證由用戶名和密碼組成。隨后將用 MD5(一種單向哈希算法)對摘要式身份驗證進行哈希運算,并將其發送到服務器。具體用法如下:
from requests.auth import HTTPDigestAuth
url = 'http://httpbin.org/digest-auth/auth/user/passwd/MD5'
requests.get(url, auth=HTTPDigestAuth('user', 'pass'))
- OAuth 認證
OAuth(開放授權)認證在我們的生活中隨處可見。Requests 同樣也支持這中認證方式,其中包括 OAuth 1.0 和 OAuth 2.0。如果你需要用到該認證,你需要安裝一個支持庫requests-oauthlib
。我以 OAuth 1.0 認證作為例子進行講解:
import requests
from requests_oauthlib import OAuth1
url = 'https://api.twitter.com/1.1/account/verify_credentials.json'
auth = OAuth1('YOUR_APP_KEY',
'YOUR_APP_SECRET',
'USER_OAUTH_TOKEN',
'USER_OAUTH_TOKEN_SECRET')
requests.get(url, auth=auth)
上篇文章:Python 多進程與多線程
推薦閱讀:爬蟲實戰一:爬取當當網所有 Python 書籍