Python Requests:網路服務整合的關鍵利器
在現代應用程式開發中,與網路服務的整合已成為不可或缺的一環。無論是存取RESTful API、抓取網頁內容,還是上載檔案至雲端服務,這些需求都離不開HTTP請求的處理。Python作為一門靈活與強大的程式語言,提供了多種處理HTTP請求的方式,而其中最為優雅與受歡迎的解決方案,非Requests模組莫屬。
為何選擇Requests?
當初我在帶領一個跨國金融科技專案時,團隊需要整合超過二十個不同的外部API。最初我們嘗試使用Python內建的urllib模組,但很快就發現其API設計過於複雜,導致程式碼冗長與難以維護。改用Requests後,程式碼量減少了近40%,可讀性大幅提升,更重要的是,團隊的開發效率顯著提高。
Requests模組憑藉其「人性化」的設計理念,將複雜的HTTP請求簡化為直覺與易於理解的程式碼。它不僅是對Python標準函式庫裝,而是重新思考了開發者與HTTP互動的方式,提供了更符合現代Python風格的API。
本涵蓋內容
本文將從基礎到進階,全面剖析Python Requests模組的各項功能與實踐技巧:
- 基礎HTTP請求操作與回應處理
- 工作階段管理與進階請求客製化
- 身份驗證與安全機制
- 效能最佳化與最佳實踐
- 實際應用案例解析
無論你是初學者還是有經驗的開發者,這篇都能幫助你更有效地使用Requests模組,開發出更穩健、更高效的網路應用。
Requests模組基礎:簡單而強大
安裝與設定
使用pip可以輕鬆安裝Requests:
pip install requests
這個簡單的指令會安裝最新版本的Requests模組。若需要特定版本,可以指定版本號:
pip install requests==2.25.1
安裝完成後,我們可以透過簡單的程式碼測試安裝是否成功:
import requests
response = requests.get('https://api.github.com')
print(response.status_code) # 應該輸出 200
print(response.headers['content-type']) # 應該輸出 'application/json; charset=utf-8'
傳送基本請求
Requests模組的核心功能是傳送HTTP請求。它提供了對應HTTP協定主要方法的函式:
import requests
# GET請求
response = requests.get('https://api.github.com/users/kennethreitz')
# POST請求
response = requests.post('https://httpbin.org/post', data={'key': 'value'})
# PUT請求
response = requests.put('https://httpbin.org/put', data={'key': 'updated_value'})
# DELETE請求
response = requests.delete('https://httpbin.org/delete')
# HEAD請求
response = requests.head('https://httpbin.org/get')
# OPTIONS請求
response = requests.options('https://httpbin.org/get')
這些函式呼叫看似簡單,但背後Requests處理了許多複雜的細節,包括連線管理、編碼處理、標頭設定等。
處理回應內容
傳送請求後,Requests會回傳一個Response物件,包含伺服器的所有回應資訊:
import requests
response = requests.get('https://api.github.com/users/kennethreitz')
# 檢視狀態碼
print(response.status_code) # 200
# 查看回應標頭
print(response.headers)
# 取得回應內容(文字形式)
print(response.text)
# 取得回應內容(JSON形式,自動解析)
print(response.json())
# 檢視請求的URL
print(response.url)
# 檢視編碼
print(response.encoding)
# 取得原始二進位內容
print(response.content)
當我在處理各種API時,發現.json()
方法特別實用。它會自動將JSON回應內容轉換為Python字典,省去了手動解析的麻煩。不過要注意,如果回應內容不是有效的JSON格式,這個方法會引發異常。
自定義請求標頭
在許多API整合場景中,我們需要自定義請求標頭,例如設定認證令牌或指定內容類別:
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Authorization': 'Bearer YOUR_TOKEN_HERE',
'Content-Type': 'application/json',
}
response = requests.get('https://api.github.com/users/kennethreitz', headers=headers)
自定義標頭對於API認證、內容協商、快取控制等場景非常重要。
處理查詢引數
Requests提供了簡潔的方式來處理URL查詢引數:
import requests
# 方法1:直接在URL中加入引數
response = requests.get('https://api.github.com/search/repositories?q=requests+language:python')
# 方法2:使用params引數(推薦)
params = {
'q': 'requests+language:python',
'sort': 'stars',
'order': 'desc'
}
response = requests.get('https://api.github.com/search/repositories', params=params)
print(response.url) # 顯示實際請求的URL
使用params
引數的好處是Requests會自動處理URL編碼,避免特殊字元導致的問題。
進階請求技巧
處理表單資料
在Web應用程式中,我們經常需要處理表單提交。Requests簡化了這一過程:
import requests
# 傳送表單資料
payload = {'username': 'john', 'password': 'secret'}
response = requests.post('https://httpbin.org/post', data=payload)
print(response.json())
上述程式碼會以application/x-www-form-urlencoded
內容類別傳送表單資料,這是HTML表單的預設行為。
傳送JSON資料
對於現代REST API,JSON是最常用的資料交換格式:
import requests
import json
# 方法1:使用json引數
payload = {'name': 'john', 'age': 30}
response = requests.post('https://httpbin.org/post', json=payload)
# 方法2:手動處理JSON(較舊的方式)
payload = {'name': 'john', 'age': 30}
headers = {'Content-Type': 'application/json'}
response = requests.post('https://httpbin.org/post',
data=json.dumps(payload),
headers=headers)
print(response.json())
使用json
引數比手動處理更簡潔,Requests會自動將Python物件序列化為JSON,並設定正確的Content-Type
標頭。
上載檔案
Requests簡化了檔案上載操作:
import requests
# 單檔案上載
files = {'file': open('report.pdf', 'rb')}
response = requests.post('https://httpbin.org/post', files=files)
# 多檔案上載
files = {
'file1': open('report.pdf', 'rb'),
'file2': open('image.jpg', 'rb')
}
response = requests.post('https://httpbin.org/post', files=files)
# 自定義檔案名和MIME類別
files = {'file': ('report.pdf', open('report.pdf', 'rb'), 'application/pdf')}
response = requests.post('https://httpbin.org/post', files=files)
記得在完成請求後關閉檔案,或使用with
陳述式來自動處理檔案關閉:
import requests
with open('report.pdf', 'rb') as f:
files = {'file': f}
response = requests.post('https://httpbin.org/post', files=files)
設定超時
在生產環境中,設定超時是一個良好的實踐,可以避免請求陷入無限等待:
import requests
# 設定5秒的連線超時和30秒的讀取超時
try:
response = requests.get('https://api.github.com', timeout=(5, 30))
except requests.exceptions.ConnectTimeout:
print("連線超時")
except requests.exceptions.ReadTimeout:
print("讀取超時")
except requests.exceptions.Timeout:
print("請求超時")
在我的實踐中,為關鍵API設定合理的超時是防止系統因外部服務不可用而當機的重要手段。
重定向處理
預設情況下,Requests會自動處理重定向。我們可以透過allow_redirects
引數控制這一行為:
import requests
# 停用重定向
response = requests.get('http://github.com', allow_redirects=False)
print(response.status_code) # 301
# 啟用重定向(預設行為)
response = requests.get('http://github.com', allow_redirects=True)
print(response.status_code) # 200
# 檢視重定向歷史
response = requests.get('http://github.com')
print(response.history) # [<Response [301]>]
Requests預設最多允許30次重定向,可以透過設定max_redirects
引數修改這一限制。
工作階段管理與進階功能
使用Session物件
在需要維護狀態(如cookies或連線)的場景中,Session物件非常有用:
import requests
# 建立工作階段
session = requests.Session()
# 設定工作階段級別的標頭或cookies
session.headers.update({'User-Agent': 'Mozilla/5.0'})
session.cookies.update({'session_id': '12345'})
# 使用工作階段傳送請求
response = session.get('https://httpbin.org/cookies')
print(response.json()) # 包含我們設定的cookies
# 工作階段會自動儲存伺服器設定的cookies
response = session.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
print(session.cookies) # 包含伺服器設定的新cookie
# 傳送另一個請求,自動使用儲存的cookies
response = session.get('https://httpbin.org/cookies')
print(response.json()) # 顯示所有cookies
Session物件還有助於提高效能,因為它會在多個請求之間重用底層的TCP連線。
身份驗證
Requests支援多種身份驗證方式:
import requests
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
# 基本認證
response = requests.get('https://api.github.com/user',
auth=HTTPBasicAuth('username', 'password'))
# 簡化的基本認證寫法
response = requests.get('https://api.github.com/user', auth=('username', 'password'))
# 摘要認證
response = requests.get('https://httpbin.org/digest-auth/auth/user/pass',
auth=HTTPDigestAuth('user', 'pass'))
# 自定義認證
from requests.auth import AuthBase
class TokenAuth(AuthBase):
def __init__(self, token):
self.token = token
def __call__(self, r):
r.headers['Authorization'] = f'Bearer {self.token}'
return r
response = requests.get('https://httpbin.org/headers',
auth=TokenAuth('my-token'))
在企業應用中,我經常使用自定義認證類別來處理OAuth令牌或API金鑰等認證機制。
代理設定
在某些情況下,我們需要透過代理傳送請求:
import requests
proxies = {
'http': 'http://10.10.1.10:3128',
'https': 'http://10.10.1.10:1080',
}
response = requests.get('https://api.github.com', proxies=proxies)
# 使用帶認證的代理
proxies = {
'http': 'http://user:pass@10.10.1.10:3128',
}
response = requests.get('https://api.github.com', proxies=proxies)
# 使用SOCKS代理
proxies = {
'http': 'socks5://user:pass@host:port',
'https': 'socks5://user:pass@host:port'
}
response = requests.get('https://api.github.com', proxies=proxies)
注意,使用SOCKS代理需要安裝額外的依賴:pip install requests[socks]
。
處理SSL證書驗證
預設情況下,Requests會驗證SSL證書。在開發或特殊環境中,我們可能需要停用這一驗證:
import requests
# 停用SSL證書驗證(不推薦用於生產環境)
response = requests.get('https://expired.badssl.com/', verify=False)
# 自定義CA證書
response = requests.get('https://api.github.
## 玄貓的 Python Requests 實戰:HTTP 互動與網路爬蟲技術
### 深入 Requests 的世界
Python Requests 套件已成為現代網路互動的標準工具,它徹底改變了開發者與 HTTP 協定互動的方式。這個套件以其優雅的 API 設計和直覺的使用體驗,讓網路請求變得簡單而強大。在我多年開發經驗中,Requests 一直是我首選的 HTTP 客戶端函式庫要是因為它能讓複雜的網路互動簡化為幾行程式碼。
#### HTTP 請求基礎與 Python 模組比較
HTTP 請求是現代網路通訊的根本,而 Python 提供了多種處理 HTTP 的模組。傳統上,Python 標準函式庫 urllib2 是主要選擇,但它的 API 設計較為複雜與不直覺。相比之下,Requests 套件提供了更現代、更人性化的介面。
以下是 Requests 與 urllib2 的關鍵差異:
```python
# urllib2 範例 - 較複雜
import urllib2
req = urllib2.Request('https://api.example.com/data')
req.add_header('User-Agent', 'Mozilla/5.0')
response = urllib2.urlopen(req)
data = response.read()
# Requests 範例 - 更簡潔直觀
import requests
response = requests.get('https://api.example.com/data',
headers={'User-Agent': 'Mozilla/5.0'})
data = response.text
這個簡單的比較就能看出 Requests 的優勢 - 它將複雜的 HTTP 互動簡化為更直觀的方法呼叫。
Requests 的核心特性
Requests 套件的設計理念是「HTTP for Humans」,它徹底實作了這一理念。以下是 Requests 的核心特性:
- 簡潔的 API 設計
- 自動處理常見的 HTTP 功能(如編碼、cookies、重定向)
- 內建 JSON 解析功能
- 對 SSL 驗證的完整支援
- 永續性連線(Keep-alive)的自動處理
- 多種身份驗證機制的支援
發起簡單請求
讓我們從最基本的 HTTP GET 請求開始:
import requests
# 發起 GET 請求
response = requests.get('https://api.github.com')
# 檢查狀態碼
print(f"狀態碼: {response.status_code}")
# 查看回應內容
print(response.text[:100]) # 只顯示前100個字元
當執行上述程式碼時,Requests 會向 GitHub API 傳送 GET 請求,然後回傳回應物件。這個物件包含了狀態碼、標頭和內容等重要資訊。
回應內容處理
Requests 提供了多種方式處理回應內容:
import requests
response = requests.get('https://api.github.com/users/kennethreitz')
# 自動解析 JSON 內容
json_data = response.json()
print(f"User: {json_data['name']}")
print(f"Bio: {json_data['bio']}")
# 取得二進位內容
binary_data = response.content
# 取得文字內容
text_data = response.text
這個範例展示瞭如何使用 .json()
方法自動將 JSON 回應解析為 Python 字典。Requests 也提供了 .content
屬性來取得原始二進位內容,以及 .text
屬性來取得文字內容。
高階 HTTP 請求技巧
自定義標頭
在實際開發中,我們經常需要設定自定義 HTTP 標頭,例如 User-Agent 或授權資訊:
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept-Language': 'zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7',
'Authorization': 'Bearer your_token_here'
}
response = requests.get('https://api.example.com/data', headers=headers)
print(f"狀態碼: {response.status_code}")
這個技巧在開發爬蟲或與需要認證的 API 互動時特別有用。
傳送表單編碼資料
對於 POST 請求,經常需要傳送表單資料:
import requests
# 表單資料
form_data = {
'username': 'testuser',
'password': 'password123'
}
# 傳送 POST 請求
response = requests.post('https://api.example.com/login', data=form_data)
# 檢查登入是否成功
if response.status_code == 200:
print("登入成功!")
else:
print(f"登入失敗: {response.text}")
當使用 data
引數時,Requests 會自動將資料編碼為 application/x-www-form-urlencoded 格式,這是 HTML 表單的預設格式。
上載多部分編碼檔案
Requests 也支援檔案上載:
import requests
# 準備要上載的檔案
files = {
'document': open('report.pdf', 'rb'),
'image': ('photo.jpg', open('photo.jpg', 'rb'), 'image/jpeg')
}
# 傳送帶檔案的 POST 請求
response = requests.post('https://api.example.com/upload', files=files)
# 檢查上載結果
print(f"上載狀態: {response.status_code}")
print(response.text)
在這個例子中,我們上載了兩個檔案,一個是 PDF 檔案,另一個是 JPEG 圖片。Requests 會自動將這些檔案編碼為 multipart/form-data 格式,這是檔案上載的標準格式。
檢視內建回應狀態碼
Requests 提供了方便的方式來檢查 HTTP 狀態碼:
import requests
response = requests.get('https://api.github.com')
# 檢查是否成功
if response.ok: # 檢查狀態碼是否為 2xx
print("請求成功!")
elif response.status_code == requests.codes.not_found: # 404
print("資源不存在")
elif response.status_code == requests.codes.forbidden: # 403
print("無許可權存取")
else:
print(f"發生錯誤: {response.status_code}")
response.raise_for_status() # 如果狀態碼表示錯誤,引發異常
requests.codes
物件提供了所有標準 HTTP 狀態碼的符號名稱,使程式碼更具可讀性。而 raise_for_status()
方法則可以在狀態碼表示錯誤時自動引發相應的異常。
查看回應標頭
標頭中包含了許多有用的資訊,如內容類別、快取控制等:
import requests
response = requests.get('https://www.python.org')
# 檢視所有標頭
for name, value in response.headers.items():
print(f"{name}: {value}")
# 檢視特定標頭
content_type = response.headers['Content-Type']
print(f"內容類別: {content_type}")
# 不區分大小寫的標頭存取
server = response.headers.get('server')
print(f"伺服器: {server}")
Requests 的標頭存取不區分大小寫,這使得標頭的存取更加便捷。
使用 Requests 存取 Cookies
Cookies 在網路應用中扮演著重要的角色,尤其是在身份驗證和工作階段管理方面:
import requests
# 傳送請求並儲存 Cookies
response = requests.get('https://www.example.com')
cookies = response.cookies
print(f"取得的 Cookies: {cookies}")
# 使用特定的 Cookies 傳送請求
custom_cookies = {'session_id': '12345', 'user_id': '67890'}
response = requests.get('https://www.example.com/dashboard', cookies=custom_cookies)
Requests 會自動處理 Cookies,這使得模擬使用者工作階段變得非常簡單。
追蹤請求重定向
重定向是 HTTP 的常見功能,Requests 預設會自動處理重定向:
import requests
# 預設情況下會自動處理重定向
response = requests.get('http://github.com')
print(f"最終 URL: {response.url}") # 應該是 https://github.com/
# 檢視重定向歷史
print("重定向歷史:")
for resp in response.history:
print(f" {resp.status_code}: {resp.url} -> {resp.headers['Location']}")
# 停用自動重定向
response = requests.get('http://github.com', allow_redirects=False)
print(f"狀態碼: {response.status_code}") # 應該是 301
print(f"重定向到: {response.headers['Location']}") # 應該是 https://github.com/
透過檢視 response.history
屬性,我們可以取得請求的重定向歷史。這在除錯或需要了解完整請求路徑時非常有用。
使用超時機制確保生產環境穩定
在生產環境中,設定請求超時是一個良好的實踐,可以防止因網路問題而導致的程式卡死:
import requests
from requests.exceptions import Timeout
try:
# 設定連線超時為 3 秒,讀取超時為 10 秒
response = requests.get('https://api.github.com', timeout=(3, 10))
print(f"回應時間: {response.elapsed.total_seconds()}秒")
except Timeout:
print("請求超時!")
在這個例子中,我們設定了兩種超時:連線超時(3秒)和讀取超時(10秒)。如果連線或讀取操作超過了指定的時間,Requests 會引發 Timeout
異常。
錯誤與例外處理
Requests 提供了豐富的異常類別,使錯誤處理變得更加精確:
import requests
from requests.exceptions import RequestException, HTTPError, ConnectionError, Timeout
try:
response = requests.get('https://api.example.com/data')
response.raise_for_status() # 引發 HTTP 錯誤
data = response.json()
except HTTPError as e:
print(f"HTTP 錯誤: {e}")
except ConnectionError as e:
print(f"連線錯誤: {e}")
except Timeout as e:
print(f"請求超時: {e}")
except RequestException as e:
print(f"其他請求錯誤: {e}")
except Exception as e:
print(f"其他錯誤: {e}")
透過捕捉不同類別的異常,我們可以針對不同的錯誤情況採取不同的處理策略。
深入挖掘 Requests 的進階功能
使用 Session 物件持久化引數
在需要保持工作階段狀態的場景中,Session
物件非常有用:
import requests
# 建立工作階段物件
session = requests.Session()
# 設定工作階段級別的引數
session.headers.update({'User-Agent': 'Mozilla/5.0', 'Accept-Language': 'zh-TW'})
session.auth = ('username', 'password')
session.cookies.set('session_token', 'abc123')
# 使用工作階段傳送請求
# 所有引數都會自動應用
response1 = session.get('https://api.example.com/profile')
response2 = session.get('https://api.example.com/settings')
# 工作階段會自動儲存和傳送 cookies
print(f"Cookies: {session.cookies}")
使用 Session
物件可以避免在每個請求中重複設定相同的引數,同時也能自動處理 cookies,這使得模擬完整的使用者工作階段變得簡單。
揭示請求與回應的結構
Requests 提供了方便的屬性來檢查請求和回應的詳細資訊:
import requests
response = requests.get('https://api.github.com', headers={'Accept': 'application/vnd.github.v3+json'})
# 檢查請求資訊
print(f"請求 URL: {response.request.url}")
print(f"請求方法: {response.request.method}")
print(f"請求標頭: {response.request.headers}")
print(f"請求體: {response.request.body}")
# 檢查回應資訊
print(f"回應版本: {response.raw.version}")
print(f"回應狀態: {response.status_code} {response.reason}")
print(f"回應標頭: {response.headers}")
print(f"回應編碼: {response.encoding}")
這些資訊在除錯過程中非常有用,可以幫助我們瞭解請求和回應的完整細節。
使用預備請求
有時候,我們需要更細粒度的控制請求的準備和傳送過程:
import requests
from requests import Request, Session
# 建立工作階段
session = Session()
# 準備請求
req = Request('POST', 'https://api.example.com/data',
data={'key': 'value'},
headers={'X-Custom-Header': 'value'})
# 準備請求
prepped = session.prepare_request(req)
# 修改準備好的請求
prepped.headers['X-Another-Header'] = 'another_value'
# 傳送請求
response = session.send(preppe