1. 程式人生 > >python爬蟲入門(二):Requests的使用

python爬蟲入門(二):Requests的使用

雖然Python有內建的urllib庫,可以實現網路的請求,但是我並不推薦。因為urllib在很多時候使用起來不方便,比如加一個代理,處理Cookie時API都很繁瑣,再比如傳送一個POST請求也很麻煩。而Requests就相當於urllib的升級版本,簡化了urllib的使用方法。有了Requests,我們可以用幾句程式碼實現代理的設定,Cookie的設定,非常方便。詳細可以參考Requests官方文件

requests實現了HTTP協議中絕大部分功能,它提供的功能包括Keep-Alive、連線池、Cookie持久化、內容自動解壓、HTTP代理、SSL認證、連線超時、Session等很多特性,最重要的是它同時相容python2 和 python3。

什麼是Requests?

Requests是Python語言編寫,基於urllib3,採用Apache2 Licensed開源協議的HTTP庫。

它比urllib更加方便,可以節約我們大量的工作,完全滿足HTTP測試需求。是Python實現的簡單易用的HTTP庫。

Requests的作用

傳送網路請求,返回響應資料。

requests庫的安裝
# 使用終端安裝requests庫
pip install requests
使用步驟(三部曲)
  • 匯入模組: import reqeusts
  • 傳送get請求,獲取響應: response = requests.get(url)
  • 從響應中獲取資料
Requests基本使用

response的常用屬性:

  • response.text
  • respones.content 二進位制形式的響應資料
  • response.status_code 響應狀態嗎
  • response.headers 響應頭
  • response.request.headers 請求頭

response.text 和response.content的區別

  • response.text
    • 型別:str
    • 解碼型別: 根據HTTP頭部對響應的編碼作出有根據的推測,推測的文字編碼
    • 如何修改編碼方式:response.encoding=”gbk”
  • response.content
    • 型別:bytes
    • 解碼型別: 沒有指定
    • 如何修改編碼方式:response.content.deocde(“utf8”)
  • 更推薦使用response.content.deocde()的方式獲取響應的html頁面
Requests的語法操作
例項引入:
import requests
response = requests.get("http://www.baidu.com/")
print("URL地址:")
print(response.url)
print("響應內容:")
print(response.text)
print("響應狀態碼:")
print(response.status_code)
print("響應cookie:")
print(response.cookies)
# URL地址:
# http://www.baidu.com/
# 響應內容:
# <!DOCTYPE html>
# <!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8>......</head>  </p> </div> </div> </div> </body> </html>
# 響應狀態碼:
# 200
# 響應cookie:
# <RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
各種請求方式:

requests還支援其他的請求方式:

import requests

data={
    'name':'zhangsan',
    'age':18
}
response = requests.get("http://httpbin.org/")
response = requests.post("http://httpbin.org/post/", data=data)
response = requests.put("http://httpbin.org/put/", data=data)
response = requests.delete("http://httpbin.org/delete/")
response = requests.puch("http://httpbin.org/puch")
......
GET請求:
基本用法
import requests

response = requests.get("http://www.httpbin.org/get")
print(response.text) 
# {
#   "args": {}, 
#   "headers": {
#     "Accept": "*/*", 
#     "Accept-Encoding": "gzip, deflate", 
#     "Connection": "close", 
#     "Host": "httpbin.org", 
#     "User-Agent": "python-requests/2.19.1"
#   }, 
#   "origin": "183.54.192.122", 
#   "url": "http://httpbin.org/get"
# }
帶引數GET請求
1、構建請求查詢引數:

很多URL都帶有很長一串引數,我們稱這些引數為URL的查詢引數,用”?”附加在URL連結後面,多個引數之間用”&”隔開,比如:http://fav.foofish.net/?p=4&s=20

import requests

# 第一種方式:
response = requests.get("http://httpbin.org/get?name=zhangsan&age=18")
print(response.text)
2、params:

還可以用字典來構建查詢引數:傳入引數只需要把資料生成一個字典,然後呼叫params引數進行賦值就可以了

import requests

# 第二種方式:
data = {
    "name":"zhangsan",
    "age":18
}
response = requests.get("http://httpbin.org/get", params=data)
print(response.text)
解析json

Requests的json解析和json的loads方法解析出來的結果是完全一樣的。所以Requests可以使用requests.json()很方便的解析json資料。

import requests

response = requests.get("http://httpbin.org/get")
print(response.json())  # 返回的是json型別的字串
二進位制資料
獲取二進位制資料:

content方法獲取的資料是二進位制資料,可以使用這個方法將資料進行儲存,而text獲取的則是字串程式碼。

import requests

response = requests.get("http://github.com/favicon.ico")
# 獲取二進位制資料
print(response.content)
儲存二進位制資料:
# 1. 匯入requests模組
import requests
# 2. 傳送請求獲取資料
response = requests.get("http://ww3.sinaimg.cn/mw600/006XNEY7gy1frloq7utftj30hs0hsac3.jpg")
# 獲取二進位制資料; 注意: 這裡不要解碼, 因為圖片,視訊等檔案都是二進位制的不是文字,不需要解碼
data = response.content
# 3. 把資料寫入檔案
with open("美女桌布.jpg", "wb") as f:
    f.write(data)
新增headers

requests 可以很簡單地指定請求首部欄位Headers,比如有時要指定User-Agent偽裝成瀏覽器傳送請求,以此來矇騙伺服器。直接傳遞一個字典物件給引數headers即可。

import requests

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}
resp = requests.get('http://www.baidu.com', headers=headers)
print(resp.text)
POST請求

一個POST必然是要有一個Form Data的表單提交的,我們只要把資訊傳給data引數就可以了。一個POST請求只需要呼叫post方法

import requests

data={
    "name":"zhangsan",
    "age":18
}
response = requests.post("http:httpbin.org/post", data=data)
print(response.text)
響應
響應首部(headers)
import requests

response = requests.get("http://www.baidu.com/")
for name,value in response.headers.items():
    print("%s:%s" % (name, value))
response相關屬性
import requests

response = requests.get('http://www.baidu.com/')
print(type(response.status_code)) # 狀態碼
print(type(response.text)) # 網頁原始碼
print(type(response.headers)) # 頭部資訊
print(type(response.cookies)) # Cookie
print(type(response.url)) # 請求的url
print(type(response.history)) # 訪問的歷史記錄
狀態碼判斷
import requests

response = requests.get('http://www.baidu.com/')
exit() if not resp.status_code == 200 else print('Sucessful')  # 三元表示式

# 執行結果:
# Sucessful

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

import requests

response = requests.get('http://httpbin.org/status/404')
response.status_code
# 404
response.raise_for_status()
# Traceback (most recent call last):
#   File "requests/models.py", line 832, in raise_for_status
#     raise http_error
# requests.exceptions.HTTPError: 404 Client Error
Response中的響應體

HTTP返回的響應訊息中很重要的一部分內容是響應體,響應體在 requests 中處理非常靈活,與響應體相關的屬性有:contenttextjson()

content 是 byte 型別,適合直接將內容儲存到檔案系統或者傳輸到網路中;

r = requests.get("http://github.com/favicon.ico")
print(type(r.content))
# <class 'bytes'>
# 另存為 test.jpg
with open("fav.ico", "wb") as f:
    f.write(r.content)

text 是 str 型別,比如一個普通的 HTML 頁面,需要對文字進一步分析時,使用 text;

import requests

response = requests.get("https://foofish.net/understand-http.html")
print(type(response.text))
# <class 'str'>
# 可以使用正則或者xpath進行資料的篩選
re = re.match('正則規則', r.text)

如果使用第三方開放平臺或者API介面爬取資料時,返回的內容是json格式的資料時,那麼可以直接使用json()方法返回一個經過json.loads()處理後的物件。

import requests

response = requests.get('https://www.v2ex.com/api/topics/hot.json')
print(response.json())
# [{'title': '寬頻症候群',
#   'url': 'https://www.v2ex.com/go/bb',
#   'topics': 4827,
#   'footer': '',
#   'header': '網速很重要。比快更快。',
#   ....
檔案上傳

檔案上傳的操作只要我們從資料夾中把檔案讀取出來,並且賦值給 files 引數,就可以了,打印出原始碼我們就可以看到上傳檔案的位元組流了。

import requests

files = {"file":open("favicon.ico", "rb")}
response = requests.post("http://httpbin.org/post", files=files)  # 使用post上傳
print(response.status_code)
print(response.text)
獲取cookie

要獲取cookie,那麼使用cookies就可以獲取到響應的cookies,可以通過獲取字典的鍵值對來檢視cookie

import requests

resp = requests.get('http://www.baidu.com')
print(resp.cookies)
for key, value in response.cookies.items():
    print(key+":"+value)
會話維持

獲得到了cookie就可以做一個會話維持,可以維持一個登入的狀態,也就是做模擬登入。

import requests

s = requests.Session()
s.get('http://httpbin.org/cookies/set/number/123456789') # 設定了一個cookie
resp = s.get('http://httpbin.org/cookies')
print(resp.text)
代理設定

當爬蟲頻繁地對伺服器進行抓取內容時,很容易被伺服器遮蔽掉,因此要想繼續順利的進行爬取資料,使用代理proxies是明智的選擇。如果你想爬取牆外的資料,同樣設定代理可以解決問題,requests 完美支援代理。

import requests

proxies = {
  'http': 'http://10.10.1.10:3128',
  'https': 'http://10.10.1.10:1080',
}

requests.get('http://example.org', proxies=proxies)
證書驗證
import requests
response = requests.get('https://www.12306.cn')
print(response.status_code)
#以上會顯示錯誤,因為需要證書驗證

#解決證書問題,我們有兩種方法

#方法一,我們可以通過設定verify=False來忽略證書驗證
import requests
response = requests.get('https://www.12306.cn',verify=False)
print(response.status_code)
#以上解決了證書驗證問題,但是仍然是有警告丟擲:InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised.
#為了忽略警告,可以引入以下
import requests
from requests.packages import urllib3
urllib3.disable_warning()
response = requests.get('https://www.12306.cn',verify=False)
print(response.status_code)

#方法二,手動傳入證書,如果有的話
response = requests.get('https://www.12306.cn',cert=('/path/server.vrt','/path/key'))
print(response.status_code)
認證設定
import requests
from requests.auth import HTTPBasicAuth

resp = requests.get(url, auth=HTTPBasicAuth('username','password'))
print(resp.status_code)
超時設定

requests 傳送請求時,預設請求下執行緒一直阻塞,直到有響應返回才處理後面的邏輯。如果遇到伺服器沒有響應的情況時,問題就變得很嚴重了,它將導致整個應用程式一直處於阻塞狀態而沒法處理其他請求。

import requests
response = requests.get("http://www.google.coma") # google是外國網站,訪問需要翻牆,
# 無法訪問處於一直阻塞中

正確的方式的是給每個請求顯示地指定一個超時時間timeout。(可以通過異常捕獲來處理超時問題)

import requests 

response = requests.get("http://www.google.coma", timeout=5) # 請求在5秒內沒有響應就報錯
# 5秒後報錯
# Traceback (most recent call last):
# socket.timeout: timed out
異常處理

如果遇到無法訪問的網站,或者是網速不夠快,訪問超時,就會導致程式的中斷。顯然在實際的抓取中不願意看到爬取到一半的程式突然中斷的情況,那麼就對其進行異常處理:

import requests
from requests.exceptions import ReadTimeout, ConnectionError, RequestException

try:
    resp = requests.get('http://httpbin.org/get', timeout=0.5)
    print(resp.status_code)
except ReadTimeout: # 訪問超時的錯誤
    print('Timeout')
except ConnectionError: # 網路中斷連線錯誤
    print('Connect error')
except RequestException: # 父類錯誤
    print('Error')