大數據時代,各行各業對數據采集的需求日益增多,網絡爬蟲的運用也更為廣泛,越來越多的人開始學習網絡爬蟲這項技術,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.requestresponse = 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,parseurl = '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,errortry: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 requestsresponse = 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 requestsheaders = {'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 requestssession = requests.Session() #創建session對象
session.get('http://httpbin.org/cookies/set/username/test') #發起請求,模擬一次登錄
response = session.get('http://httpbin.org/cookies') #獲取cookieprint(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 httpxwith httpx.Client() as client:response = client.get('https://httpbin.org/get')print(response) #<Response [200 OK]>
在設置請求頭、傳遞參數時也有新的寫法。
import httpxheaders = {'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 asyncioasync 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 WebSocketAppdef 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_openws.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協議的庫,使用也較為簡單,可以在需要時再做了解。