본문 바로가기
DEVEL/PYTHON

파이썬 requests 완전 정복: 대안 라이브러리 비교, 장단점, 실전 예제

by codebyai 2025. 9. 2.
반응형

웹 개발, 크롤링, 내부 API 연동까지… 파이썬에서 HTTP를 다룬다면 가장 먼저 떠오르는 라이브러리가 바로 requests 입니다. “인간을 위한(human-friendly)” API를 표방할 만큼 문법이 직관적이고 실무 채택률도 매우 높죠. 이 글에서는 requests의 핵심 사용법을 정리하고, HTTPX, urllib3, aiohttp, urllib.request(표준 라이브러리) 와 비교해 언제 무엇을 선택할지 명확하게 안내합니다. 각 라이브러리별 장단점, 코드 예제, 베스트 프랙티스까지 한 번에 정리해 드려요.


1) 왜 requests 인가?

  • 가독성/간결성 최고: requests.get(url)만으로도 충분히 읽기 쉽고 직관적
  • 세션/쿠키 관리: Session()으로 커넥션 재사용, 쿠키 자동 유지
  • 폼/JSON/파일 업로드가 쉬움
  • 광범위한 문서/예시/질문답변: 문제 생겨도 검색이 잘 됨
import requests

# GET + 쿼리스트링
r = requests.get("https://api.example.com/search", params={"q": "python"})
r.raise_for_status()
data = r.json()

# POST JSON
r = requests.post("https://api.example.com/login", json={"id": "kim", "pw": "1234"})
token = r.json()["token"]

# 세션 재사용(쿠키/커넥션)
with requests.Session() as s:
    s.headers.update({"Authorization": f"Bearer {token}"})
    r1 = s.get("https://api.example.com/me")
    r2 = s.post("https://api.example.com/upload", files={"file": open("a.png", "rb")})

2) 비교 대상 한눈에 보기

라이브러리 동기/비동기 강점 약점 추천 상황
requests 동기 쉬운 문법, 에코시스템 풍부, 학습 곡선 낮음 비동기 부재, HTTP/2 한계 빠르게 안정적인 동기 코드 필요 시
HTTPX 동기 + 비동기 requests와 유사 API, async 지원, HTTP/2 자료가 상대적으로 적음 비동기/HTTP/2 필요할 때
urllib3 동기 저수준 제어, 리트라이, 커넥션 풀 코드 장황 고급 커스텀 제어 필요 시
aiohttp 비동기 고성능 동시성, 스트리밍, 웹소켓 async/await 학습 필요 대량 동시 요청/웹소켓
urllib.request 동기 표준 라이브러리 사용성 낮음 패키지 설치 제한 환경

3) 실전 예제 모음

3-1. requests 기본/중급

import requests

try:
    r = requests.get("https://example.com/api", timeout=(3.05, 10))
    r.raise_for_status()
except requests.Timeout:
    print("타임아웃!")
except requests.HTTPError as e:
    print("HTTP 에러:", e.response.status_code)
import requests
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter

s = requests.Session()
retry = Retry(total=5, backoff_factor=0.5, status_forcelist=[429, 500, 502, 503, 504])
s.mount("https://", HTTPAdapter(max_retries=retry))

r = s.get("https://api.example.com/stable-endpoint", timeout=10)
# 대용량 다운로드
with requests.get("https://example.com/big.zip", stream=True) as r:
    with open("big.zip", "wb") as out:
        for chunk in r.iter_content(chunk_size=1024*64):
            out.write(chunk)

3-2. HTTPX 동기/비동기

import httpx

with httpx.Client(http2=True) as client:
    r = client.get("https://www.example.com")
    print(r.text[:200])
import asyncio, httpx

async def fetch(client, url):
    r = await client.get(url)
    return r.text[:80]

async def main():
    urls = [f"https://httpbin.org/delay/1?i={i}" for i in range(10)]
    async with httpx.AsyncClient(http2=True) as client:
        results = await asyncio.gather(*(fetch(client, u) for u in urls))
    print(results)

asyncio.run(main())

3-3. aiohttp (비동기 + 웹소켓)

import asyncio, aiohttp

async def fetch(session, url):
    async with session.get(url) as r:
        return await r.text()

async def main():
    urls = [f"https://httpbin.org/delay/1?i={i}" for i in range(20)]
    async with aiohttp.ClientSession() as session:
        results = await asyncio.gather(*(fetch(session, u) for u in urls))
    print(len(results))

asyncio.run(main())

3-4. urllib3

import urllib3, json

http = urllib3.PoolManager()
r = http.request("GET", "https://httpbin.org/json")
data = json.loads(r.data.decode())
print(data["slideshow"]["title"])

3-5. urllib.request

from urllib.request import Request, urlopen
import json

req = Request("https://httpbin.org/get", headers={"User-Agent": "Stdlib"})
with urlopen(req) as resp:
    body = resp.read().decode()
    print(json.loads(body))

4) 베스트 프랙티스

  1. 항상 타임아웃 지정
  2. 리트라이 + 백오프 전략
  3. 세션/커넥션 재사용
  4. 스트리밍 다운로드
  5. 지표/로깅
  6. 헤더/캐시 제어
  7. SSL/프록시 정책 명확화
  8. 비동기 필요성 판단
  9. HTTP/2 고려
  10. 우아한 종료

5) 선택 가이드

  • 내부 API/크롤링 → requests
  • 향후 비동기 확장 → HTTPX
  • 고급 커스텀 제어 → urllib3
  • 대규모 동시성/웹소켓 → aiohttp
  • 패키지 설치 제한 → urllib.request

6) 마무리

빠르고 안전한 동기 HTTP 호출이 목적이라면 requests가 기본값입니다. 성능/동시성/HTTP/2/웹소켓이 핵심이라면 HTTPX 또는 aiohttp를 고려하세요. 장기적으로는 타임아웃/리트라이 표준화, 로깅/메트릭을 팀 규약으로 묶어두면 운영 품질이 크게 올라갑니다.

반응형