大資料時代,各行各業對資料採集的需求日益增多,網路爬蟲的運用也更為廣泛,越來越多的人開始學習網路爬蟲這項技術,K哥爬蟲此前已經推出不少爬蟲進階、逆向相關文章,為實現從易到難全方位覆蓋,特設【0基礎學爬蟲】專欄,幫助小白快速入門爬蟲,本期為網路請求庫的使用。
網路請求庫概述
作為一名爬蟲初學者,熟練使用各種網路請求庫是一項必備的技能。利用這些網路請求庫,我們可以透過非常簡單的操作來進行各種協議的模擬請求。我們不需要深入底層去關注如何建立通訊與資料如何傳輸,只需要呼叫各種網路請求庫封裝好的方法。Python提供了很多功能強大的網路請求庫,如urllib、requests、httpx、aiohttp、websocket等,下文中會對這些庫做一一介紹。
urllib
安裝與介紹
安裝
urllib是Python的內建請求庫,不需要再額外安裝。
介紹
urllib庫包含四個模組:
urllib.request: 向目標url發起請求並讀取響應資訊。
urllib.error: 負責異常處理,捕獲urllib.request丟擲的異常。
urllib.parse: 解析url,提供了一些url的解析方法。
urllib.robotparser: 解析網站robots.txt檔案,判斷網站是否允許爬蟲程式進行採集。
使用方法
請求與響應
使用到了urllib.request模組中的urlopen方法來開啟一個url並獲取響應資訊。urlopen預設返回的是一個HTTPResponse物件,可以透過read方法得到它的明文資訊。
import urllib.request
response = urllib.request.urlopen('http://httpbin.org/get')
print(response) #列印:<http.client.HTTPResponse object at 0x0000013D85AE6548>
print(response.read().decode('utf-8')) #響應資訊
print(response.status) #返回狀態碼
print(response.getheaders()) #返回響應頭資訊
設定請求頭與引數
當請求需要設定請求頭時,就需要用到urllib.request模組中的另一個方法Request,它允許傳遞如下幾個引數:
def __init__(self, url, data=None, headers={},origin_req_host=None, unverifiable=False,method=None)
url:目標url
data:請求引數,預設為None
headers:請求頭資訊,字典型別
origin_req_host:請求的主機地址
unverifiable:設定網頁是否需要驗證
method:請求方式
from urllib import request,parse
url = 'https://httpbin.org/post' #目標URL
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
} #請求頭資訊
params = {
'test':'test01' #請求引數
}
data = bytes(parse.urlencode(params),encoding='utf-8') #解析為bytes型別
res = request.Request(url,data=data,headers=headers,method='POST') #例項化Request
response = request.urlopen(res) #發起請求
print(response.read().decode('utf-8')) #響應資訊
異常捕獲
在發起請求時,可能會因為網路、url錯誤、引數錯誤等問題導致請求異常,程式報錯。為了應對這種情況,我們需要新增異常處理功能。
from urllib import request,error
try:
response = request.urlopen('http://httpbin.org/get')
except error.HTTPError as e: #捕獲異常
print(e) #列印異常資訊
requests
requests是Python爬蟲開發中最常使用到的庫,它提供了簡單易用的API,使得在Python中傳送HTTP請求變得非常容易,它比urllib模組更加簡潔,使用更加方便。
安裝與介紹
安裝
requests是Python的第三方庫,使用 pip install requests
進行安裝
介紹
requests包含了許多模組,這裡只介紹主要模組:
requests: 主模組,提供了HTTP請求方法。
requests.session: 會話模組,提供了Session類,用於多個請求中共享請求資訊。
requests.adapters: 介面卡模組,提供了不同協議的介面卡類,用於處理不同協議的請求。
requests.cookie: Cookie模組,用於處理cookie資訊。
requests.exceptions: 異常處理模組,用於處理請求中會出現的各種異常。
requests.status_codes: 狀態碼模組,提供了HTTP狀態碼常量和狀態碼解釋。
使用方法
請求與響應
import requests #匯入requests模組
get_response = requests.get('http://httpbin.org/get') #傳送get請求
post_response = requests.post('http://httpbin.org/post') #傳送post請求
print(get_response) #<Response [200]>
print(post_response) #<Response [200]>
requests庫傳送請求非常簡單,並支援多種請求方式,如:get、post、put、delete等。發起請求後requests會返回一個Response物件,可以使用多種方法來解析Response物件。
import requests
response = requests.get('http://httpbin.org/get')
print(response.status_code) #返回響應狀態碼
print(response.encoding) #返回響應資訊的編碼
print(response.text) #返回響應的文字資訊
print(response.content) #返回響應的位元組資訊
print(response.json()) #將JSON響應資訊解析為字典,如果響應資料型別不為JSON則會報錯
print(response.headers) #返回響應頭資訊
print(response.cookies) #返回響應cookie
設定請求頭與引數
request(self,method,url,params=None,data=None,headers=None,cookies=None,files=None,auth=None,timeout=None,allow_redirects=True,proxies=None,hooks=None,stream=None,verify=None,cert=None,json=None)
requests中設定請求頭可以透過headers引數來設定,headers是一個字典型別,鍵為請求頭的欄位名,值為對應請求頭的值。
請求引數可以透過params方法進行設定,型別為字典。鍵為引數名,值為對應引數的值。
在網路請求中,攜帶的引數可以分為兩個型別,它們在python中對應的欄位名如下:
查詢字串引數: params
請求載荷: data/json
查詢字串引數params是拼接在url中的引數,常用於get請求,作為查詢引數使用。而data與json一般使用與post請求中,它是要傳送到伺服器的實際資料。
import requests
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
}
params = {'key':'value'}
data = {'username':'user','passowrd':'password'}
get_response = requests.get(url,params=params,headers=headers)
post_response = requests.post(url,data=data,headers=headers)
Session的使用
當一個網站我們需要多次請求時,如我需要登入 -> 請求個人頁面,在面對這種場景時,我們可以使用到Session方法。因為透過requests傳送到的請求是獨立,我們請求登入介面與請求個人頁面之間是沒有聯絡的,我們需要請求登入介面後獲取它返回的cookie,然後設定cookie進行下一次請求。每次請求後都需要設定一次cookie,如果請求流程更多的話那麼過程就會顯得很繁瑣。使用Session方法就能更好的模擬一次請求流程,不需要頻繁的設定cookie。
Session的作用類似於瀏覽器中的cookie與快取,它可以用於在多次請求中維護一些狀態資訊,避免重複傳送相同的資訊和資料,使用Session可以最佳化HTTP請求的效能與可維護性,它的使用也非常簡單。
import requests
session = requests.Session() #建立session物件
session.get('http://httpbin.org/cookies/set/username/test') #發起請求,模擬一次登入
response = session.get('http://httpbin.org/cookies') #獲取cookie
print(response.text) #{"cookies": {"username": "test"}}
異常捕獲
requests.exceptions 中提供了一系列請求異常。
ConnectTimeout:連線超時
ReadTimeout:伺服器在指定時間內沒有應答
ConnectionError:未知的伺服器
ProxyError:代理異常
URLRequired:無效URL
TooManyRedirects:重定向過多
MissingSchema:URL缺失,如缺少:http/https
InvalidSchema:提供的URL方案無效或不受支援
InvalidURL:提供的URL不知何故無效
InvalidHeader:提供的請求頭無效
InvalidProxyURL:提供的代理URL無效
ChunkedEncodingError:伺服器宣告瞭編碼分塊,但傳送了無效分塊
ContentDecodingError:無法對響應資訊解碼
StreamConsumedError:此響應內容已被使用
RetryError:自定義重試邏輯錯誤
UnrewindableBodyError:請求在嘗試倒帶正文時遇到錯誤
HTTPError:出現HTTP錯誤
SSLError:發生SSL錯誤
Timeout:請求超時
httpx
前面講到了requests庫,它功能強大、使用簡單,並且提供session會話模組,似乎requests庫已經可以滿足所有的應用場景了。但是requests也有一些致命的缺點:
- 同步請求,不支援非同步,requests預設使用同步請求,在網路請求中同步請求到導致效能問題。
- 不支援HTTP2.0,如今已經有少部分網站採用HTTP2.0協議來進行資料傳輸,面對這類網站無法使用requests。
而httpx是一個基於非同步IO的Python3的全功能HTTP客戶端庫,旨在提供一個快速、簡單、現代化的HTTP客戶端,它提供同步與非同步API,而且支援HTTP1.1和HTTP2.0。並且httpx功能也很齊全,requests支援的功能httpx也基本同樣支援。因此,在爬蟲開發中使用httpx也是一個非常不錯的選擇。
安裝與介紹
安裝
httpx是Python的第三方庫,使用 pip install httpx
進行安裝
如果需要httpx支援https2.0,則需要安裝它的可選依賴項, pip install httpx[http2]
介紹
httpx是建立在requests的成熟可用性之上的,提供的模組與requests大同小異,因此不做介紹。
使用方法
httpx用法與requests基本一致,這裡主要介紹httpx的Client例項。
httpx Client
Client作用與requests的session方法一致,但用法有些區別。
常見用法是使用上下文管理器,這樣可以確保在請求完成後能夠正確清理連線。
import httpx
with httpx.Client() as client:
response = client.get('https://httpbin.org/get')
print(response) #<Response [200 OK]>
在設定請求頭、傳遞引數時也有新的寫法。
import httpx
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'}
params = {'key':'value'}
with httpx.Client(headers=headers,params=params) as client:
response = client.get('https://httpbin.org/get')
print(response)
aiohttp
aiohttp是基於Python非同步IO的HTTP客戶端/伺服器庫,它與httpx相似,同樣支援HTTP1.1和HTTP2.0協議,aiohttp是基於asyncio實現的,它支援WebSocket協議。
安裝
aiohttp是Python的第三方庫,使用 pip install aiohttp
進行安裝
使用
import aiohttp
import asyncio
async def main():
async with aiohttp.ClientSession() as session:
async with session.get('https://httpbin.org/get') as response:
print(response) #<ClientResponse(https://httpbin.org/get) [200 OK]>
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
aiohttp不支援同步,需要與asyncio一起使用,與前文中講到的庫對比,aiohttp顯得異常複雜,requests兩行程式碼就能完成的功能aiohttp卻需要5行。為什麼aiohttp程式碼如此冗餘我們卻要使用它呢?因為aiohttp是非同步的,它的api旨在充分利用非阻塞網路操作,在例項程式碼中,請求將阻塞三次,這為事件迴圈提供了三次切換上下文的機會。aiohttp可以實現單執行緒併發IO操作,它在處理大量網站請求時的速度遠超於requests,但在涉及到檔案讀寫操作時,它發揮的作用就沒有預期的那麼大,因此aiohttp庫的使用需要爬蟲開發者自行斟酌。
websocket
Python websocket庫是專門用於建立WebSocket服務的庫。WebSocket是一種在客戶端與服務端之間進行雙向通訊的協議,服務端可以向客戶端推送資料,客戶端也可以向服務端推送資料,這樣就能實現資料的及時通訊,它與HTTP協議一樣,由socket實現。WebSocket通常使用在直播、彈幕等場景中。
安裝
websocket是Python的內建庫,不需要手動安裝。當你在執行下文中的例項時,如果報錯cannot import name 'WebSocketApp' from 'websocket'
,你可以解除安裝現有的websocket庫,安裝websocket-client==0.53.0
版本的包。
使用
websocket用於客戶端與服務端通訊,爬蟲開發中一般只會進行客戶端的開發,所有這裡只介紹客戶端的開發。
使用WebSocketApp可以快速的建立一個Websocket連線。
from websocket import WebSocketApp
def on_message(ws, message): #接收到訊息時執行
print(message)
def on_error(ws, error): #異常時執行
print(error)
def on_close(ws): #關閉連線時執行
print("WebSocket closed")
def on_open(ws): #開啟連線時執行
ws.send("Hello, WebSocket!") #傳送資訊
if __name__ == "__main__":
ws = WebSocketApp("ws://echo.websocket.org/",
on_message=on_message,
on_error=on_error,
on_close=on_close)
ws.on_open = on_open
ws.run_forever()
可以看到websocket提供了四個模組:
on_message: 接收伺服器推送來的資料
on_error: 連線異常時會觸發on_error
on_close: 連線關閉時觸發on_close
on_open: 連線開啟時觸發on_open
歸納
上文中講到了urllib、requests、httpx、aiohttp、websocket這五個庫的使用,這五個庫基本能夠滿足爬蟲開發中的請求需求。urllib是python的內建庫,使用起來較為繁瑣,可以只做瞭解。requests是爬蟲開發中最常使用的庫,功能齊全,使用簡單,需要認真學習。httpx在requests的基礎上支援非同步處理、HTTP2.0與Websocket協議,requests的功能httpx都支援,但在效能方面httpx弱於其他請求庫,httpx也需要爬蟲初學者好好學習。aiohttp用於編寫非同步爬蟲,開發效率低於其它庫,但是執行效率遠高與其它庫,也是一個需要好好掌握的請求庫。websocket是專門用於Websocket協議的庫,使用也較為簡單,可以在需要時再做了解。