「PythonでAPIアクセスしてるけど、毎回新しい接続を作るのは無駄な気がする…」「大量のHTTPリクエストが遅くて困っている」そんな悩みを抱えていませんか?
実は、requests.Session()
を使うことで、アプリケーションのパフォーマンスを大幅に向上させることができます。特に複数のHTTPリクエストを送信する場合、TCP接続の再利用により最大90%の処理時間短縮が可能です。
この記事では、requests.Session().get()
の基本的な使い方から実践的な活用法まで、具体的なコード例とともに詳しく解説します。読み終わる頃には、効率的なHTTP通信を実装できるようになるでしょう。
requests.get()とrequests.Session().get()の基本的な違い
PythonでHTTPリクエストを送信する際、requests.get()
とrequests.Session().get()
には重要な違いがあります。この違いを理解することが、パフォーマンス向上への第一歩です。
接続方式の違い:短い接続 vs 持続的接続
requests.get()
は、リクエストごとに新しいセッションオブジェクトを作成し、リクエスト完了後に即座に接続を切断します。一方、requests.Session().get()
は一度確立したTCP接続を維持し、複数のリクエストで再利用します。
import requests
# 毎回新しい接続を作成(非効率)
response1 = requests.get('https://api.example.com/data1')
response2 = requests.get('https://api.example.com/data2')
# 接続を再利用(効率的)
session = requests.Session()
response1 = session.get('https://api.example.com/data1')
response2 = session.get('https://api.example.com/data2')
パフォーマンスに与える影響
実際のベンチマークテストでは、同一サーバーへの10,000回のリクエストにおいて以下の結果が報告されています:
requests.get()
使用時:38.56秒requests.Session()
使用時:3.06秒
この差は、TCP接続の確立とハンドシェイクにかかるオーバーヘッドによるものです。Session使用により、約90%の処理時間短縮が実現されています。
メモリ使用量の比較
Sessionオブジェクトは接続プール(デフォルトで10接続)を管理するため、わずかなメモリオーバーヘッドが発生します。しかし、大量のリクエストを処理する場合、全体的なリソース効率は大幅に改善されます。
requests.Sessionを使うべき5つのメリット
1. TCP接続の再利用による高速化
同一ホストへの複数リクエストで、既存のTCP接続を再利用できます。これにより、接続確立のオーバーヘッド(通常50-100ms)を削減できます。
import time
import requests
# 接続再利用なし
start = time.time()
for i in range(10):
requests.get('https://httpbin.org/delay/0')
print(f"通常のrequests: {time.time() - start:.2f}秒")
# 接続再利用あり
start = time.time()
session = requests.Session()
for i in range(10):
session.get('https://httpbin.org/delay/0')
print(f"Session使用: {time.time() - start:.2f}秒")
2. Cookie情報の自動保持
Sessionオブジェクトは、レスポンスで受信したCookieを自動的に保存し、次回のリクエストで送信します。ログイン状態の維持に特に有効です。
session = requests.Session()
# ログイン処理
login_data = {'username': 'user', 'password': 'pass'}
session.post('https://example.com/login', data=login_data)
# ログイン状態が保持されたままアクセス
protected_data = session.get('https://example.com/protected')
3. リクエスト設定の共通化
ヘッダー、認証情報、タイムアウト設定などを一度設定すれば、全てのリクエストに適用されます。
session = requests.Session()
session.headers.update({
'User-Agent': 'MyApp/1.0',
'Accept': 'application/json'
})
session.auth = ('username', 'password')
# すべてのリクエストに共通設定が適用される
response1 = session.get('https://api.example.com/endpoint1')
response2 = session.get('https://api.example.com/endpoint2')
4. セキュリティ向上
SSL/TLS設定の一元管理により、セキュリティポリシーの一貫性を保てます。
session = requests.Session()
session.verify = '/path/to/cert.pem' # 証明書検証
session.cert = ('/path/to/client.cert', '/path/to/client.key') # クライアント証明書
5. リソース効率の最適化
接続プールにより、システムリソースの効率的な利用が可能になります。
Session getの基本的な使い方と実装例
基本的なSessionオブジェクトの作成
import requests
# Sessionオブジェクトの作成
session = requests.Session()
# GETリクエストの実行
response = session.get('https://api.example.com/data')
print(response.json())
# セッションのクローズ(明示的に行う場合)
session.close()
with文を使った適切なリソース管理
推奨される方法は、with文を使用したコンテキストマネージャーの活用です:
import requests
with requests.Session() as session:
# リクエスト処理
response = session.get('https://api.example.com/data')
print(response.status_code)
# with文を抜ける際に自動的にセッションがクローズされる
共通設定の適用方法
with requests.Session() as session:
# 共通ヘッダーの設定
session.headers.update({
'Authorization': 'Bearer your-token',
'Content-Type': 'application/json'
})
# タイムアウト設定
session.timeout = 10
# プロキシ設定
session.proxies.update({
'http': 'http://proxy.example.com:8080',
'https': 'https://proxy.example.com:8080'
})
response = session.get('https://api.example.com/data')
実践的なコード例で学ぶSession活用法
API連続アクセスの高速化例
import requests
import time
def fetch_user_data_without_session(user_ids):
"""Session未使用の例"""
results = []
start_time = time.time()
for user_id in user_ids:
response = requests.get(f'https://api.example.com/users/{user_id}')
results.append(response.json())
print(f"Session未使用: {time.time() - start_time:.2f}秒")
return results
def fetch_user_data_with_session(user_ids):
"""Session使用の例"""
results = []
start_time = time.time()
with requests.Session() as session:
for user_id in user_ids:
response = session.get(f'https://api.example.com/users/{user_id}')
results.append(response.json())
print(f"Session使用: {time.time() - start_time:.2f}秒")
return results
# 使用例
user_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
data1 = fetch_user_data_without_session(user_ids)
data2 = fetch_user_data_with_session(user_ids)
ログインが必要なサイトへのアクセス
import requests
def scrape_protected_content():
with requests.Session() as session:
# ログイン処理
login_url = 'https://example.com/login'
login_data = {
'username': 'your_username',
'password': 'your_password',
'csrf_token': 'token_value'
}
# ログインページでCSRFトークンを取得
login_page = session.get(login_url)
# CSRFトークンの抽出ロジック(BeautifulSoupなどを使用)
# ログイン実行
login_response = session.post(login_url, data=login_data)
if login_response.status_code == 200:
# ログイン成功後、保護されたページにアクセス
protected_url = 'https://example.com/protected-data'
data_response = session.get(protected_url)
return data_response.text
else:
print("ログインに失敗しました")
return None
# 使用例
content = scrape_protected_content()
パフォーマンス最適化のベストプラクティス
接続プール設定の調整
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
def create_optimized_session():
session = requests.Session()
# リトライ戦略の設定
retry_strategy = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504],
)
# HTTPアダプターの設定
adapter = HTTPAdapter(
pool_connections=20, # 接続プール数
pool_maxsize=20, # プール内の最大接続数
max_retries=retry_strategy
)
session.mount("http://", adapter)
session.mount("https://", adapter)
return session
# 使用例
session = create_optimized_session()
タイムアウト設定の重要性
import requests
from requests.exceptions import Timeout, RequestException
def safe_request_with_timeout(url, timeout=(5, 10)):
"""
安全なリクエスト実行
timeout=(接続タイムアウト, 読み取りタイムアウト)
"""
try:
with requests.Session() as session:
response = session.get(url, timeout=timeout)
response.raise_for_status()
return response.json()
except Timeout:
print(f"タイムアウトが発生しました: {url}")
return None
except RequestException as e:
print(f"リクエストエラー: {e}")
return None
# 使用例
data = safe_request_with_timeout('https://api.example.com/slow-endpoint')
よくある問題と解決方法
セッションが切れる問題への対処
import requests
import time
class PersistentSession:
def __init__(self, base_url):
self.base_url = base_url
self.session = None
self.last_activity = None
self.session_timeout = 300 # 5分
def get_session(self):
current_time = time.time()
# セッションが存在しない、または期限切れの場合は新規作成
if (self.session is None or
self.last_activity is None or
current_time - self.last_activity > self.session_timeout):
if self.session:
self.session.close()
self.session = requests.Session()
self.authenticate() # 再認証
self.last_activity = current_time
return self.session
def authenticate(self):
"""認証処理(必要に応じて実装)"""
# ログイン処理やAPI Keyの設定など
self.session.headers.update({
'Authorization': 'Bearer your-token'
})
def get(self, endpoint, **kwargs):
session = self.get_session()
url = f"{self.base_url}/{endpoint}"
return session.get(url, **kwargs)
# 使用例
api = PersistentSession('https://api.example.com')
response = api.get('users/1')
メモリリークを避ける方法
Sessionオブジェクトは使用後に必ずクローズし、リソースの適切な解放を行うことが重要です。with文の使用やSessionManagerクラスによる管理を推奨します。
マルチスレッド環境での注意点
requests.Sessionはスレッドセーフではありません。マルチスレッド環境では、各スレッドで独立したSessionオブジェクトを使用するか、ThreadLocalStorageを活用してください。
まとめ
requests.Session().get()
は、Pythonでの効率的なHTTP通信を実現する強力なツールです。特に以下のような場面で威力を発揮します:
- 同一サーバーへの複数リクエスト
- ログイン状態の維持が必要な処理
- 大量データの取得処理
- APIの連続アクセス
この記事で紹介した5つのメリットを理解し、適切な設定とエラーハンドリングを組み合わせることで、パフォーマンスとセキュリティの両方を向上させることができます。ぜひこの記事の内容を参考に、あなたのPythonアプリケーションをより効率的にしてください。