Saltar al contenido principal

HTTP ์š”์ฒญ

Python์˜ requests ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์›น API์™€ ํ†ต์‹ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์›Œ๋ด…์‹œ๋‹ค.

requests๋ž€?โ€‹

requests๋Š” Python์—์„œ HTTP ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ธ API๋กœ ์›น ์„œ๋ฒ„์™€ ์‰ฝ๊ฒŒ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์š” ํŠน์ง•โ€‹

  • ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ธ API
  • ์ž๋™ JSON ์ธ์ฝ”๋”ฉ/๋””์ฝ”๋”ฉ
  • ์„ธ์…˜ ๊ด€๋ฆฌ ๋ฐ ์ฟ ํ‚ค ์ฒ˜๋ฆฌ
  • ํŒŒ์ผ ์—…๋กœ๋“œ ์ง€์›
  • ํƒ€์ž„์•„์›ƒ ์„ค์ • ๊ฐ€๋Šฅ

์„ค์น˜ํ•˜๊ธฐโ€‹

pip install requests

๊ธฐ๋ณธ GET ์š”์ฒญโ€‹

๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ GET ์š”์ฒญ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ด…์‹œ๋‹ค.

import requests

# ๊ธฐ๋ณธ GET ์š”์ฒญ
response = requests.get('https://api.github.com')

# ์‘๋‹ต ํ™•์ธ
print(response.status_code) # 200
print(response.text) # ์‘๋‹ต ๋ณธ๋ฌธ
print(response.json()) # JSON ํ˜•์‹์œผ๋กœ ํŒŒ์‹ฑ

์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์ถ”๊ฐ€โ€‹

# URL์— ์ง์ ‘ ์ž‘์„ฑ
response = requests.get('https://api.github.com/search/repositories?q=python')

# params ๋”•์…”๋„ˆ๋ฆฌ ์‚ฌ์šฉ (๊ถŒ์žฅ)
params = {
'q': 'python',
'sort': 'stars',
'order': 'desc'
}
response = requests.get('https://api.github.com/search/repositories', params=params)

print(response.url) # ์‹ค์ œ ์š”์ฒญ๋œ URL ํ™•์ธ

POST ์š”์ฒญโ€‹

๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„๋กœ ์ „์†กํ•  ๋•Œ POST ์š”์ฒญ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

# Form ๋ฐ์ดํ„ฐ ์ „์†ก
data = {
'username': 'john',
'password': 'secret123'
}
response = requests.post('https://httpbin.org/post', data=data)

# JSON ๋ฐ์ดํ„ฐ ์ „์†ก
json_data = {
'name': 'John Doe',
'email': 'john@example.com',
'age': 30
}
response = requests.post('https://httpbin.org/post', json=json_data)

print(response.json())

ํŒŒ์ผ ์—…๋กœ๋“œโ€‹

# ๋‹จ์ผ ํŒŒ์ผ ์—…๋กœ๋“œ
files = {'file': open('report.pdf', 'rb')}
response = requests.post('https://httpbin.org/post', files=files)

# ํŒŒ์ผ๋ช… ์ง€์ •
files = {
'file': ('report.pdf', open('report.pdf', 'rb'), 'application/pdf')
}
response = requests.post('https://httpbin.org/post', files=files)

# ์—ฌ๋Ÿฌ ํŒŒ์ผ ์—…๋กœ๋“œ
files = {
'file1': open('image1.jpg', 'rb'),
'file2': open('image2.jpg', 'rb')
}
response = requests.post('https://httpbin.org/post', files=files)

PUT๊ณผ DELETE ์š”์ฒญโ€‹

๋ฆฌ์†Œ์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

# PUT ์š”์ฒญ (์ „์ฒด ์—…๋ฐ์ดํŠธ)
update_data = {
'id': 1,
'title': 'Updated Title',
'completed': True
}
response = requests.put('https://jsonplaceholder.typicode.com/todos/1', json=update_data)

# PATCH ์š”์ฒญ (๋ถ€๋ถ„ ์—…๋ฐ์ดํŠธ)
partial_data = {'completed': True}
response = requests.patch('https://jsonplaceholder.typicode.com/todos/1', json=partial_data)

# DELETE ์š”์ฒญ
response = requests.delete('https://jsonplaceholder.typicode.com/todos/1')
print(response.status_code) # 200 ๋˜๋Š” 204

ํ—ค๋” ์„ค์ •โ€‹

์š”์ฒญ ํ—ค๋”๋ฅผ ํ†ตํ•ด ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# ๊ธฐ๋ณธ ํ—ค๋” ์„ค์ •
headers = {
'User-Agent': 'MyApp/1.0',
'Accept': 'application/json',
'Content-Type': 'application/json'
}
response = requests.get('https://api.github.com', headers=headers)

# API ํ‚ค ์ธ์ฆ
headers = {
'Authorization': 'Bearer YOUR_API_KEY',
'X-API-Key': 'YOUR_API_KEY'
}
response = requests.get('https://api.example.com/data', headers=headers)

์ธ์ฆโ€‹

๋‹ค์–‘ํ•œ ์ธ์ฆ ๋ฐฉ๋ฒ•์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

from requests.auth import HTTPBasicAuth, HTTPDigestAuth

# Basic ์ธ์ฆ
response = requests.get(
'https://api.example.com/protected',
auth=HTTPBasicAuth('username', 'password')
)

# ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•
response = requests.get(
'https://api.example.com/protected',
auth=('username', 'password')
)

# Bearer Token ์ธ์ฆ
headers = {'Authorization': 'Bearer YOUR_ACCESS_TOKEN'}
response = requests.get('https://api.example.com/data', headers=headers)

# OAuth 2.0
from requests_oauthlib import OAuth2Session

oauth = OAuth2Session(client_id, token=token)
response = oauth.get('https://api.example.com/protected')

JSON ์ฒ˜๋ฆฌโ€‹

JSON ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# JSON ์‘๋‹ต ํŒŒ์‹ฑ
response = requests.get('https://api.github.com/users/github')
data = response.json()

print(data['name'])
print(data['public_repos'])

# JSON ์š”์ฒญ ์ „์†ก
payload = {
'name': 'John',
'email': 'john@example.com',
'settings': {
'notifications': True,
'theme': 'dark'
}
}
response = requests.post('https://api.example.com/users', json=payload)

# ์ปค์Šคํ…€ JSON ์ธ์ฝ”๋”
import json

class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)

response = requests.post(
'https://api.example.com/data',
data=json.dumps(payload, cls=CustomEncoder),
headers={'Content-Type': 'application/json'}
)

ํƒ€์ž„์•„์›ƒ ์„ค์ •โ€‹

๋„คํŠธ์›Œํฌ ๋ฌธ์ œ๋กœ ์ธํ•œ ๋ฌดํ•œ ๋Œ€๊ธฐ๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

# ์—ฐ๊ฒฐ ํƒ€์ž„์•„์›ƒ 5์ดˆ, ์ฝ๊ธฐ ํƒ€์ž„์•„์›ƒ 10์ดˆ
try:
response = requests.get('https://api.example.com', timeout=(5, 10))
except requests.exceptions.Timeout:
print("์š”์ฒญ ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")

# ์ „์ฒด ํƒ€์ž„์•„์›ƒ 10์ดˆ
response = requests.get('https://api.example.com', timeout=10)

# ํƒ€์ž„์•„์›ƒ ์—†์Œ (๊ถŒ์žฅํ•˜์ง€ ์•Š์Œ)
response = requests.get('https://api.example.com', timeout=None)

์—๋Ÿฌ ์ฒ˜๋ฆฌโ€‹

๋‹ค์–‘ํ•œ HTTP ์—๋Ÿฌ๋ฅผ ์ ์ ˆํžˆ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

import requests
from requests.exceptions import (
ConnectionError,
Timeout,
HTTPError,
RequestException
)

try:
response = requests.get('https://api.example.com/data', timeout=5)
response.raise_for_status() # 4xx, 5xx ์—๋Ÿฌ ๋ฐœ์ƒ

data = response.json()
print(data)

except ConnectionError:
print("์—ฐ๊ฒฐ ์‹คํŒจ: ๋„คํŠธ์›Œํฌ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.")
except Timeout:
print("์‹œ๊ฐ„ ์ดˆ๊ณผ: ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
except HTTPError as e:
print(f"HTTP ์—๋Ÿฌ: {e.response.status_code}")
if e.response.status_code == 404:
print("๋ฆฌ์†Œ์Šค๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
elif e.response.status_code == 401:
print("์ธ์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.")
elif e.response.status_code == 500:
print("์„œ๋ฒ„ ๋‚ด๋ถ€ ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค.")
except RequestException as e:
print(f"์š”์ฒญ ์‹คํŒจ: {str(e)}")

์„ธ์…˜ ์‚ฌ์šฉโ€‹

์—ฌ๋Ÿฌ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ์„ธ์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

# ์„ธ์…˜ ์ƒ์„ฑ
session = requests.Session()

# ๋ชจ๋“  ์š”์ฒญ์— ์ ์šฉ๋  ํ—ค๋” ์„ค์ •
session.headers.update({
'User-Agent': 'MyApp/1.0',
'Authorization': 'Bearer YOUR_TOKEN'
})

# ์„ธ์…˜์œผ๋กœ ์—ฌ๋Ÿฌ ์š”์ฒญ
response1 = session.get('https://api.example.com/users')
response2 = session.get('https://api.example.com/posts')
response3 = session.post('https://api.example.com/comments', json={'text': 'Hello'})

# ์ฟ ํ‚ค ์ž๋™ ๊ด€๋ฆฌ
login_data = {'username': 'john', 'password': 'secret'}
session.post('https://example.com/login', data=login_data)

# ๋กœ๊ทธ์ธ ํ›„ ์ธ์ฆ๋œ ์š”์ฒญ
response = session.get('https://example.com/dashboard')

# ์„ธ์…˜ ์ข…๋ฃŒ
session.close()

# Context Manager ์‚ฌ์šฉ (๊ถŒ์žฅ)
with requests.Session() as session:
session.headers.update({'Authorization': 'Bearer TOKEN'})
response = session.get('https://api.example.com/data')

์žฌ์‹œ๋„ ์„ค์ •โ€‹

๋„คํŠธ์›Œํฌ ๋ฌธ์ œ ์‹œ ์ž๋™์œผ๋กœ ์žฌ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

# ์žฌ์‹œ๋„ ์ „๋žต ์„ค์ •
retry_strategy = Retry(
total=3, # ์ตœ๋Œ€ 3๋ฒˆ ์žฌ์‹œ๋„
backoff_factor=1, # 1์ดˆ, 2์ดˆ, 4์ดˆ ๋Œ€๊ธฐ
status_forcelist=[429, 500, 502, 503, 504],
method_whitelist=["HEAD", "GET", "OPTIONS", "POST"]
)

adapter = HTTPAdapter(max_retries=retry_strategy)
session = requests.Session()
session.mount("https://", adapter)
session.mount("http://", adapter)

# ์ž๋™ ์žฌ์‹œ๋„ ์ ์šฉ
response = session.get('https://api.example.com/data')

์‹ค์ „ ์˜ˆ์ œโ€‹

์˜ˆ์ œ 1: OpenWeather API๋กœ ๋‚ ์”จ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐโ€‹

import requests

def get_weather(city, api_key):
"""ํŠน์ • ๋„์‹œ์˜ ๋‚ ์”จ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค."""
base_url = "http://api.openweathermap.org/data/2.5/weather"

params = {
'q': city,
'appid': api_key,
'units': 'metric', # ์„ญ์”จ ์˜จ๋„
'lang': 'kr' # ํ•œ๊ตญ์–ด
}

try:
response = requests.get(base_url, params=params, timeout=10)
response.raise_for_status()

data = response.json()

weather_info = {
'city': data['name'],
'temperature': data['main']['temp'],
'feels_like': data['main']['feels_like'],
'humidity': data['main']['humidity'],
'description': data['weather'][0]['description'],
'wind_speed': data['wind']['speed']
}

return weather_info

except requests.exceptions.RequestException as e:
print(f"๋‚ ์”จ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: {e}")
return None

# ์‚ฌ์šฉ ์˜ˆ์‹œ
api_key = "YOUR_API_KEY"
weather = get_weather("Seoul", api_key)

if weather:
print(f"๋„์‹œ: {weather['city']}")
print(f"์˜จ๋„: {weather['temperature']}ยฐC")
print(f"์ฒด๊ฐ์˜จ๋„: {weather['feels_like']}ยฐC")
print(f"์Šต๋„: {weather['humidity']}%")
print(f"๋‚ ์”จ: {weather['description']}")
print(f"ํ’์†: {weather['wind_speed']} m/s")

์˜ˆ์ œ 2: GitHub API๋กœ ์ €์žฅ์†Œ ์ •๋ณด ์กฐํšŒโ€‹

import requests
from typing import List, Dict

class GitHubAPI:
def __init__(self, token=None):
self.base_url = "https://api.github.com"
self.session = requests.Session()

if token:
self.session.headers.update({
'Authorization': f'token {token}',
'Accept': 'application/vnd.github.v3+json'
})

def get_user_info(self, username: str) -> Dict:
"""์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค."""
url = f"{self.base_url}/users/{username}"
response = self.session.get(url)
response.raise_for_status()
return response.json()

def get_user_repos(self, username: str) -> List[Dict]:
"""์‚ฌ์šฉ์ž์˜ ์ €์žฅ์†Œ ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค."""
url = f"{self.base_url}/users/{username}/repos"
params = {
'sort': 'updated',
'per_page': 10
}
response = self.session.get(url, params=params)
response.raise_for_status()
return response.json()

def search_repositories(self, query: str, language=None) -> List[Dict]:
"""์ €์žฅ์†Œ๋ฅผ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค."""
url = f"{self.base_url}/search/repositories"

search_query = query
if language:
search_query += f" language:{language}"

params = {
'q': search_query,
'sort': 'stars',
'order': 'desc',
'per_page': 10
}

response = self.session.get(url, params=params)
response.raise_for_status()
return response.json()['items']

# ์‚ฌ์šฉ ์˜ˆ์‹œ
github = GitHubAPI()

# ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ
user = github.get_user_info('torvalds')
print(f"์ด๋ฆ„: {user['name']}")
print(f"ํŒ”๋กœ์›Œ: {user['followers']}")
print(f"๊ณต๊ฐœ ์ €์žฅ์†Œ: {user['public_repos']}")

# ์ €์žฅ์†Œ ๊ฒ€์ƒ‰
repos = github.search_repositories('machine learning', language='python')
for repo in repos[:5]:
print(f"\n{repo['full_name']}")
print(f"โญ {repo['stargazers_count']} | ๐Ÿด {repo['forks_count']}")
print(f"์„ค๋ช…: {repo['description']}")

์˜ˆ์ œ 3: REST API ํด๋ผ์ด์–ธํŠธ ๋งŒ๋“ค๊ธฐโ€‹

import requests
from typing import Optional, Dict, Any
import json

class APIClient:
"""๋ฒ”์šฉ REST API ํด๋ผ์ด์–ธํŠธ"""

def __init__(self, base_url: str, api_key: Optional[str] = None):
self.base_url = base_url.rstrip('/')
self.session = requests.Session()

# ๊ธฐ๋ณธ ํ—ค๋” ์„ค์ •
self.session.headers.update({
'Content-Type': 'application/json',
'User-Agent': 'Python-API-Client/1.0'
})

# API ํ‚ค๊ฐ€ ์žˆ์œผ๋ฉด ํ—ค๋”์— ์ถ”๊ฐ€
if api_key:
self.session.headers.update({'Authorization': f'Bearer {api_key}'})

def _make_request(
self,
method: str,
endpoint: str,
**kwargs
) -> requests.Response:
"""HTTP ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค."""
url = f"{self.base_url}/{endpoint.lstrip('/')}"

try:
response = self.session.request(method, url, timeout=30, **kwargs)
response.raise_for_status()
return response
except requests.exceptions.HTTPError as e:
print(f"HTTP Error: {e.response.status_code}")
print(f"Response: {e.response.text}")
raise
except requests.exceptions.RequestException as e:
print(f"Request Error: {str(e)}")
raise

def get(self, endpoint: str, params: Optional[Dict] = None) -> Dict[str, Any]:
"""GET ์š”์ฒญ"""
response = self._make_request('GET', endpoint, params=params)
return response.json()

def post(self, endpoint: str, data: Optional[Dict] = None) -> Dict[str, Any]:
"""POST ์š”์ฒญ"""
response = self._make_request('POST', endpoint, json=data)
return response.json()

def put(self, endpoint: str, data: Optional[Dict] = None) -> Dict[str, Any]:
"""PUT ์š”์ฒญ"""
response = self._make_request('PUT', endpoint, json=data)
return response.json()

def patch(self, endpoint: str, data: Optional[Dict] = None) -> Dict[str, Any]:
"""PATCH ์š”์ฒญ"""
response = self._make_request('PATCH', endpoint, json=data)
return response.json()

def delete(self, endpoint: str) -> bool:
"""DELETE ์š”์ฒญ"""
response = self._make_request('DELETE', endpoint)
return response.status_code in [200, 204]

# ์‚ฌ์šฉ ์˜ˆ์‹œ
client = APIClient('https://jsonplaceholder.typicode.com')

# GET ์š”์ฒญ
posts = client.get('/posts', params={'userId': 1})
print(f"๊ฒŒ์‹œ๊ธ€ ์ˆ˜: {len(posts)}")

# POST ์š”์ฒญ
new_post = client.post('/posts', data={
'title': 'New Post',
'body': 'This is a new post',
'userId': 1
})
print(f"์ƒ์„ฑ๋œ ๊ฒŒ์‹œ๊ธ€ ID: {new_post['id']}")

# PUT ์š”์ฒญ
updated_post = client.put('/posts/1', data={
'id': 1,
'title': 'Updated Title',
'body': 'Updated body',
'userId': 1
})

# DELETE ์š”์ฒญ
success = client.delete('/posts/1')
print(f"์‚ญ์ œ ์„ฑ๊ณต: {success}")

์˜ˆ์ œ 4: ๋‹ค์šด๋กœ๋“œ ์ง„ํ–‰๋ฅ  ํ‘œ์‹œโ€‹

import requests
from tqdm import tqdm

def download_file(url: str, filename: str):
"""ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  ์ง„ํ–‰๋ฅ ์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค."""
response = requests.get(url, stream=True)
response.raise_for_status()

total_size = int(response.headers.get('content-length', 0))

with open(filename, 'wb') as file, tqdm(
desc=filename,
total=total_size,
unit='B',
unit_scale=True,
unit_divisor=1024,
) as progress_bar:
for chunk in response.iter_content(chunk_size=8192):
file.write(chunk)
progress_bar.update(len(chunk))

print(f"๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ: {filename}")

# ์‚ฌ์šฉ ์˜ˆ์‹œ
url = "https://example.com/large-file.zip"
download_file(url, "downloaded-file.zip")

์ž์ฃผ ๋ฌป๋Š” ์งˆ๋ฌธโ€‹

Q1. requests์™€ urllib์˜ ์ฐจ์ด์ ์€?โ€‹

A: requests๋Š” urllib ์œ„์— ๊ตฌ์ถ•๋œ ๋” ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. requests๋Š” ๊ฐ„๋‹จํ•œ API, ์ž๋™ JSON ์ฒ˜๋ฆฌ, ์„ธ์…˜ ๊ด€๋ฆฌ ๋“ฑ์˜ ํŽธ์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

# urllib (๋ณต์žกํ•จ)
import urllib.request
import json

request = urllib.request.Request(
'https://api.github.com',
headers={'User-Agent': 'Python'}
)
response = urllib.request.urlopen(request)
data = json.loads(response.read().decode())

# requests (๊ฐ„๋‹จํ•จ)
import requests

response = requests.get('https://api.github.com')
data = response.json()

Q2. ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ์€ ์–ด๋–ป๊ฒŒ ๋‹ค์šด๋กœ๋“œํ•˜๋‚˜์š”?โ€‹

A: stream=True ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฒญํฌ ๋‹จ์œ„๋กœ ๋‹ค์šด๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

response = requests.get(url, stream=True)
with open('large_file.zip', 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)

Q3. SSL ์ธ์ฆ์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.โ€‹

A: ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋Š” verify=False๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ํ”„๋กœ๋•์…˜์—์„œ๋Š” ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

# ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋งŒ ์‚ฌ์šฉ
response = requests.get(url, verify=False)

# ํ”„๋กœ๋•์…˜: ์ธ์ฆ์„œ ๊ฒฝ๋กœ ์ง€์ •
response = requests.get(url, verify='/path/to/certfile')

Q4. ํ”„๋ก์‹œ๋Š” ์–ด๋–ป๊ฒŒ ์„ค์ •ํ•˜๋‚˜์š”?โ€‹

A: proxies ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

proxies = {
'http': 'http://10.10.10.10:8000',
'https': 'http://10.10.10.10:8000',
}

response = requests.get('https://api.example.com', proxies=proxies)

Q5. ์‘๋‹ต์ด JSON์ด ์•„๋‹ ๋•Œ๋Š”?โ€‹

A: ์‘๋‹ต ์œ ํ˜•์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ์†์„ฑ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

response = requests.get(url)

# JSON
data = response.json()

# ํ…์ŠคํŠธ
text = response.text

# ๋ฐ”์ด๋„ˆ๋ฆฌ
binary = response.content

# ์ž๋™ ๊ฐ์ง€
if 'application/json' in response.headers.get('Content-Type', ''):
data = response.json()
else:
text = response.text

๋‹ค์Œ ๋‹จ๊ณ„โ€‹

requests๋กœ HTTP ์š”์ฒญ์„ ๋งˆ์Šคํ„ฐํ–ˆ๋‹ค๋ฉด, ๋‹ค์Œ ์ฃผ์ œ๋ฅผ ํ•™์Šตํ•ด๋ณด์„ธ์š”:

  1. ์›น ์Šคํฌ๋ž˜ํ•‘ - BeautifulSoup์œผ๋กœ ์›น ํŽ˜์ด์ง€์—์„œ ๋ฐ์ดํ„ฐ ์ถ”์ถœํ•˜๊ธฐ
  2. ๋น„๋™๊ธฐ ์š”์ฒญ - aiohttp๋กœ ๋™์‹œ์— ์—ฌ๋Ÿฌ ์š”์ฒญ ์ฒ˜๋ฆฌํ•˜๊ธฐ
  3. API ๊ฐœ๋ฐœ - FastAPI๋กœ ์ž์‹ ๋งŒ์˜ REST API ๋งŒ๋“ค๊ธฐ
  4. ์ธ์ฆ - OAuth 2.0, JWT ๋“ฑ ๊ณ ๊ธ‰ ์ธ์ฆ ๋ฐฉ๋ฒ•

์ฐธ๊ณ  ์ž๋ฃŒโ€‹