Menu

Żądania HTTP w Pythonie: biblioteka requests (GET, POST, JSON)

Jak wysyłać żądania HTTP w Pythonie biblioteką requests: GET, POST, parametry zapytania, nagłówki, dane JSON i obsługa błędów.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Pobieranie danych z internetu w kilku liniach

Większość prawdziwych programów w Pythonie prędzej czy później musi porozmawiać z czymś przez sieć: z REST API, serwisem pogodowym, endpointem GitHuba, serwerem z plikiem do pobrania. Biblioteka standardowa to potrafi (przez urllib), ale w świecie Pythona standardem de facto jest zewnętrzna biblioteka requests. Jej API jest na tyle przyjaźniejsze, że warto wykonać to jedno pip install.

pip install requests

Jeśli nie pracujesz jeszcze w środowisku wirtualnym, najpierw je utwórz: dzięki temu instalacja dotyczy tylko twojego projektu.

Pierwsze żądanie GET

Trzy linie: wywołaj get, sprawdź kod statusu, obejrzyj treść. response.text to treść odpowiedzi jako napis. Tutaj jest przycięta, bo pełny JSON jest długi.

Kody statusu, które warto rozpoznawać na poziomie ściągi:

  • 200: OK, wszystko zadziałało.
  • 201: Created, utworzono zasób (częsta odpowiedź na POST).
  • 301 / 302: przekierowania, requests domyślnie automatycznie za nimi podąża.
  • 400: błędne żądanie, coś w wysłanych danych było nie tak.
  • 401 / 403: brak uwierzytelnienia / brak uprawnień.
  • 404: zasób nie istnieje.
  • 429: przekroczony limit żądań, zwolnij.
  • 500: błąd serwera.

Parsowanie odpowiedzi JSON

Gdy endpoint zwraca JSON, wywołaj na odpowiedzi .json(): parsuje treść i daje ci słownik (albo listę):

Pod spodem .json() to to samo co json.loads(response.text), tylko skrót dla typowego przypadku.

Wysyłanie parametrów zapytania

Nie doklejaj ręcznie ?key=value&... do adresu URL. Przekaż słownik do params=:

requests samo zajmuje się kodowaniem URL: spacje, znaki specjalne i Unicode działają bezpiecznie.

Faktyczny adres, który został wysłany, jest dostępny w response.url, co przydaje się przy debugowaniu.

Żądania POST z danymi JSON

Do wysyłania danych (tworzenia zasobów, wysyłania formularzy, wywoływania endpointów, które coś zmieniają) użyj requests.post:

import requests

payload = {
    "title": "Docs update",
    "body": "Added HTTP requests page.",
    "labels": ["docs"],
}

response = requests.post(
    "https://api.example.com/issues",
    json=payload,
    headers={"Authorization": "Bearer YOUR_TOKEN"},
)

print(response.status_code)
print(response.json())

Argument json= robi dwie rzeczy: serializuje payload do JSON i ustawia Content-Type: application/json. Oba kroki dałoby się zrobić ręcznie przez data=json.dumps(payload) i jawny nagłówek, ale json= to idiomatyczny skrót.

Dla danych kodowanych jak formularz (takich, jakie wysyła klasyczny formularz HTML) użyj zamiast tego data=:

requests.post("https://example.com/login", data={"user": "rosa", "password": "..."})

Nagłówki

Własne nagłówki przekazuj jako słownik:

import requests

response = requests.get(
    "https://api.example.com/profile",
    headers={
        "Authorization": "Bearer abc123",
        "User-Agent": "my-tool/1.0",
    },
)

Większość API wymaga do uwierzytelnienia nagłówka Authorization. Dokładny schemat (Bearer, Basic, Token) znajdziesz w ich dokumentacji.

Limity czasu nie są opcjonalne

Domyślnie requests będzie czekać na odpowiedź w nieskończoność. W prawdziwym programie niestabilny serwer zamienia się wtedy w zawieszony skrypt. Zawsze przekazuj timeout:

import requests

try:
    response = requests.get("https://api.example.com/slow", timeout=5)
except requests.Timeout:
    print("Server took too long.")

Liczba oznacza sekundy. timeout=5 znaczy "poddaj się, jeśli w ciągu 5 sekund nie będzie odpowiedzi". Dla większej kontroli możesz przekazać krotkę (connect_timeout, read_timeout).

Obsługa błędów

Mogą wystąpić dwa rodzaje problemów:

  1. Błędy na poziomie HTTP (4xx, 5xx): serwer odpowiedział, ale odpowiedź jest błędem. Mówi o tym response.status_code.
  2. Problemy na poziomie sieci: przekroczony czas, błędy DNS, nieosiągalne hosty. Te zgłaszają wyjątki.

Idiomatyczny wzorzec łączy jedno i drugie:

raise_for_status() nic nie robi przy odpowiedziach 2xx, a w pozostałych przypadkach zgłasza wyjątek. RequestException to klasa bazowa każdego błędu zgłaszanego przez requests, więc jeden blok łapie "wszystko, co poszło nie tak w rozmowie z tym endpointem".

Pobieranie pliku

Przy dużych plikach binarnych pobieraj odpowiedź strumieniowo, żeby nie trzymać jej w pamięci:

import requests

url = "https://example.com/large.zip"

with requests.get(url, stream=True, timeout=30) as r:
    r.raise_for_status()
    with open("large.zip", "wb") as f:
        for chunk in r.iter_content(chunk_size=8192):
            f.write(chunk)

stream=True mówi requests, żeby nie wczytywało treści z góry. iter_content(chunk_size=...) oddaje treść kawałek po kawałku, a ty od razu zapisujesz ją na dysk.

Sesje: ponowne użycie połączeń i ustawień

Jeśli masz wysłać kilka żądań do tej samej usługi, użyj Session. Sesja ponownie wykorzystuje połączenie TCP (szybciej) i pozwala raz ustawić wartości domyślne:

import requests

session = requests.Session()
session.headers.update({"Authorization": "Bearer abc123"})

# Każde żądanie w tej sesji niesie ten nagłówek.
a = session.get("https://api.example.com/users/1")
b = session.get("https://api.example.com/users/2")
c = session.post("https://api.example.com/users", json={"name": "Rosa"})

W skryptach, które odpytują to samo API dziesiątki razy, sesja daje wyraźne przyspieszenie.

Realistyczny przykład: mały klient GitHuba

Pobranie najnowszego wydania repozytorium:

import requests

def latest_release(owner, repo):
    url = f"https://api.github.com/repos/{owner}/{repo}/releases/latest"
    response = requests.get(url, timeout=10)
    response.raise_for_status()
    data = response.json()
    return {
        "tag": data["tag_name"],
        "name": data["name"],
        "published": data["published_at"],
        "url": data["html_url"],
    }

release = latest_release("python", "cpython")
print(release)

Niecałe piętnaście linii: zbuduj adres, wyślij żądanie, sprawdź błędy, wyciągnij pola, które cię interesują. Tak wygląda większość klientów API, które napiszesz.

A co z urllib?

urllib.request z biblioteki standardowej potrafi wszystko to, co requests, tylko w większej liczbie linii i mniej wygodnie. Jeśli absolutnie nie możesz dodać zależności, masz go pod ręką:

import json
import urllib.request

with urllib.request.urlopen("https://api.github.com/repos/python/cpython") as r:
    data = json.loads(r.read().decode("utf-8"))

print(data["name"])

Przy wszystkim, co wykracza poza szybki skrypt, requests (albo httpx, jeśli potrzebujesz async) jest wart instalacji.

Kilka nawyków

  • Zawsze ustawiaj timeout. Bez wyjątków.
  • Używaj raise_for_status() w skryptach, które oczekują sukcesu: zamienia złą odpowiedź w głośny wyjątek.
  • Przekazuj słowniki do params= i json=, a nie ręcznie sklejane napisy.
  • Opakowuj powiązane wywołania w Session, gdy wiele razy odpytujesz to samo API.
  • Loguj response.status_code i response.text przy debugowaniu: treść odpowiedzi zwykle mówi dokładnie, co nie spodobało się serwerowi.

Dalej: daty i godziny

Z requests w zestawie narzędzi możesz rozmawiać z każdym współczesnym webowym API, pobierać pliki i budować małe integracje między usługami. Razem z wcześniejszymi stronami o JSON i CSV masz już pełny cykl "pobierz dane, odczytaj je, zrób z nimi coś, zapisz z powrotem", czyli kształt ogromnej liczby prawdziwych skryptów w Pythonie. Większość tych danych ma jednak znacznik czasu, a następna strona opisuje, jak Python reprezentuje daty i godziny oraz jakich pułapek ze strefami czasowymi warto unikać.

Najczęściej zadawane pytania

Jak wysłać żądanie HTTP w Pythonie?

Zainstaluj bibliotekę requests poleceniem pip install requests, a potem wywołaj requests.get(url) dla GET albo requests.post(url, json=...) dla POST. Obiekt odpowiedzi ma .status_code, .text, .json() i .headers. Przykład: r = requests.get('https://api.example.com/users/1').

requests czy urllib?

requests do wszystkiego, co piszesz ręcznie, bo jego API jest nieporównanie przyjaźniejsze. urllib jest wbudowany i sprawdza się, gdy dodanie zależności jest niemożliwe, ale wymaga więcej kodu przy danych JSON czy sesjach. W produkcji wiele zespołów używa też httpx (biblioteki zgodnej z requests, obsługującej async).

Jak wysłać JSON w żądaniu POST w Pythonie?

Przekaż json={'key': 'value'} do requests.post(...). requests serializuje słownik do JSON i sam ustawia Content-Type: application/json. Nie przekazuj jednocześnie data= i json=: wybierz jedno.

Jak obsługiwać błędy w bibliotece requests?

Sprawdź response.status_code (200 oznacza sukces) albo wywołaj response.raise_for_status(), żeby zgłosić wyjątek przy kodach 4xx/5xx. Problemy na poziomie sieci (przekroczony czas, błędy DNS) zgłaszają podklasy requests.RequestException: łap ten wyjątek, żeby objąć oba przypadki.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ