Menu

Python-HTTP-Requests: Die requests-Bibliothek (GET, POST, JSON)

Wie du HTTP-Anfragen in Python mit der requests-Bibliothek stellst — GET, POST, Query-Parameter, Header, JSON-Bodies und Fehlerbehandlung.

Daten aus dem Internet holen, in wenigen Zeilen

Die meisten echten Python-Programme müssen irgendwann mit dem Netz reden — eine REST-API, ein Wetterdienst, ein GitHub-Endpoint, ein Download. Die Standardbibliothek kann das (via urllib), aber das De-facto-Werkzeug in der Python-Welt ist eine Drittanbieter-Bibliothek namens requests. Die API ist so viel freundlicher, dass sich der eine pip install lohnt.

pip install requests

Arbeitest du noch nicht in einer virtuellen Umgebung, richte erst eine ein — sie hält die Installation auf dein Projekt beschränkt.

Ein erster GET-Request

main.py
Output
Click Run to see the output here.

Drei Zeilen: get aufrufen, den Statuscode prüfen, den Body ansehen. response.text ist der Response-Body als String. Hier abgeschnitten, weil das volle JSON lang ist.

Statuscodes, die sich lohnen zu erkennen:

  • 200 — OK, alles hat geklappt.
  • 201 — Created (häufige POST-Antwort).
  • 301 / 302 — Redirects; requests folgt ihnen standardmäßig.
  • 400 — Bad Request; etwas an deinem Input war falsch.
  • 401 / 403 — nicht authentifiziert / nicht autorisiert.
  • 404 — Ressource existiert nicht.
  • 429 — Rate-Limit; langsamer machen.
  • 500 — Serverfehler.

Eine JSON-Antwort parsen

Wenn der Endpoint JSON liefert, ruf .json() auf der Antwort — es parst den Body und gibt dir ein Dict (oder eine Liste):

main.py
Output
Click Run to see the output here.

Unter der Haube ist .json() dasselbe wie json.loads(response.text) — eine Abkürzung für den Normalfall.

Query-Parameter senden

Kleb ?key=value&... nicht manuell an die URL. Übergib ein Dict an params=:

main.py
Output
Click Run to see the output here.

requests erledigt die URL-Kodierung — Leerzeichen, Sonderzeichen, Unicode funktionieren sicher.

Die tatsächlich gesendete URL steht in response.url, nützlich beim Debuggen.

POST-Requests mit JSON-Bodies

Zum Senden von Daten — Ressourcen erzeugen, Formulare absenden, mutierende Endpoints aufrufen — nimm 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())

Das json=-Argument tut zwei Dinge: es serialisiert payload zu JSON und setzt Content-Type: application/json. Du könntest beides von Hand mit data=json.dumps(payload) und explizitem Header tun, aber json= ist die idiomatische Abkürzung.

Für formularkodierte Daten (wie ein klassisches HTML-Formular sie sendet) nutz data=:

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

Übergib eigene Header als Dict:

import requests

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

Die meisten APIs wollen einen Authorization-Header zur Authentifizierung. Das genaue Schema (Bearer, Basic, Token) steht in ihrer Dokumentation.

Timeouts sind nicht optional

Standardmäßig wartet requests ewig auf eine Antwort. In einem echten Programm verwandelt das einen wackligen Server in ein hängendes Skript. Übergib immer einen timeout:

import requests

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

Die Zahl ist in Sekunden. timeout=5 heißt „gib auf, wenn innerhalb von 5 Sekunden keine Antwort da ist“. Du kannst ein Tupel (connect_timeout, read_timeout) für mehr Kontrolle übergeben.

Fehlerbehandlung

Zwei Problemarten können auftreten:

  1. HTTP-Fehler (4xx, 5xx) — der Server hat geantwortet, aber die Antwort ist ein Fehler. response.status_code sagt es dir.
  2. Netzwerkprobleme — Timeouts, DNS-Fehler, nicht erreichbare Hosts. Die werfen Ausnahmen.

Das idiomatische Muster kombiniert beide:

main.py
Output
Click Run to see the output here.

raise_for_status() ist bei 2xx-Antworten ein No-op und wirft sonst eine Ausnahme. RequestException ist die Basisklasse jedes Fehlers, den requests wirft — ein einzelnes Catch für „irgendwas ist beim Reden mit diesem Endpoint schiefgegangen“.

Eine Datei herunterladen

Für große Binärdownloads streame die Antwort, damit sie nicht im Speicher liegt:

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 sagt requests, den Body nicht vorzuladen. iter_content(chunk_size=...) liefert den Body Stück für Stück, das du direkt auf die Platte schreibst.

Sessions: Verbindungen und Defaults wiederverwenden

Machst du mehrere Anfragen an denselben Dienst, nimm eine Session. Sie nutzt die darunterliegende TCP-Verbindung wieder (schneller) und erlaubt dir, Defaults einmal zu setzen:

import requests

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

# Every request through this session carries the header.
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"})

Für Skripte, die dieselbe API dutzende Male treffen, ist eine Session ein spürbarer Tempogewinn.

Ein realistisches Beispiel: kleiner GitHub-Client

Das neueste Release eines Repos holen:

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)

Unter fünfzehn Zeilen: URL bauen, anfragen, auf Fehler prüfen, gewünschte Felder extrahieren. Das ist die Form der meisten API-Clients, die du schreiben wirst.

Was ist mit urllib?

urllib.request aus der Standardbibliothek kann alles, was requests kann — mit mehr Zeilen und weniger Ergonomie. Wenn du absolut keine Abhängigkeit hinzufügen kannst, ist es da:

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"])

Für alles jenseits eines schnellen Skripts ist requests (oder httpx, wenn du async brauchst) die Installation wert.

Ein paar Gewohnheiten

  • Setz immer einen Timeout. Keine Ausnahmen.
  • Nutz raise_for_status() in Skripten, die Erfolg erwarten — es verwandelt eine schlechte Antwort in eine laute Ausnahme.
  • Übergib Dicts an params= und json=, keine handgebauten Strings.
  • Wickle zusammenhängende Aufrufe in eine Session, wenn du dieselbe API oft triffst.
  • Logge response.status_code und response.text beim Debuggen — der Body sagt meist genau, was dem Server nicht gefiel.

Als Nächstes: Daten und Uhrzeiten

Mit requests im Werkzeugkasten kannst du mit jeder modernen Web-API reden, Dateien herunterladen und kleine Integrationen zwischen Diensten bauen. Kombiniert mit den JSON- und CSV-Seiten davor hast du jetzt die komplette „Daten holen, lesen, damit etwas tun, zurückschreiben“-Schleife — die Form unzähliger echter Python-Skripte. Die meisten Daten davon tragen einen Zeitstempel, und die nächste Seite behandelt, wie Python Daten, Zeiten und die Zeitzonen-Fallen darstellt, die es zu vermeiden lohnt.

Häufig gestellte Fragen

Wie mache ich eine HTTP-Anfrage in Python?

Installier die requests-Bibliothek mit pip install requests, dann ruf requests.get(url) für ein GET oder requests.post(url, json=...) für ein POST. Das Response-Objekt hat .status_code, .text, .json() und .headers. Beispiel: r = requests.get('https://api.example.com/users/1').

Soll ich requests oder urllib nutzen?

requests für alles, was du von Hand schreiben würdest — die API ist deutlich freundlicher. urllib ist eingebaut und okay, wenn eine Abhängigkeit unmöglich ist, erfordert aber mehr Code für Dinge wie JSON-Bodies und Sessions. Für Produktion nutzen viele Teams auch httpx (eine requests-kompatible Bibliothek mit async-Unterstützung).

Wie sende ich JSON in einem POST-Request in Python?

Übergib json={'key': 'value'} an requests.post(...). requests serialisiert das Dict zu JSON und setzt Content-Type: application/json für dich. Übergib nicht beides data= und json= — wähl eines.

Wie behandle ich Fehler mit der requests-Bibliothek?

Prüf response.status_code (200 heißt Erfolg) oder ruf response.raise_for_status(), um bei 4xx/5xx eine Ausnahme zu werfen. Netzwerkprobleme (Timeouts, DNS-Fehler) werfen Unterklassen von requests.RequestException — die zu fangen deckt beide ab.

Lerne mit Coddy zu programmieren

LOS GEHT'S