HTTP ve API Tüketimi: requests Kütüphanesi
Şimdiye kadar Python ile kendi programlarımızı yazdık — veri işledik, dosya okuduk, veritabanıyla çalıştık. Ama modern yazılım dünyasında programlar tek başına çalışmaz. Hava durumu verisi bir API'dan gelir, ödeme işlemi başka bir servise gönderilir, kullanıcı kimliği üçüncü bir sistemden doğrulanır. Programlar sürekli birbirleriyle konuşur.
Bu konuşmanın dili HTTP'dir ve Python'da bu dili en kolay konuşmanın yolu requests kütüphanesidir. Bu derste requests'i sıfırdan öğrenecek, gerçek API'larla çalışacak ve production seviyesinde HTTP istekleri yapmayı kavrayacaksın.
1. Neden requests?
📞 Analoji: Telefon Görüşmesi
Bir arkadaşını aramak istiyorsun. İki yol var:
Zor yol: Telefon hattının fiziksel sinyallerini kendin yönet — bakır kabloya sinyal gönder, frekansları ayarla, handshake protokolünü kendin uygula.
Kolay yol: Telefonu aç, numarayı çevir, konuş.
Python'da HTTP isteği yapmak da böyle. socket ve http.client modülleriyle her şeyi elle yapabilirsin — ama requests kütüphanesi senin için "telefonu" hazırlar. Sen sadece "numarayı çevir ve konuş" kısmına odaklanırsın.
stdlib vs requests
Python'un yerleşik urllib modülü HTTP istekleri yapabilir ama kullanımı zahmetlidir:
# ❌ urllib ile — zahmetli
import urllib.request
import json
url = "https://jsonplaceholder.typicode.com/posts/1"
req = urllib.request.Request(url)
with urllib.request.urlopen(req) as response:
data = json.loads(response.read().decode())
print(data["title"])# ✅ requests ile — temiz ve okunabilir
import requests
response = requests.get("https://jsonplaceholder.typicode.com/posts/1")
data = response.json()
print(data["title"])Fark ortada. requests kütüphanesi Python topluluğunun fiili (de facto) HTTP standardıdır. PyPI'deki en çok indirilen paketlerden biridir — haftada 100 milyondan fazla indirme.
2. Kurulum ve İlk İstek
Kurulum
pip install requestsİlk GET İsteği
import requests
# JSONPlaceholder — ücretsiz test API'si
response = requests.get("https://jsonplaceholder.typicode.com/posts/1")
# Status code — isteğin sonucu
print(f"Status: {response.status_code}") # 200
# Yanıt başlıkları
print(f"Content-Type: {response.headers['Content-Type']}")
# Yanıt gövdesi — JSON olarak
data = response.json()
print(f"Başlık: {data['title']}")
print(f"Yazar ID: {data['userId']}")Bu kadar. Tek satırda HTTP isteği yaptın, yanıtı aldın ve JSON olarak parse ettin. response nesnesi isteğin tüm detaylarını taşır.
3. HTTP Metodları
REST API'larda dört temel HTTP metodu kullanılır. Her birinin requests'teki karşılığı çok basit:
GET — Veri Çekme
import requests
# Tüm kullanıcıları getir
response = requests.get("https://jsonplaceholder.typicode.com/users")
users = response.json()
print(f"Toplam {len(users)} kullanıcı")
for user in users[:3]:
print(f" {user['name']} — {user['email']}")POST — Yeni Kayıt Oluşturma
import requests
new_post = {
"title": "Python ile API",
"body": "requests kütüphanesi harika!",
"userId": 1
}
response = requests.post(
"https://jsonplaceholder.typicode.com/posts",
json=new_post # Otomatik JSON serialization + Content-Type header
)
print(f"Status: {response.status_code}") # 201 Created
created = response.json()
print(f"Oluşturulan ID: {created['id']}")json=new_post parametresi üç şeyi otomatik yapar: dict'i JSON string'e çevirir, Content-Type: application/json header'ını ekler ve body'ye yazar. Elle json.dumps() yapmanız gerekmez.
PUT — Tam Güncelleme
import requests
updated_post = {
"id": 1,
"title": "Güncellenmiş Başlık",
"body": "Yeni içerik",
"userId": 1
}
response = requests.put(
"https://jsonplaceholder.typicode.com/posts/1",
json=updated_post
)
print(f"Status: {response.status_code}") # 200
print(response.json()["title"])PATCH — Kısmi Güncelleme
import requests
# Sadece başlığı güncelle
response = requests.patch(
"https://jsonplaceholder.typicode.com/posts/1",
json={"title": "Sadece Başlık Değişti"}
)
print(response.json()["title"])PUT tüm kaynağı değiştirir, PATCH sadece belirtilen alanları değiştirir. Pratikte çoğu API ikisini de kabul eder ama semantik olarak fark budur.
DELETE — Silme
import requests
response = requests.delete("https://jsonplaceholder.typicode.com/posts/1")
print(f"Status: {response.status_code}") # 2004. Query Parameters
URL'ye ?key=value&key2=value2 eklemek yerine params parametresini kullan — daha temiz, daha güvenli:
import requests
# ❌ Elle URL birleştirme — özel karakterlerde sorun çıkar
response = requests.get(
"https://jsonplaceholder.typicode.com/posts?userId=1&_limit=3"
)
# ✅ params kullan — otomatik URL encoding
response = requests.get(
"https://jsonplaceholder.typicode.com/posts",
params={
"userId": 1,
"_limit": 3
}
)
print(f"URL: {response.url}")
# https://jsonplaceholder.typicode.com/posts?userId=1&_limit=3
posts = response.json()
for post in posts:
print(f" [{post['id']}] {post['title'][:40]}...")params dict'i otomatik olarak URL query string'ine dönüştürülür. Türkçe karakterler, boşluklar gibi özel karakterler de doğru şekilde encode edilir (URL encoding).
Birden fazla değer göndermek için:
# Aynı parametre birden fazla — /search?tag=python&tag=web
response = requests.get(
"https://api.example.com/search",
params=[("tag", "python"), ("tag", "web")]
)5. Headers ve Özel İstek Yapılandırması
HTTP header'ları isteğin meta bilgilerini taşır — content type, authentication, user agent gibi:
import requests
headers = {
"Accept": "application/json",
"User-Agent": "MyPythonApp/1.0",
"Accept-Language": "tr-TR",
"X-Custom-Header": "özel-değer"
}
response = requests.get(
"https://jsonplaceholder.typicode.com/posts/1",
headers=headers
)
# Yanıt header'larını incele
print(f"Server: {response.headers.get('Server')}")
print(f"Content-Type: {response.headers.get('Content-Type')}")
print(f"Content-Length: {response.headers.get('Content-Length')}")Header isimleri case-insensitive'dir — response.headers['content-type'] ve response.headers['Content-Type'] aynı şeydir. requests bunu otomatik yönetir.
6. Response Nesnesini Kullanma
requests.get() ve diğer metodlar Response nesnesi döndürür. Bu nesnenin birçok faydalı özelliği var:
import requests
response = requests.get("https://jsonplaceholder.typicode.com/posts/1")
# Status bilgileri
print(f"Status Code: {response.status_code}") # 200
print(f"Reason: {response.reason}") # OK
print(f"OK mu?: {response.ok}") # True (200-299 arası)
# İçerik — farklı formatlar
print(f"JSON: {response.json()}") # Dict olarak
print(f"Text: {response.text[:100]}") # String olarak
print(f"Bytes: {response.content[:50]}") # Bytes olarak
# Encoding
print(f"Encoding: {response.encoding}") # utf-8
# Yanıt süreleri
print(f"Yanıt süresi: {response.elapsed}") # 0:00:00.234567
print(f"Milisaniye: {response.elapsed.total_seconds() * 1000:.0f}ms")
# İstek bilgileri
print(f"İstek URL: {response.url}")
print(f"İstek metodu: {response.request.method}")
# Yönlendirme geçmişi
print(f"Redirect sayısı: {len(response.history)}")Status Code Kontrolü
import requests
response = requests.get("https://jsonplaceholder.typicode.com/posts/999")
# Yöntem 1: Manuel kontrol
if response.status_code == 200:
data = response.json()
elif response.status_code == 404:
print("Kayıt bulunamadı")
elif response.status_code >= 500:
print("Sunucu hatası")
# Yöntem 2: ok özelliği (200-299 arası True)
if response.ok:
data = response.json()
else:
print(f"Hata: {response.status_code}")
# Yöntem 3: raise_for_status() — hata varsa exception fırlatır
try:
response.raise_for_status()
data = response.json()
except requests.HTTPError as e:
print(f"HTTP Hatası: {e}")raise_for_status() en güvenli yöntemdir — 4xx ve 5xx status kodlarında HTTPError exception'ı fırlatır. Bu sayede hatalı yanıtları try/except ile temiz bir şekilde yakalar ve sessizce geçmezsin.
💡 İpucu:
response.json()yanıt JSON değilseJSONDecodeErrorfırlatır. Her zaman önce status code'u kontrol et, sonra.json()çağır.
7. Authentication (Kimlik Doğrulama)
API'ların çoğu kimlik doğrulama gerektirir. En yaygın yöntemler:
API Key
import requests
# Yöntem 1: Header'da
headers = {"X-API-Key": "your-secret-api-key-123"}
response = requests.get(
"https://api.example.com/data",
headers=headers
)
# Yöntem 2: Query parameter'da
response = requests.get(
"https://api.example.com/data",
params={"api_key": "your-secret-api-key-123"}
)API key nereye konulacağı API'nın dokümantasyonuna bağlıdır. Header'da göndermek daha güvenlidir — URL'ler loglarda görünür.
Bearer Token (JWT)
import requests
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
response = requests.get(
"https://api.example.com/profile",
headers={"Authorization": f"Bearer {token}"}
)
if response.ok:
profile = response.json()
print(f"Kullanıcı: {profile['name']}")Bearer token genellikle bir login endpoint'inden alınır ve sonraki isteklerde Authorization header'ında gönderilir. JWT (JSON Web Token) bunun en yaygın formatıdır.
Basic Auth
import requests
from requests.auth import HTTPBasicAuth
# Yöntem 1: HTTPBasicAuth
response = requests.get(
"https://api.example.com/secret",
auth=HTTPBasicAuth("username", "password")
)
# Yöntem 2: Kısa yol — tuple
response = requests.get(
"https://api.example.com/secret",
auth=("username", "password")
)Basic Auth, kullanıcı adı ve şifreyi Base64 ile encode edip Authorization header'ında gönderir. HTTPS olmadan kullanma — şifre düz metin olarak görünür.
⚠️ Dikkat: API key'lerini, token'ları ve şifreleri asla kaynak koduna yazma. Ortam değişkenleri (
os.environ) veya.envdosyası kullan.
import os
API_KEY = os.environ.get("MY_API_KEY")
if not API_KEY:
raise ValueError("MY_API_KEY ortam değişkeni tanımlı değil!")8. Dosya Upload ve Download
Dosya Upload
import requests
# Tek dosya
with open("rapor.pdf", "rb") as f:
response = requests.post(
"https://api.example.com/upload",
files={"document": f}
)
# Dosya adı ve MIME type belirterek
with open("foto.jpg", "rb") as f:
response = requests.post(
"https://api.example.com/upload",
files={"image": ("profil.jpg", f, "image/jpeg")}
)
# Dosya + form verisi birlikte
with open("foto.jpg", "rb") as f:
response = requests.post(
"https://api.example.com/upload",
files={"image": f},
data={"description": "Profil fotoğrafı", "user_id": "42"}
)files parametresi kullanıldığında requests otomatik olarak Content-Type: multipart/form-data header'ını ekler. json ve files parametrelerini aynı anda kullanamazsın — data ile birleştir.
Dosya Download
import requests
# Küçük dosyalar
response = requests.get("https://example.com/report.pdf")
with open("report.pdf", "wb") as f:
f.write(response.content)
# Büyük dosyalar — stream ile parça parça indir
response = requests.get(
"https://example.com/big-video.mp4",
stream=True
)
with open("video.mp4", "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f"İndirildi: {os.path.getsize('video.mp4') / 1024 / 1024:.1f} MB")stream=True dosyayı belleğe tamamen yüklemez — parça parça (chunk) indirir. GB boyutunda dosyalar için şarttır, yoksa RAM patlar.
9. Session Kullanımı
Aynı sunucuya birden fazla istek yapıyorsan Session nesnesi kullan. Avantajları:
Cookie persistence: Oturum çerezleri istekler arasında korunur
Connection reuse: TCP bağlantısı yeniden kullanılır (performans)
Ortak ayarlar: Header'lar, auth bilgileri tüm isteklerde geçerli
import requests
# ❌ Session olmadan — her istekte yeni bağlantı
for i in range(10):
response = requests.get(
"https://api.example.com/data",
headers={"Authorization": "Bearer my-token"}
)
# ✅ Session ile — bağlantı ve ayarlar paylaşılır
session = requests.Session()
session.headers.update({
"Authorization": "Bearer my-token",
"Accept": "application/json",
"User-Agent": "MyApp/1.0"
})
for i in range(10):
response = session.get("https://api.example.com/data")
# Header'lar otomatik eklenir, bağlantı yeniden kullanılırContext Manager ile Session
import requests
with requests.Session() as session:
# Login — cookie otomatik saklanır
session.post(
"https://example.com/login",
json={"username": "admin", "password": "secret"}
)
# Sonraki istekler — cookie otomatik gönderilir
profile = session.get("https://example.com/profile")
settings = session.get("https://example.com/settings")
print(f"Profil: {profile.json()['name']}")
print(f"Ayarlar: {settings.json()}")
# Session otomatik kapatılırwith bloğu içinde session kullanmak kaynakların düzgün temizlenmesini garanti eder.
10. Timeout ve Hata Yönetimi
Production kodunda timeout şarttır. Timeout olmadan istek sonsuza kadar bekleyebilir ve uygulamanı kilitler.
Timeout Ayarlama
import requests
# Tek timeout — bağlantı + okuma birlikte
try:
response = requests.get(
"https://api.example.com/data",
timeout=5 # 5 saniye
)
except requests.Timeout:
print("İstek zaman aşımına uğradı!")
# İki ayrı timeout — (bağlantı, okuma)
response = requests.get(
"https://api.example.com/data",
timeout=(3, 10) # 3sn bağlantı, 10sn okuma
)timeout=(3, 10) şu anlama gelir: Sunucuya bağlanmak için 3 saniye bekle, yanıt okumak için 10 saniye bekle. İki farklı timeout çünkü bağlantı kurulması hızlı ama yanıt yavaş olabilir.
Kapsamlı Hata Yönetimi
import requests
from requests.exceptions import (
ConnectionError, Timeout, HTTPError,
TooManyRedirects, RequestException
)
def safe_request(url, **kwargs):
"""Güvenli HTTP isteği — tüm hataları ele alır."""
try:
response = requests.get(url, timeout=10, **kwargs)
response.raise_for_status()
return response.json()
except ConnectionError:
print(f"Bağlantı hatası: {url} adresine ulaşılamıyor")
except Timeout:
print(f"Zaman aşımı: {url} yanıt vermedi")
except HTTPError as e:
print(f"HTTP hatası: {e.response.status_code} — {e.response.reason}")
except TooManyRedirects:
print(f"Çok fazla yönlendirme: {url}")
except RequestException as e:
print(f"Beklenmeyen hata: {e}")
return None
# Kullanım
data = safe_request("https://jsonplaceholder.typicode.com/posts/1")
if data:
print(f"Başlık: {data['title']}")Exception hiyerarşisi:
RequestException (en genel)
├── ConnectionError (ağ bağlantısı sorunu)
├── Timeout (zaman aşımı)
├── HTTPError (4xx, 5xx status kodları)
├── TooManyRedirects (sonsuz yönlendirme)
└── URLRequired, MissingSchema, ... (URL formatı hataları)Genel kural: Önce spesifik hataları yakala, en sonda RequestException ile gerisini yakala.
⚠️ Dikkat: Production kodunda
timeoutparametresini her zaman belirt. Varsayılan timeoutNone'dır — yani sonsuza kadar bekler. Bu sunucunun yanıt vermediği durumlarda uygulamanı kilitler.
11. Retry Mekanizması
Geçici hatalar (ağ kesintisi, sunucu aşırı yüklenme) için otomatik yeniden deneme çok önemli:
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
def create_session_with_retry(
retries=3,
backoff_factor=0.3,
status_forcelist=(500, 502, 503, 504)
):
"""Otomatik retry mekanizmalı session oluşturur."""
session = requests.Session()
retry_strategy = Retry(
total=retries, # Toplam deneme sayısı
backoff_factor=backoff_factor, # Denemeler arası bekleme çarpanı
status_forcelist=status_forcelist, # Bu kodlarda tekrar dene
allowed_methods=["GET", "POST"], # Bu metodlarda tekrar dene
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("https://", adapter)
session.mount("http://", adapter)
return session
# Kullanım
session = create_session_with_retry()
response = session.get(
"https://jsonplaceholder.typicode.com/posts/1",
timeout=10
)
print(response.json()["title"])backoff_factor=0.3 denemeler arasında artan bekleme süresi uygular: 0.3s → 0.6s → 1.2s. Bu sayede sunucuya baskı yapmadan tekrar denersin. status_forcelist hangi HTTP kodlarında tekrar deneneceğini belirler — genellikle 5xx (sunucu hataları) eklenir.
12. Gerçek Dünya Projesi: GitHub API
Şimdi öğrendiğimiz her şeyi birleştiren gerçek bir proje yazalım — GitHub API'sından kullanıcı ve repo bilgilerini çeken bir araç:
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from datetime import datetime
class GitHubClient:
"""GitHub API istemcisi."""
BASE_URL = "https://api.github.com"
def __init__(self, token=None):
self.session = requests.Session()
# Ortak header'lar
self.session.headers.update({
"Accept": "application/vnd.github.v3+json",
"User-Agent": "PythonGitHubClient/1.0"
})
# Opsiyonel authentication
if token:
self.session.headers["Authorization"] = f"Bearer {token}"
# Retry mekanizması
retry = Retry(total=3, backoff_factor=0.5,
status_forcelist=[500, 502, 503])
adapter = HTTPAdapter(max_retries=retry)
self.session.mount("https://", adapter)
def _request(self, endpoint, params=None):
"""Temel istek metodu — hata yönetimi dahil."""
url = f"{self.BASE_URL}{endpoint}"
try:
response = self.session.get(url, params=params, timeout=10)
response.raise_for_status()
return response.json()
except requests.HTTPError as e:
if e.response.status_code == 404:
return None
elif e.response.status_code == 403:
print("Rate limit aşıldı! Biraz bekleyin.")
return None
raise
except requests.RequestException as e:
print(f"İstek hatası: {e}")
return None
def get_user(self, username):
"""Kullanıcı bilgilerini getir."""
return self._request(f"/users/{username}")
def get_repos(self, username, sort="updated", per_page=10):
"""Kullanıcının repolarını getir."""
return self._request(
f"/users/{username}/repos",
params={"sort": sort, "per_page": per_page}
)
def search_repos(self, query, language=None, per_page=5):
"""Repo ara."""
q = query
if language:
q += f" language:{language}"
data = self._request(
"/search/repositories",
params={"q": q, "per_page": per_page, "sort": "stars"}
)
return data.get("items", []) if data else []
def close(self):
"""Session'ı kapat."""
self.session.close()
def __enter__(self):
return self
def __exit__(self, *args):
self.close()
# --- Kullanım ---
def main():
with GitHubClient() as github:
# 1. Kullanıcı bilgisi
user = github.get_user("torvalds")
if user:
print(f"👤 {user['name']}")
print(f" Bio: {user['bio']}")
print(f" Followers: {user['followers']:,}")
print(f" Public repos: {user['public_repos']}")
print()
# 2. Kullanıcının repoları
repos = github.get_repos("torvalds", per_page=5)
if repos:
print("📦 Son güncellenen repolar:")
for repo in repos:
stars = repo['stargazers_count']
lang = repo.get('language', 'N/A')
print(f" ⭐ {stars:>6,} {repo['name']} ({lang})")
print()
# 3. Repo arama
results = github.search_repos("web framework", language="python")
if results:
print("🔍 Python web framework araması:")
for repo in results:
stars = repo['stargazers_count']
print(f" ⭐ {stars:>6,} {repo['full_name']}")
print(f" {repo.get('description', '')[:60]}")
if __name__ == "__main__":
main()Bu projede neler kullandık:
Session — ortak header'lar, bağlantı yeniden kullanımı
Authentication — opsiyonel Bearer token
Retry — geçici hatalarda otomatik yeniden deneme
Timeout — her istekte 10 saniye limit
Hata yönetimi — 404, 403 (rate limit), genel hatalar
Query parameters — sort, per_page, search query
Context manager — kaynakların temiz yönetimi
13. Pagination (Sayfalama)
Çoğu API büyük veri setlerini sayfalara böler. Tüm veriyi çekmek için sayfalar arası dolaşman gerekir:
import requests
def get_all_posts(base_url, per_page=10):
"""Tüm sayfaları dolaşarak tüm kayıtları toplar."""
all_posts = []
page = 1
with requests.Session() as session:
while True:
response = session.get(
f"{base_url}/posts",
params={"_page": page, "_limit": per_page},
timeout=10
)
response.raise_for_status()
posts = response.json()
if not posts: # Boş sayfa — bitirdik
break
all_posts.extend(posts)
print(f" Sayfa {page}: {len(posts)} kayıt")
page += 1
return all_posts
# Kullanım
posts = get_all_posts("https://jsonplaceholder.typicode.com")
print(f"\nToplam: {len(posts)} post")Bazı API'lar Link header'ında sonraki sayfa URL'sini verir (GitHub gibi):
import requests
def get_paginated_github(url, per_page=30):
"""GitHub tarzı Link header ile pagination."""
all_items = []
with requests.Session() as session:
session.headers["Accept"] = "application/vnd.github.v3+json"
while url:
response = session.get(
url, params={"per_page": per_page}, timeout=10
)
response.raise_for_status()
all_items.extend(response.json())
# Link header'dan sonraki sayfa URL'sini çıkar
url = None
link_header = response.headers.get("Link", "")
for part in link_header.split(","):
if 'rel="next"' in part:
url = part.split(";")[0].strip(" <>")
return all_items14. Proxy ve SSL Ayarları
Proxy Kullanımı
import requests
proxies = {
"http": "http://proxy.example.com:8080",
"https": "http://proxy.example.com:8080",
}
response = requests.get(
"https://api.example.com/data",
proxies=proxies,
timeout=10
)SSL Sertifika Kontrolü
import requests
# Varsayılan: SSL doğrulama açık (güvenli)
response = requests.get("https://api.example.com/data")
# SSL doğrulamayı kapat (sadece test/geliştirme için!)
response = requests.get(
"https://api.example.com/data",
verify=False # ⚠️ Production'da KULLANMA
)
# Özel sertifika
response = requests.get(
"https://api.example.com/data",
verify="/path/to/custom-ca-bundle.crt"
)💡 İpucu:
verify=Falsesadece geliştirme ve test ortamında, self-signed sertifika olan sunucularda kullan. Production'da SSL doğrulamasını asla devre dışı bırakma.
15. Yaygın Hatalar ve Best Practices
1. Timeout Koymamak
# ❌ Timeout yok — sunucu yanıt vermezse sonsuza kadar bekler
response = requests.get("https://api.example.com/data")
# ✅ Her zaman timeout koy
response = requests.get("https://api.example.com/data", timeout=10)2. Status Code Kontrol Etmemek
# ❌ Hata durumunda çökebilir
response = requests.get("https://api.example.com/users/99999")
data = response.json() # 404 döndüyse JSON olmayabilir!
# ✅ Önce kontrol et
response = requests.get("https://api.example.com/users/99999", timeout=10)
if response.ok:
data = response.json()
else:
print(f"Hata: {response.status_code}")3. Session Kullanmamak
# ❌ 100 ayrı TCP bağlantısı açar
for i in range(100):
requests.get(f"https://api.example.com/item/{i}")
# ✅ Tek session, bağlantı yeniden kullanımı
with requests.Session() as session:
for i in range(100):
session.get(f"https://api.example.com/item/{i}", timeout=10)4. API Key'i Kodda Tutmak
# ❌ Güvenlik açığı — Git'e push'larsan key sızar
headers = {"Authorization": "Bearer sk-1234567890abcdef"}
# ✅ Ortam değişkeninden oku
import os
token = os.environ["API_TOKEN"]
headers = {"Authorization": f"Bearer {token}"}5. Rate Limiting'e Saygı Göstermemek
import requests
import time
# ✅ API rate limit'ine uy
def respectful_fetch(urls, delay=0.5):
"""İstekler arası bekleme — API'yı boğma."""
results = []
with requests.Session() as session:
for url in urls:
response = session.get(url, timeout=10)
if response.status_code == 429: # Too Many Requests
retry_after = int(response.headers.get("Retry-After", 60))
print(f"Rate limit! {retry_after}sn bekleniyor...")
time.sleep(retry_after)
response = session.get(url, timeout=10)
results.append(response)
time.sleep(delay)
return resultsÖzet
requests Python'un fiili HTTP kütüphanesidir —
get(),post(),put(),delete()ile tüm HTTP metodlarını destekler.Response nesnesi status code, headers, body (text/json/bytes) ve süre bilgisi taşır.
raise_for_status()ile hataları exception'a çevir.Authentication için API Key (header/param), Bearer Token ve Basic Auth yöntemlerini kullanabilirsin — key'leri kodda değil ortam değişkeninde tut.
Session aynı sunucuya birden fazla istekte bağlantı yeniden kullanımı, cookie persistence ve ortak ayarlar sağlar.
Timeout her zaman belirt, retry mekanizması ekle ve rate limit'e saygı göster — production kodunun üç altın kuralı.
Büyük dosya indirirken
stream=True, upload içinfilesparametresini kullan.
AI Asistan
Sorularını yanıtlamaya hazır