首先讓咱們來看 Requests 官方的介紹:html
Requests is an elegant and simple HTTP library for Python, built for human beings.
複製代碼
翻譯過來就是:Requests 是爲人類寫的一個優雅而簡單的 Python HTTP 庫。這個介紹很直白了,讓咱們先來感覺一下 Requests 的威力。python
import requests
# 發送請求
response = requests.get(url="http://www.baidu.com/s", params={'wd':'python'})
# 處理響應
print(response.status_code)
#返回
200
複製代碼
這個請求若是用 urllib 來實現,代碼以下:nginx
import urllib.parse
import urllib.request
url = "http://www.baidu.com/s"
params = urllib.parse.urlencode({'wd':'python'})
# 發送請求
response = urllib.request.urlopen('?'.join([url, params]))
# 處理響應
print(response.getcode())
#返回
200
複製代碼
從感官上就能看出來,使用 urllib 在 URL 、參數等方面會複雜一些。這只是冰山一角,實際使用中 Requests 還有好多方面超越 urllib ,它並非浪得虛名,接下來的學習中你就會感覺到。git
使用pip命令github
$ pip3 install requests
複製代碼
或者也可使用 easy_install 命令安裝json
$ easy_install requests
複製代碼
使用 Requests 發送網絡請求很是簡單。api
咱們首先須要導入 Requests 模塊:跨域
import requests
複製代碼
而後,咱們就能夠嘗試獲取某個網頁。本例子中,咱們來獲取 Github 的公共時間線:瀏覽器
r = requests.get('https://api.github.com/events')
複製代碼
如今,咱們有一個名爲 r 的 Response 對象。咱們能夠從這個對象中獲取全部咱們想要的信息。bash
Requests 簡便的 API 意味着全部 HTTP 請求類型都是顯而易見的。例如,你能夠這樣發送一個 HTTP POST 請求:
r = requests.post('http://httpbin.org/post', data = {'key':'value'})
複製代碼
簡單,對吧?那麼其餘 HTTP 請求類型:PUT,DELETE,HEAD 以及 OPTIONS 又是如何的呢?都是同樣的簡單:
r = requests.put('http://httpbin.org/put', data = {'key':'value'})
r = requests.delete('http://httpbin.org/delete')
r = requests.head('http://httpbin.org/get')
r = requests.options('http://httpbin.org/get')
複製代碼
咱們在發送請求時,常常須要向服務端發送請求參數,一般參數都是以鍵/值對的形式置於 URL 中,跟在一個問號的後面。例如, httpbin.org/get?key=val。 Requests 容許你使用 params 關鍵字參數,以一個字符串字典來提供這些參數。舉例來講,若是你想傳遞 key1=value1 和 key2=value2 到 httpbin.org/get ,那麼你可使用以下代碼:
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://httpbin.org/get", params=payload)
print(r.url)
#返回
http://httpbin.org/get?key1=value1&key2=value2
複製代碼
經過打印輸出該 URL,你能看到 URL 已被正確編碼。
注意字典裏值爲 None 的鍵都不會被添加到 URL 的查詢字符串裏。
你還能夠將一個列表做爲值傳入:
payload = {'key1': 'value1', 'key2': ['value2', 'value3']}
r = requests.get("http://httpbin.org/get", params=payload)
#返回
http://httpbin.org/get?key1=value1&key2=value2&key2=value3
複製代碼
咱們能夠經過返回讀取服務器響應的內容,以 請求百度首頁爲例:
import requests
r = requests.get('http://www.baidu.com')
print(r.text)
#返回(太多,只顯示一部分)
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-eq...
複製代碼
Requests 會自動解碼來自服務器的內容,大多數 unicode 字符集都能被無縫地解碼。
請求發出後,Requests 會基於 HTTP 頭部對響應的編碼做出有根據的推測。當你訪問 r.text 之時,Requests 會使用其推測的文本編碼。你能夠經過 r.encoding 來獲取 Requests 使用的編碼:
r.encoding
#返回
'utf-8'
複製代碼
而且可以使用 r.encoding 屬性來改變它:
r.encoding = 'ISO-8859-1'
複製代碼
若是你改變了編碼,每當你訪問 r.text ,Request 都將會使用 r.encoding 的新值。
對於非文本請求(例如圖片),你也能以字節的方式訪問請求響應體,Requests 會自動爲你解碼 gzip 和 deflate 傳輸編碼的響應數據。
例如,以請求返回的二進制數據建立一張圖片,你可使用以下代碼:
import requests
from PIL import Image
from io import BytesIO
r = requests.get('http://img.sccnn.com/bimg/326/203.jpg')
print(r.content)
bi = BytesIO(r.content)
print(bi)
i = Image.open(bi)
print(i)
#返回
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\... <_io.BytesIO object at 0x1112fdbf8> <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=600x400 at 0x111020588> 複製代碼
Requests 中有一個內置的 JSON 解碼器,能夠幫助你處理 JSON 數據:
r = requests.get('https://api.github.com/events')
print(r.json())
#返回
[{u'repository': {u'open_issues': 0, u'url': 'https://github.com/... 複製代碼
若是 JSON 解碼失敗, r.json() 就會拋出一個異常。
r = requests.get('https://www.baidu.com')
print(r.json())
#返回
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
複製代碼
須要注意的是,成功調用 r.json() 並不意味着響應的成功。有的服務器會在失敗的響應中包含一個 JSON 對象(好比 HTTP 500 的錯誤細節)。這種 JSON 會被解碼返回。要檢查請求是否成功,請使用 r.raise_for_status() 或者檢查 r.status_code 是否和你的指望相同。
在極少數狀況下,你可能想獲取來自服務器的原始套接字響應,那麼你能夠訪問 r.raw。 這個時候請確保在初始請求中設置了 stream=True。具體你能夠這麼作:
r = requests.get('https://api.github.com/events', stream=True)
print(r.raw)
print(r.raw.read(10))
#返回
<requests.packages.urllib3.response.HTTPResponse object at 0x101194810>
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'
複製代碼
若是你在爬取某個頁面內容的時候,發現獲取的數據爲空,可是直接用瀏覽器訪問 URL 沒問題,這時候頗有多是你被服務器識別爲爬蟲用戶了,怎麼辦呢?咱們應該要模擬瀏覽器去請求,這時候你須要爲請求添加 HTTP 頭部信息,只要簡單地傳遞一個 dict 給 headers 參數就能夠了。
例如,咱們設置一下 User-Agent :
url = 'http://www.baidu.com'
headers = {'User-Agent': 'myagent/2.21.0'}
r = requests.get(url, headers=headers)
print(r.request.headers)
#返回
{'User-Agent': 'myagent/2.21.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
複製代碼
能夠看到,請求的 User-Agent 已經變成了設置的 myagent/2.21.0。
咱們在使用 POST 請求的時候,打印一下 r.text 會發現每次都會出現幾個關鍵字:
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {},
"json": null,
"origin": "221.232.172.222, 221.232.172.222",
"url": "https://httpbin.org/post"
}
複製代碼
這些關鍵字均可以在 POST 的參數裏面設置。其中 headers 和 args 咱們前面已經講過,分別表示請求頭和參數信息。origin 是指請求的路由 ip,url 是咱們請求的 url,其餘幾個咱們都是能夠設置的。下面咱們就來看看其餘幾個關鍵字怎麼設置。
若是你在 POST 請求時想提交表單,也只須要簡單的傳遞一個字典給 data 參數便可。你的數據字典在發出請求時會自動編碼爲表單形式:
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.post("http://httpbin.org/post", data=payload)
print(r.text)
#返回
{
...
"form": {
"key1": "value1",
"key2": "value2"
},
...
}
複製代碼
你也能夠爲 data 參數傳入一個元組列表。Requests 會自動將其轉換成一個列表:
payload = (('key1', 'value1'), ('key1', 'value2'))
r = requests.post("http://httpbin.org/post", data=payload)
print(r.text)
#返回
{
...
"form": {
"key1": [
"value1",
"value2"
]
},
...
}
複製代碼
Requests 容許你使用 json 直接傳遞參數,而後它就會被自動編碼。
payload = {'some': 'data'}
r = requests.post("http://httpbin.org/post", json=payload)
print(r.text)
#返回
{
"args": {},
"data": "{\"some\": \"data\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "16",
"Content-Type": "application/json",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.21.0"
},
"json": {
"some": "data"
},
"origin": "221.232.172.222, 221.232.172.222",
"url": "https://httpbin.org/post"
}
複製代碼
注意,這裏不只賦值給 json 了,並且還自動賦值給 data 了,json 裏面的鍵值對也被自動編碼到 data 中了。
Requests 上傳文件很簡單:
files = {'file': open('test.txt', 'rb')}
r = requests.post('http://httpbin.org/post', files=files)
print(r.text)
#返回
{
...
"files": {
"file": "this is a file test"
},
...
}
複製代碼
你也能夠增長一個參數,把字符串發送到上傳的文件中,例如:
files = {'file': ('test.txt', 'some,data,to,send\nanother,row,to,send\n')}
r = requests.post('http://httpbin.org/post', files=files)
print(r.text)
#返回
{
...
"files": {
"file": "some,data,to,send\nanother,row,to,send\n"
},
...
}
複製代碼
咱們能夠從服務器響應的結果中獲取狀態碼和響應頭的信息,例如:
r = requests.get('http://httpbin.org/get')
print(r.status_code)
#返回
200
複製代碼
爲方便引用,Requests還附帶了一個內置的狀態碼查詢對象:
print(r.status_code == requests.codes.ok)
#返回
True
複製代碼
咱們還能夠查看響應的響應頭信息:
r = requests.get('http://httpbin.org/get')
print(r.headers)
#返回
{'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Origin': '*', 'Content-Encoding': 'gzip', 'Content-Type': 'application/json', 'Date': 'Wed, 18 Sep 2019 12:22:06 GMT', 'Referrer-Policy': 'no-referrer-when-downgrade', 'Server': 'nginx', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'DENY', 'X-XSS-Protection': '1; mode=block', 'Content-Length': '183', 'Connection': 'keep-alive'}
複製代碼
要獲取響應頭的某個字段值,咱們能夠這樣:
print(r.headers['Content-Encoding'])
#返回
gzip
複製代碼
若是一個響應中包含了 cookie ,那麼咱們能夠利用 cookies 變量來拿到:
url = 'http://example.com/some/cookie/setting/url'
r = requests.get(url)
r.cookies['example_cookie_name']
#返回
'example_cookie_value'
複製代碼
以上程序僅是樣例,運行程序並不會獲得下面的返回。須要包含 cookie 的響應才能夠獲得。
另外能夠利用 cookies 變量來向服務器發送 cookies 信息:
cookies = dict(cookies_are='working')
r = requests.get('http://httpbin.org/cookies', cookies=cookies)
print(r.text)
#返回
{
"cookies": {
"cookies_are": "working"
}
}
複製代碼
能夠看到咱們設置 cookies 參數後,返回中就包含了咱們設置的信息。
Cookie 的返回對象爲 RequestsCookieJar,它和字典相似,適合跨域名跨路徑使用,也就是說咱們能夠爲不一樣的域名或者路徑設置不一樣的 cookie 。你還能夠把 Cookie Jar 傳到 Requests 中:
jar = requests.cookies.RequestsCookieJar()
#爲路徑/cookies設置cookie
jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies')
#爲路徑/elsewhere設置cookie
jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere')
#請求路徑爲/cookies的URL
url = 'http://httpbin.org/cookies'
r = requests.get(url, cookies=jar)
print(r.text)
#返回
{
"cookies": {
"tasty_cookie": "yum"
}
}
複製代碼
默認狀況下,除了 HEAD 請求, Requests 會自動處理全部重定向。
可使用響應對象的 history 方法來追蹤重定向。
Response.history 是一個 Response 對象的列表,這個對象列表按照從最老到最近的請求進行排序。
例如,Github 將全部的 HTTP 請求重定向到 HTTPS:
r = requests.get('http://github.com')
print(r.url)
print(r.status_code)
print(r.history)
#返回
https://github.com/
200
[<Response [301]>]
複製代碼
若是你使用的 Mac ,在運行這段代碼時報錯: ConnectionResetError: [Errno 54] Connection reset by peer。你須要升級你係統的 openssl,具體方法請自行百度關鍵詞「mac 更新OpenSSL」,更新以後就不會報錯了。
咱們還能夠經過 allow_redirects 參數禁用重定向處理:
r = requests.get('http://github.com', allow_redirects=False)
print(r.status_code)
print(r.history)
#返回
301
[]
複製代碼
你能夠經過設置 timeout 參數來告訴 requests 在通過以 timeout 參數設定的秒數時間以後中止等待響應。
requests.get('http://github.com', timeout=0.001)
#返回
requests.exceptions.ConnectTimeout: HTTPConnectionPool(host='github.com', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x110adf400>, 'Connection to github.com timed out. (connect timeout=0.001)'))
複製代碼
這裏經過設置極短的超時時間致使請求中止等待響應,從而引起報錯。注意 timeout 僅對鏈接過程有效,與響應體的下載無關。 timeout 並非整個下載響應的時間限制,而是若是服務器在 timeout 秒內沒有應答,將會引起一個異常。
本節給你們介紹了 Requests 的基本用法,若是你對爬蟲有了必定的基礎,那麼確定能夠很快上手,由於 Requests 使用起來簡直太方便了。話很少說,感受上手實踐吧!