Requests的基本用法

介紹

首先讓咱們來看 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> 複製代碼

JSON 響應內容

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 請求

咱們在使用 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,其餘幾個咱們都是能夠設置的。下面咱們就來看看其餘幾個關鍵字怎麼設置。

設置data參數

若是你在 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"
    ]
  }, 
  ...
}
複製代碼

設置 json 參數

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

若是一個響應中包含了 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 使用起來簡直太方便了。話很少說,感受上手實踐吧!

相關文章
相關標籤/搜索