HTTP Requests
Learn how to communicate with web APIs using Python's requests library.
What is requests?โ
requests is the most popular library in Python for sending HTTP requests. With its simple and intuitive API, you can easily communicate with web servers.
Key Featuresโ
- Simple and intuitive API
- Automatic JSON encoding/decoding
- Session management and cookie handling
- File upload support
- Configurable timeouts
Installationโ
pip install requests
Basic GET Requestโ
Let's start with the most basic GET request.
import requests
# ๊ธฐ๋ณธ GET ์์ฒญ
response = requests.get('https://api.github.com')
# ์๋ต ํ์ธ
print(response.status_code) # 200
print(response.text) # ์๋ต ๋ณธ ๋ฌธ
print(response.json()) # JSON ํ์์ผ๋ก ํ์ฑ
Adding Query Parametersโ
# 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 Requestsโ
Use POST requests when sending data to the server.
# 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())
File Uploadโ
# ๋จ์ผ ํ์ผ ์
๋ก๋
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 and DELETE Requestsโ
Use these to update or delete resources.
# 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
Setting Headersโ
You can pass additional information through request headers.
# ๊ธฐ๋ณธ ํค๋ ์ค์
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)
Authenticationโ
Various authentication methods are supported.
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 Processingโ
You can easily handle JSON data.
# 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'}
)
Timeout Settingsโ
Prevent indefinite waiting due to network issues.
# ์ฐ๊ฒฐ ํ์์์ 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)
Error Handlingโ
Different HTTP errors should be handled appropriately.
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)}")
Using Sessionsโ
When making multiple requests, using sessions is more efficient.
# ์ธ์
์์ฑ
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')
Retry Settingsโ
Automatic retries can be performed in case of network issues.
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')
Practical Examplesโ
Example 1: Getting Weather Information with 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")
Example 2: Retrieving Repository Information with 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']}")
Example 3: Creating a REST API Clientโ
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}")
Example 4: Displaying Download Progressโ
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")
Frequently Asked Questionsโ
Q1. What's the difference between requests and urllib?โ
A: requests is a more user-friendly library built on top of urllib. requests provides convenient features such as simple API, automatic JSON processing, and session management.
# 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. How do you download large files?โ
A: Use the stream=True option to download in chunks.
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. Getting an SSL certificate error.โ
A: In development environments, you can use verify=False, but this is not recommended in production.
# ๊ฐ๋ฐ ํ๊ฒฝ์์๋ง ์ฌ์ฉ
response = requests.get(url, verify=False)
# ํ๋ก๋์
: ์ธ์ฆ์ ๊ฒฝ๋ก ์ง์
response = requests.get(url, verify='/path/to/certfile')
Q4. How do you configure a proxy?โ
A: Use the proxies parameter.
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. What if the response isn't JSON?โ
A: Use the appropriate attribute depending on the response type.
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
Next Stepsโ
If you've mastered HTTP requests with requests, learn these topics:
- Web Scraping - Extract data from web pages with BeautifulSoup
- Asynchronous Requests - Process multiple requests simultaneously with
aiohttp - API Development - Create your own REST API with FastAPI
- Authentication - Advanced authentication methods like OAuth 2.0, JWT