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 中處理非常靈活,與響應體相關的屬性有:content
、text
、json()
。
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')