
在 Python 處理 HTTP 請求(如接口調(diào)用、數(shù)據(jù)爬取、API 交互)的場景中,urllib.request
(Python 標(biāo)準(zhǔn)庫)與requests
(第三方庫)是最常用的兩大工具。前者依托 “原生標(biāo)準(zhǔn)庫” 優(yōu)勢無需額外安裝,后者以 “簡潔 API、豐富功能” 成為開發(fā)者首選。但兩者在使用體驗、功能覆蓋、異常處理等方面存在顯著差異,選擇不當(dāng)可能導(dǎo)致代碼冗余或效率低下。本文將從實戰(zhàn)角度拆解兩者的核心差異,提供清晰的選擇依據(jù)與實操建議。
要理解兩者的差異,首先需明確其 “出身” 帶來的底層定位差異 —— 這是后續(xù)所有功能與用法區(qū)別的根源。
urllib.request
:Python 原生的 “基礎(chǔ)工具”歸屬:屬于 Python 標(biāo)準(zhǔn)庫(自 Python 3 起整合為urllib
模塊下的子模塊),無需額外安裝,隨 Python 環(huán)境自帶;
設(shè)計目標(biāo):提供 “最小化、底層” 的 HTTP 請求能力,覆蓋 GET/POST 等基礎(chǔ)操作,滿足簡單場景需求,不依賴任何第三方依賴;
核心特點:功能精簡、穩(wěn)定性強(qiáng)(隨 Python 版本同步更新),但 API 設(shè)計偏 “底層”,需手動處理編碼、Cookie、會話等細(xì)節(jié)。
requests
:社區(qū)驅(qū)動的 “高效工具”歸屬:由 Python 社區(qū)開發(fā)的第三方庫(由 Kenneth Reitz 發(fā)起),需通過pip install requests
安裝;
設(shè)計目標(biāo):以 “人類可讀” 為核心,簡化 HTTP 請求流程,封裝常用功能(如會話保持、文件上傳、身份認(rèn)證),降低開發(fā)成本;
核心特點:API 簡潔、功能豐富、文檔完善,是 Python 生態(tài)中 “HTTP 請求” 的事實標(biāo)準(zhǔn),但依賴第三方環(huán)境(需確保安裝且版本兼容)。
基礎(chǔ)對比表:
維度 | urllib.request |
requests |
---|---|---|
安裝方式 | 無需安裝(標(biāo)準(zhǔn)庫) | 需pip install requests |
依賴環(huán)境 | 無第三方依賴 | 依賴urllib3 (底層)、chardet (編碼檢測)等 |
設(shè)計理念 | 底層、最小化 | 高層、人性化 |
適用人群 | 需兼容原生環(huán)境、簡單需求場景 | 追求開發(fā)效率、復(fù)雜功能場景 |
兩者的差異在實際編碼中體現(xiàn)得最為明顯,以下從 “API 簡潔性”“功能完整性”“異常處理”“細(xì)節(jié)處理” 四個核心維度,結(jié)合代碼示例對比分析。
urllib.request
的 API 基于 “底層協(xié)議封裝”,需手動處理請求構(gòu)建、數(shù)據(jù)編碼、響應(yīng)解析等步驟;而requests
通過 “函數(shù)式 API” 將復(fù)雜流程封裝,一行代碼即可完成基礎(chǔ)請求。
需求:向https://httpbin.org/get
發(fā)送 GET 請求,攜帶參數(shù)name=python
、version=3.10
。
urllib.request
實現(xiàn):
需手動構(gòu)建 URL 參數(shù)(用urllib.parse.urlencode
編碼)、創(chuàng)建Request
對象、打開請求、讀取響應(yīng),步驟繁瑣:
import urllib.request
import urllib.parse
# 1. 構(gòu)建請求參數(shù)(需編碼,否則中文/特殊字符報錯)
params = {"name": "python", "version": "3.10"}
encoded_params = urllib.parse.urlencode(params) # 編碼為"name=python&version=3.10"
url = f"https://httpbin.org/get?{encoded_params}"
# 2. 創(chuàng)建請求對象(可選設(shè)置請求頭)
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
request = urllib.request.Request(url, headers=headers)
# 3. 發(fā)送請求并獲取響應(yīng)(需異常捕獲)
try:
with urllib.request.urlopen(request) as response:
# 4. 讀取響應(yīng)(需手動解碼,默認(rèn)返回bytes)
response_data = response.read().decode("utf-8")
print("響應(yīng)內(nèi)容:", response_data)
except urllib.error.HTTPError as e:
print("HTTP錯誤:", e.code, e.reason)
requests
實現(xiàn):
直接調(diào)用requests.get()
,參數(shù)通過params
傳入(自動編碼),響應(yīng)通過text
屬性直接獲取解碼后的字符串,代碼量減少 50%:
import requests
# 1. 直接發(fā)送GET請求,參數(shù)自動編碼
url = "https://httpbin.org/get"
params = {"name": "python", "version": "3.10"}
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
try:
response = requests.get(url, params=params, headers=headers)
# 2. 直接獲取解碼后的響應(yīng)內(nèi)容
print("響應(yīng)內(nèi)容:", response.text)
except requests.exceptions.RequestException as e:
print("請求錯誤:", e)
參數(shù)處理:urllib
需手動用urlencode
編碼,requests
通過params
參數(shù)自動編碼;
響應(yīng)讀?。?code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(271,93,108);">urllib返回bytes
需手動解碼,requests
用text
(自動識別編碼)或json()
(直接解析 JSON)簡化操作;
代碼冗余:urllib
需多步構(gòu)建請求,requests
一步完成,更符合 “開發(fā)者直覺”。
urllib.request
僅提供 HTTP 請求的 “基礎(chǔ)功能”,復(fù)雜場景(如會話保持、文件上傳、身份認(rèn)證)需大量自定義代碼;而requests
原生支持這些功能,封裝程度極高。
需求:模擬用戶登錄后訪問個人中心(需保持 Cookie 會話)。
urllib.request
實現(xiàn):
需手動創(chuàng)建CookieJar
對象,通過HTTPCookieProcessor
處理 Cookie,步驟復(fù)雜:
import urllib.request
import urllib.parse
import http.cookiejar
# 1. 創(chuàng)建Cookie容器(保存登錄后的Cookie)
cookie_jar = http.cookiejar.CookieJar()
# 2. 創(chuàng)建帶Cookie處理的 opener
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie_jar))
urllib.request.install_opener(opener) # 全局生效
# 3. 發(fā)送登錄請求(模擬POST提交表單)
login_url = "https://httpbin.org/post"
login_data = urllib.parse.urlencode({"username": "test", "password": "123456"}).encode("utf-8")
login_request = urllib.request.Request(login_url, data=login_data, headers={"Content-Type": "application/x-www-form-urlencoded"})
opener.open(login_request) # 登錄后,Cookie保存在cookie_jar中
# 4. 訪問個人中心(自動攜帶Cookie)
profile_url = "https://httpbin.org/cookies"
with urllib.request.urlopen(profile_url) as response:
print("個人中心響應(yīng):", response.read().decode("utf-8"))
import requests
# 1. 創(chuàng)建會話對象(自動保存Cookie)
session = requests.Session()
# 2. 發(fā)送登錄請求(會話自動保存Cookie)
login_url = "https://httpbin.org/post"
login_data = {"username": "test", "password": "123456"}
session.post(login_url, data=login_data, headers={"Content-Type": "application/x-www-form-urlencoded"})
# 3. 訪問個人中心(會話自動攜帶Cookie)
profile_url = "https://httpbin.org/cookies"
response = session.get(profile_url)
print("個人中心響應(yīng):", response.text)
需求:向服務(wù)器上傳一張圖片文件(test.jpg
)。
urllib.request
實現(xiàn):
需手動構(gòu)建multipart/form-data
格式的請求體(復(fù)雜且易出錯),需計算邊界符、編碼文件內(nèi)容:
import urllib.request
import os
url = "https://httpbin.org/post"
filename = "test.jpg"
boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW" # 自定義邊界符
# 1. 讀取文件內(nèi)容
with open(filename, "rb") as f:
file_data = f.read()
# 2. 構(gòu)建請求體(multipart/form-data格式)
data = f"""--{boundary}r
Content-Disposition: form-data; name="file"; filename="{filename}"r
Content-Type: image/jpegr
r
{file_data.decode("latin-1")}r
--{boundary}--r"""
data = data.encode("latin-1") # 用latin-1編碼避免二進(jìn)制報錯
# 3. 發(fā)送請求
headers = {"Content-Type": f"multipart/form-data; boundary={boundary}"}
request = urllib.request.Request(url, data=data, headers=headers)
with urllib.request.urlopen(request) as response:
print("上傳響應(yīng):", response.read().decode("utf-8"))
requests
實現(xiàn):
用files
參數(shù)直接傳入文件對象,自動處理multipart/form-data
格式,一行代碼完成上傳:
import requests
url = "https://httpbin.org/post"
# 1. 用files參數(shù)指定文件(自動處理格式)
files = {"file": ("test.jpg", open("test.jpg", "rb"), "image/jpeg")}
response = requests.post(url, files=files)
print("上傳響應(yīng):", response.text)
會話管理:urllib
需手動構(gòu)建CookieJar
和opener
,requests
用Session
自動管理;
文件上傳:urllib
需手動構(gòu)建請求體(易出錯),requests
用files
參數(shù)一鍵完成;
擴(kuò)展功能:requests
還原生支持 Basic Auth(auth=(user, pwd)
)、代理設(shè)置(proxies={"http": "xxx"}
)、超時控制(timeout=5
),urllib
需手動配置。
HTTP 請求可能遇到多種錯誤(如網(wǎng)絡(luò)超時、404NotFound、500 服務(wù)器錯誤),兩者的異常處理機(jī)制差異顯著 ——urllib
細(xì)分錯誤類型,requests
提供統(tǒng)一捕獲入口,且更易判斷請求狀態(tài)。
urllib.request
的異常處理:需捕獲urllib.error.URLError
(網(wǎng)絡(luò)層面錯誤,如超時、域名不存在)和urllib.error.HTTPError
(HTTP 狀態(tài)碼錯誤,如 404、500),且需手動判斷響應(yīng)狀態(tài)碼:
import urllib.request
import urllib.error
try:
response = urllib.request.urlopen("https://httpbin.org/status/404", timeout=5)
# 手動判斷狀態(tài)碼(200為成功)
if response.getcode() == 200:
print("請求成功")
else:
print(f"請求失敗,狀態(tài)碼:{response.getcode()}")
except urllib.error.HTTPError as e:
print(f"HTTP錯誤:狀態(tài)碼{e.code},原因{e.reason}")
except urllib.error.URLError as e:
print(f"網(wǎng)絡(luò)錯誤:{e.reason}") # 如"timed out"(超時)、"Name or service not known"(域名錯誤)
requests
的異常處理:所有請求相關(guān)錯誤(超時、網(wǎng)絡(luò)錯誤、HTTP 錯誤)都繼承自requests.exceptions.RequestException
,可統(tǒng)一捕獲;
用response.status_code
直接獲取狀態(tài)碼,或調(diào)用response.raise_for_status()
自動拋出 HTTP 錯誤(4xx/5xx):
import requests
try:
response = requests.get("https://httpbin.org/status/404", timeout=5)
response.raise_for_status() # 自動拋出4xx/5xx錯誤
print("請求成功")
except requests.exceptions.HTTPError as e:
print(f"HTTP錯誤:{e}") # 如"404 Client Error: Not Found for url: ..."
except requests.exceptions.ConnectionError as e:
print(f"連接錯誤:{e}") # 如域名不存在、網(wǎng)絡(luò)中斷
except requests.exceptions.Timeout as e:
print(f"超時錯誤:{e}")
except requests.exceptions.RequestException as e:
print(f"其他請求錯誤:{e}") # 統(tǒng)一捕獲剩余錯誤
錯誤分類:urllib
分HTTPError
和URLError
,requests
細(xì)分更細(xì)(如ConnectionError
、Timeout
)但支持統(tǒng)一捕獲;
狀態(tài)碼判斷:urllib
需調(diào)用getcode()
,requests
用status_code
更直觀,且raise_for_status()
簡化錯誤拋出。
在編碼識別、JSON 解析、重定向處理等 “細(xì)節(jié)場景” 中,requests
的自動封裝大幅減少手動操作,而urllib
需開發(fā)者自行處理。
細(xì)節(jié)場景 | urllib.request 處理方式 |
requests 處理方式 |
---|---|---|
編碼識別 | 需手動獲取響應(yīng)頭Content-Type 中的編碼,或用chardet 庫檢測(需額外安裝),默認(rèn)utf-8 解碼易報錯 |
自動檢測編碼(依賴chardet /charset-normalizer ),response.text 直接返回解碼后字符串 |
JSON 解析 | 需先讀取bytes →解碼為字符串→用json 庫解析:json.loads(response.read().decode()) |
直接調(diào)用response.json() ,一步解析為 Python 字典 / 列表 |
重定向處理 | 默認(rèn)跟隨重定向(最多 5 次),禁用需手動設(shè)置redirect=False (Python 3.6+) |
默認(rèn)跟隨重定向,通過allow_redirects=False 禁用,且response.history 可查看重定向歷史 |
響應(yīng)頭獲取 | 用response.getheader("Header-Name") ,需注意大小寫(如"Content-type" vs "Content-Type" ) |
用response.headers["header-name"] ,不區(qū)分大小寫(如response.headers["content-type"] ) |
在日常開發(fā)中,兩者的性能差異(如請求速度、內(nèi)存占用)并不顯著,但在極端場景(如高并發(fā)、大量請求)或特殊環(huán)境(如無第三方庫權(quán)限)中,兼容性與細(xì)節(jié)優(yōu)化需重點考慮。
requests
略優(yōu)單請求速度:兩者差異在毫秒級,requests
因底層依賴urllib3
(優(yōu)化了連接池),在重復(fù)請求同一域名時,連接復(fù)用效率更高;
內(nèi)存占用:urllib
作為標(biāo)準(zhǔn)庫,內(nèi)存占用略低(約 5%-10%),但requests
的內(nèi)存管理更穩(wěn)定,大量請求時不易泄漏;
并發(fā)處理:兩者均不直接支持高并發(fā),需結(jié)合threading
(多線程)或aiohttp
(異步),但requests
的Session
對象更易與線程池結(jié)合。
urllib.request
優(yōu)勢:
適用于 “無第三方庫安裝權(quán)限” 的環(huán)境(如服務(wù)器默認(rèn) Python 環(huán)境、嵌入式設(shè)備),或需 “最小化依賴” 的場景(如編寫輕量級腳本、系統(tǒng)工具),無需擔(dān)心版本沖突;
requests
優(yōu)勢:
適用于項目開發(fā)、數(shù)據(jù)爬取、API 服務(wù)等場景,需快速迭代且功能復(fù)雜,但其兼容性依賴 Python 版本(需 Python 3.7+,舊版本需指定低版本requests
,如requests==2.25.1
支持 Python 2.7)。
兩者無 “絕對優(yōu)劣”,需根據(jù)實際需求選擇,以下是典型場景的選擇建議:
requests
的場景項目開發(fā):如 Web 后端接口調(diào)用、數(shù)據(jù)爬取、自動化測試,需快速實現(xiàn)功能(如會話保持、文件上傳),追求開發(fā)效率;
復(fù)雜請求需求:需處理身份認(rèn)證(Basic Auth、OAuth)、代理、超時控制、重定向歷史等,requests
的封裝能減少大量代碼;
團(tuán)隊協(xié)作:requests
API 簡潔統(tǒng)一,代碼可讀性高,便于團(tuán)隊成員理解與維護(hù)。
urllib.request
的場景輕量級腳本:如簡單的接口測試、數(shù)據(jù)抓?。▋H需 GET/POST),無需額外安裝庫,腳本可直接運行;
無第三方庫權(quán)限:如服務(wù)器、容器環(huán)境中無法執(zhí)行pip install
,只能使用標(biāo)準(zhǔn)庫;
底層定制需求:需深度定制 HTTP 請求細(xì)節(jié)(如自定義請求體格式、修改 TCP 參數(shù)),urllib
的底層 API 更靈活。
urllib
遷移到requests
若現(xiàn)有代碼用urllib
,需遷移到requests
以簡化開發(fā),核心替換規(guī)則如下:
urllib.request 操作 |
requests 對應(yīng)操作 |
---|---|
urllib.parse.urlencode(params) |
requests.get(url, params=params) |
urllib.request.Request(url, data=data) |
requests.post(url, data=data) |
urlopen(request, timeout=5) |
requests.get(url, timeout=5) |
response.read().decode("utf-8") |
response.text |
json.loads(response.read().decode()) |
response.json() |
CookieJar + HTTPCookieProcessor |
requests.Session() |
urllib.request
作為 Python 標(biāo)準(zhǔn)庫,是 “保底工具”—— 確保在任何環(huán)境下都能完成基礎(chǔ) HTTP 請求,但需付出更多代碼成本;requests
作為第三方庫,是 “效率工具”—— 以簡潔 API 和豐富功能降低開發(fā)難度,成為多數(shù)場景的首選。
若你是初學(xué)者:建議從requests
入手,其人性化設(shè)計能快速建立 HTTP 請求的認(rèn)知,減少 “語法挫折”;
若你是系統(tǒng)開發(fā)者:需兼顧環(huán)境兼容性與功能需求,簡單場景用urllib
,復(fù)雜場景優(yōu)先引入requests
;
若你是維護(hù)舊代碼:若現(xiàn)有urllib
代碼穩(wěn)定運行,無需強(qiáng)制遷移;若需擴(kuò)展功能(如添加會話管理),可逐步替換為requests
。
最終,優(yōu)秀的開發(fā)者不是 “執(zhí)著于某一種工具”,而是能根據(jù)場景靈活選擇 —— 讓工具適配需求,而非讓需求遷就工具。
數(shù)據(jù)分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
DSGE 模型中的 Et:理性預(yù)期算子的內(nèi)涵、作用與應(yīng)用解析 動態(tài)隨機(jī)一般均衡(Dynamic Stochastic General Equilibrium, DSGE)模 ...
2025-09-17Python 提取 TIF 中地名的完整指南 一、先明確:TIF 中的地名有哪兩種存在形式? 在開始提取前,需先判斷 TIF 文件的類型 —— ...
2025-09-17CDA 數(shù)據(jù)分析師:解鎖表結(jié)構(gòu)數(shù)據(jù)特征價值的專業(yè)核心 表結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 規(guī)范存儲的結(jié)構(gòu)化數(shù)據(jù),如數(shù)據(jù)庫表、Excel 表、 ...
2025-09-17Excel 導(dǎo)入數(shù)據(jù)含缺失值?詳解 dropna 函數(shù)的功能與實戰(zhàn)應(yīng)用 在用 Python(如 pandas 庫)處理 Excel 數(shù)據(jù)時,“缺失值” 是高頻 ...
2025-09-16深入解析卡方檢驗與 t 檢驗:差異、適用場景與實踐應(yīng)用 在數(shù)據(jù)分析與統(tǒng)計學(xué)領(lǐng)域,假設(shè)檢驗是驗證研究假設(shè)、判斷數(shù)據(jù)差異是否 “ ...
2025-09-16CDA 數(shù)據(jù)分析師:掌控表格結(jié)構(gòu)數(shù)據(jù)全功能周期的專業(yè)操盤手 表格結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 存儲的結(jié)構(gòu)化數(shù)據(jù),如 Excel 表、數(shù)據(jù) ...
2025-09-16MySQL 執(zhí)行計劃中 rows 數(shù)量的準(zhǔn)確性解析:原理、影響因素與優(yōu)化 在 MySQL SQL 調(diào)優(yōu)中,EXPLAIN執(zhí)行計劃是核心工具,而其中的row ...
2025-09-15解析 Python 中 Response 對象的 text 與 content:區(qū)別、場景與實踐指南 在 Python 進(jìn)行 HTTP 網(wǎng)絡(luò)請求開發(fā)時(如使用requests ...
2025-09-15CDA 數(shù)據(jù)分析師:激活表格結(jié)構(gòu)數(shù)據(jù)價值的核心操盤手 表格結(jié)構(gòu)數(shù)據(jù)(如 Excel 表格、數(shù)據(jù)庫表)是企業(yè)最基礎(chǔ)、最核心的數(shù)據(jù)形態(tài) ...
2025-09-15Python HTTP 請求工具對比:urllib.request 與 requests 的核心差異與選擇指南 在 Python 處理 HTTP 請求(如接口調(diào)用、數(shù)據(jù)爬取 ...
2025-09-12解決 pd.read_csv 讀取長浮點數(shù)據(jù)的科學(xué)計數(shù)法問題 為幫助 Python 數(shù)據(jù)從業(yè)者解決pd.read_csv讀取長浮點數(shù)據(jù)時的科學(xué)計數(shù)法問題 ...
2025-09-12CDA 數(shù)據(jù)分析師:業(yè)務(wù)數(shù)據(jù)分析步驟的落地者與價值優(yōu)化者 業(yè)務(wù)數(shù)據(jù)分析是企業(yè)解決日常運營問題、提升執(zhí)行效率的核心手段,其價值 ...
2025-09-12用 SQL 驗證業(yè)務(wù)邏輯:從規(guī)則拆解到數(shù)據(jù)把關(guān)的實戰(zhàn)指南 在業(yè)務(wù)系統(tǒng)落地過程中,“業(yè)務(wù)邏輯” 是連接 “需求設(shè)計” 與 “用戶體驗 ...
2025-09-11塔吉特百貨孕婦營銷案例:數(shù)據(jù)驅(qū)動下的精準(zhǔn)零售革命與啟示 在零售行業(yè) “流量紅利見頂” 的當(dāng)下,精準(zhǔn)營銷成為企業(yè)突圍的核心方 ...
2025-09-11CDA 數(shù)據(jù)分析師與戰(zhàn)略 / 業(yè)務(wù)數(shù)據(jù)分析:概念辨析與協(xié)同價值 在數(shù)據(jù)驅(qū)動決策的體系中,“戰(zhàn)略數(shù)據(jù)分析”“業(yè)務(wù)數(shù)據(jù)分析” 是企業(yè) ...
2025-09-11Excel 數(shù)據(jù)聚類分析:從操作實踐到業(yè)務(wù)價值挖掘 在數(shù)據(jù)分析場景中,聚類分析作為 “無監(jiān)督分組” 的核心工具,能從雜亂數(shù)據(jù)中挖 ...
2025-09-10統(tǒng)計模型的核心目的:從數(shù)據(jù)解讀到?jīng)Q策支撐的價值導(dǎo)向 統(tǒng)計模型作為數(shù)據(jù)分析的核心工具,并非簡單的 “公式堆砌”,而是圍繞特定 ...
2025-09-10CDA 數(shù)據(jù)分析師:商業(yè)數(shù)據(jù)分析實踐的落地者與價值創(chuàng)造者 商業(yè)數(shù)據(jù)分析的價值,最終要在 “實踐” 中體現(xiàn) —— 脫離業(yè)務(wù)場景的分 ...
2025-09-10機(jī)器學(xué)習(xí)解決實際問題的核心關(guān)鍵:從業(yè)務(wù)到落地的全流程解析 在人工智能技術(shù)落地的浪潮中,機(jī)器學(xué)習(xí)作為核心工具,已廣泛應(yīng)用于 ...
2025-09-09SPSS 編碼狀態(tài)區(qū)域中 Unicode 的功能與價值解析 在 SPSS(Statistical Product and Service Solutions,統(tǒng)計產(chǎn)品與服務(wù)解決方案 ...
2025-09-09