HTTP, APIs und Webservices¶
REST-APIs nutzen, Daten abrufen und externe Systeme automatisieren.
Moderne IT-Infrastrukturen bestehen aus einer Vielzahl von Diensten, die über HTTP-Schnittstellen miteinander kommunizieren. Cloud-Anbieter, Monitoring-Systeme, Ticket-Systeme, Container-Plattformen und viele weitere Werkzeuge stellen REST-APIs zur Verfügung, über die Informationen abgerufen oder Aktionen ausgelöst werden können.
Für Systemadministratoren und DevOps Engineers gehört der Umgang mit APIs mittlerweile zum Alltag. Serverinformationen werden aus Inventar- Systemen geladen, Monitoring-Daten abgefragt, Deployments gestartet oder Konfigurationen automatisiert verwaltet.
Python bietet mit Bibliotheken wie requests eine einfache und leistungsfähige Möglichkeit, HTTP-Anfragen auszuführen und Antworten weiterzuverarbeiten. In Kombination mit JSON lassen sich dadurch zahlreiche Aufgaben automatisieren, die sonst manuell über Weboberflächen erledigt werden müssten.
In diesem Kapitel lernen Sie die wichtigsten Grundlagen für die Arbeit mit HTTP, REST-APIs und Webservices kennen und setzen diese in praxisnahen Beispielen um.
HTTP-Anfragen mit requests¶
HTTP-Anfragen mit requests: Grundlagen und Praxis¶
Das Python-Modul requests ist das bevorzugte Werkzeug, um HTTP-Anfragen einfach und lesbar auszuführen. Es abstrahiert die Komplexität von Verbindungen, Headern und Datenformaten und ist damit ideal für Automatisierungsskripte in der Systemadministration.
Installation¶
requests ist nicht Teil der Standardbibliothek, lässt sich aber mit einem einfachen Befehl installieren:
Eine einfache GET-Anfrage¶
GET-Anfragen sind die Grundlage, um Informationen von Webservern oder APIs abzurufen. Im Vergleich zu Shell-Tools wie curl bietet requests eine native Python-Schnittstelle, die das Parsen und Weiterverarbeiten der Antwort erleichtert.
import requests
url = "https://api.github.com/repos/psf/requests"
response = requests.get(url)
print(f"Statuscode: {response.status_code}")
print(f"Content-Type: {response.headers['Content-Type']}")
print("Repository Name:", response.json()["name"])
Hier wird eine API von GitHub abgefragt, um Informationen über das requests-Repository zu erhalten. Die Antwort wird als JSON dekodiert und ein bestimmtes Feld ausgegeben.
POST-Anfragen mit Daten¶
import requests
url = "https://httpbin.org/post"
data = {"hostname": "server01", "action": "restart"}
response = requests.post(url, json=data)
print(f"Statuscode: {response.status_code}")
print("Antwort JSON:", response.json())
Im Beispiel wird ein JSON-Objekt an einen Test-Endpunkt gesendet, der die empfangenen Daten zurückgibt. So lassen sich API-Interaktionen simulieren.
Wichtige Parameter und Best Practices¶
- Timeout setzen: Vermeiden Sie, dass Ihr Skript bei Netzwerkproblemen ewig wartet.
- Fehlerbehandlung: Prüfen Sie immer den Statuscode, um unerwartete Fehler zu erkennen.
- Header anpassen: Manche APIs erwarten spezifische Header, z.B. einen User-Agent.
Vergleich mit Shell-Skripten¶
Während curl oder wget schnell und praktisch sind, bietet requests in Python folgende Vorteile:
- Direkte Verarbeitung der Antwort (JSON, Text, Binärdaten) ohne Zwischenspeicherung
- Bessere Fehlerbehandlung und Logging
- Integration in größere Automatisierungsskripte
Zusammenfassung¶
Mit requests können Sie HTTP-Anfragen in Python einfach und übersichtlich ausführen. Dies ist die Basis, um REST-APIs abzufragen, Automatisierungsskripte zu schreiben oder Monitoring-Daten zu sammeln. Im nächsten Abschnitt lernen Sie, wie Sie die erhaltenen JSON-Daten sinnvoll weiterverarbeiten.
REST-APIs verwenden¶
REST-APIs verstehen und nutzen¶
REST-APIs sind Schnittstellen, über die Systeme standardisiert Daten austauschen. Für Administratoren und DevOps-Teams sind sie ein mächtiges Werkzeug, um Infrastruktur, Monitoring oder Cloud-Dienste automatisiert abzufragen und zu steuern. Die Kommunikation erfolgt meist über HTTP, und die Daten werden häufig im JSON-Format übertragen.
JSON-Daten mit Python verarbeiten¶
JSON (JavaScript Object Notation) ist ein leichtgewichtiges, textbasiertes Datenformat. Python bietet mit dem Modul json eine einfache Möglichkeit, JSON-Daten in Python-Datenstrukturen umzuwandeln und umgekehrt.
import json
json_text = '{"status": "ok", "uptime": 12345}'
# JSON-String in Python-Dictionary umwandeln
data = json.loads(json_text)
print(data["status"]) # Ausgabe: ok
# Python-Datenstruktur zurück in JSON-String
json_str = json.dumps(data, indent=2)
print(json_str)
Beispiel: Status einer Monitoring-API abfragen¶
Viele Monitoring-Systeme wie Prometheus oder Zabbix bieten REST-APIs zur Abfrage von Systemmetriken. Hier ein Beispiel, wie man mit requests eine Statusabfrage durchführt und die JSON-Antwort auswertet.
import requests
url = "https://monitoring.example.com/api/v1/status"
response = requests.get(url)
if response.status_code == 200:
status_data = response.json() # JSON-Antwort direkt als Python-Daten
print(f"Systemstatus: {status_data['status']}")
print(f"Uptime: {status_data['uptime']} Sekunden")
else:
print(f"Fehler beim Abrufen: {response.status_code}")
Schritt-für-Schritt: API-Daten sinnvoll auswerten¶
- HTTP-Status prüfen: Nur bei 200 (OK) die Antwort weiterverarbeiten.
- JSON parsen: Mit
response.json()erhält man ein Python-Dictionary. - Datenzugriff: Über Schlüssel auf relevante Werte zugreifen.
- Fehlerbehandlung: Fehlende oder unerwartete Daten abfangen.
Praxisfall: Serverinventar aus einer Cloud-API¶
Viele Cloud-Anbieter stellen REST-APIs bereit, um virtuelle Maschinen oder Container aufzulisten. Beispiel mit fiktiver API:
import requests
api_url = "https://cloud.example.com/v1/servers"
headers = {"Authorization": "Bearer DEIN_API_TOKEN"}
response = requests.get(api_url, headers=headers)
response.raise_for_status() # Bei Fehlern Ausnahme auslösen
servers = response.json().get("servers", [])
for server in servers:
print(f"Name: {server['name']}, Status: {server['status']}, IP: {server.get('ip', 'keine IP')}")
Warum Python statt Shell-Skripte?¶
Shell-Skripte können HTTP-Anfragen mit curl ausführen, aber JSON-Auswertung ist kompliziert und fehleranfällig. Python ermöglicht:
- Einfaches Parsen und Navigieren in komplexen JSON-Strukturen
- Klare Fehlerbehandlung
- Wiederverwendbare Funktionen und Module
Damit wird die Automatisierung robuster und leichter wartbar.
Zusammenfassung¶
- REST-APIs liefern Daten meist als JSON, das sich mit Python einfach verarbeiten lässt.
requestsundjsonsind die zentralen Module für API-Kommunikation und Datenverarbeitung.- Praktische Beispiele aus Monitoring und Cloud zeigen typische Anwendungsfälle.
- Python erleichtert das Auswerten und Automatisieren von API-Daten gegenüber klassischen Shell-Methoden.
Authentifizierung und API-Tokens¶
API-Keys sicher verwalten mit python-dotenv¶
API-Keys und Tokens sind sensible Zugangsdaten, die nicht im Klartext im Quellcode stehen sollten. Eine bewährte Methode ist das Auslagern dieser Werte in Umgebungsvariablen. Das Python-Paket python-dotenv ermöglicht es, Umgebungsvariablen aus einer .env-Datei zu laden, die nicht ins Versionskontrollsystem aufgenommen wird.
Ein Beispiel .env-Datei:
Diese Datei liegt im Projektverzeichnis, wird aber z.B. in .gitignore eingetragen.
Beispiel: API-Key für eine GET-Anfrage verwenden¶
import os
from dotenv import load_dotenv
import requests
load_dotenv() # lädt Variablen aus .env
api_key = os.getenv('API_KEY')
url = 'https://api.monitoring.example.com/v1/servers'
headers = {'Authorization': f'Api-Key {api_key}'}
response = requests.get(url, headers=headers)
response.raise_for_status() # Fehler sofort erkennen
data = response.json()
print(f"Gefundene Server: {len(data['servers'])}")
Hier wird der API-Key im Header übergeben. Viele APIs erwarten diesen Header, um den Client zu authentifizieren.
Bearer-Token für OAuth-geschützte APIs¶
Bearer-Tokens sind oft Teil von OAuth2-Authentifizierungen. Sie werden im Header als Authorization: Bearer <token> gesendet.
bearer_token = os.getenv('BEARER_TOKEN')
headers = {'Authorization': f'Bearer {bearer_token}'}
url = 'https://api.cloudprovider.example.com/v2/instances'
response = requests.get(url, headers=headers)
response.raise_for_status()
instances = response.json()
print(f"Instanzen: {len(instances['items'])}")
Grundlegende HTTP-Authentifizierung (Basic Auth)¶
Manche APIs oder interne Dienste nutzen Basic Auth, bei der Benutzername und Passwort in der Anfrage kodiert werden.
from requests.auth import HTTPBasicAuth
username = os.getenv('API_USER')
password = os.getenv('API_PASS')
url = 'https://internal-api.example.com/status'
response = requests.get(url, auth=HTTPBasicAuth(username, password))
response.raise_for_status()
status = response.json()
print(f"Systemstatus: {status['state']}")
Warum nicht einfach im Code?¶
- Sicherheit: API-Keys im Code landen oft in Versionskontrolle und können so öffentlich werden.
- Flexibilität: Verschiedene Umgebungen (Test, Produktion) können unterschiedliche Schlüssel verwenden, ohne Codeänderung.
Tipps für den Alltag¶
.env-Dateien niemals ins Git-Repository einchecken.- Verwenden Sie für Produktionssysteme Umgebungsvariablen des Betriebssystems oder Secrets-Management-Tools.
- Prüfen Sie die API-Dokumentation genau: Manche APIs erwarten den Key als URL-Parameter, andere im Header.
- Fehlerbehandlung: Prüfen Sie immer den HTTP-Status und behandeln Sie Fehlermeldungen sinnvoll.
Mit diesen Grundlagen können Sie API-Authentifizierungen sicher und flexibel in Ihren Python-Skripten umsetzen, was die Automatisierung von Infrastruktur- und Monitoring-Aufgaben deutlich erleichtert.
Dateien herunterladen¶
Dateien mit requests herunterladen¶
Für die Automatisierung von Downloads ist das Modul requests ideal, da es HTTP-Anfragen einfach handhabbar macht. Besonders bei großen Dateien ist es wichtig, den Download in kleinen Stücken (Chunks) zu verarbeiten, um Speicher zu schonen.
import requests
url = 'https://example.com/logs/server-log-2024-06-01.log'
local_path = '/var/log/remote/server-log-2024-06-01.log'
with requests.get(url, stream=True) as response:
response.raise_for_status() # Fehler prüfen
with open(local_path, 'wb') as file:
for chunk in response.iter_content(chunk_size=8192):
if chunk: # Filtert Keep-Alive-Chunks
file.write(chunk)
Warum stream=True?
Ohne Streaming würde requests die gesamte Datei im Speicher halten. Bei großen Dateien kann das zu Speicherproblemen führen. Mit Streaming liest man die Datei Stück für Stück und schreibt sie direkt auf die Festplatte.
Fortschrittsanzeige für große Downloads¶
Für längere Downloads ist eine Fortschrittsanzeige hilfreich, um den Status zu überwachen. Dazu kann man die Content-Length aus dem Header nutzen:
import requests
from tqdm import tqdm # Fortschrittsbalken (muss ggf. installiert werden)
url = 'https://example.com/backup/infra-backup.tar.gz'
local_path = '/backups/infra-backup.tar.gz'
with requests.get(url, stream=True) as response:
response.raise_for_status()
total_size = int(response.headers.get('content-length', 0))
chunk_size = 8192
with open(local_path, 'wb') as file, tqdm(
total=total_size, unit='B', unit_scale=True, desc='Download'
) as progress:
for chunk in response.iter_content(chunk_size=chunk_size):
if chunk:
file.write(chunk)
progress.update(len(chunk))
Hinweis: tqdm ist ein externes Paket, das mit pip install tqdm installiert werden kann. Es erleichtert die Anzeige von Fortschrittsbalken in der Konsole.
Umgang mit Authentifizierung bei Downloads¶
Viele Infrastruktur-APIs oder Cloud-Anbieter schützen Download-URLs mit Authentifizierung, z. B. API-Tokens oder Basic Auth. requests unterstützt beides:
# Beispiel mit Bearer-Token
headers = {'Authorization': 'Bearer <API_TOKEN>'}
with requests.get(url, headers=headers, stream=True) as response:
response.raise_for_status()
# Datei speichern wie oben
Best Practices¶
- Nutze
stream=Truebei großen Dateien, um Speicher zu sparen. - Prüfe HTTP-Statuscodes mit
raise_for_status(). - Verwende eine Fortschrittsanzeige bei langen Downloads.
- Speichere Dateien in passenden Verzeichnissen mit aussagekräftigen Namen.
- Achte auf sichere Handhabung von Authentifizierungsdaten (siehe Kapitel zu API-Tokens).
Zusammenfassung¶
Das Herunterladen von Dateien mit Python ist dank requests unkompliziert und leistungsfähig. Für Systemadministratoren und DevOps-Profis ermöglicht es, Backups, Logs oder Konfigurationsdateien automatisiert und effizient zu sichern – oft mit besserer Kontrolle und Fehlerbehandlung als klassische Shell-Tools.
Automatisierung mit APIs¶
APIs als Werkzeug für Automatisierung¶
APIs sind in modernen IT-Umgebungen unverzichtbar, um Infrastruktur, Monitoring und Cloud-Dienste programmatisch zu steuern. Statt wiederkehrende manuelle Schritte in Webinterfaces oder CLI-Tools auszuführen, lassen sich administrative Aufgaben mit Python und HTTP-APIs automatisieren. Das spart Zeit, reduziert Fehler und ermöglicht komplexe Workflows.
Beispiel: Serverstatus per API abfragen¶
Viele Monitoring-Systeme wie Prometheus, Zabbix oder Cloud-Dienste bieten REST-APIs, um Statusinformationen abzurufen. Ein typischer Anwendungsfall ist das automatisierte Auslesen von Servermetriken oder Alarmen.
import requests
# Beispiel-URL eines Monitoring-API-Endpunkts
url = "https://monitoring.example.com/api/v1/alerts"
# API-Key für Authentifizierung (z.B. aus Umgebungsvariablen laden)
api_key = "DEIN_API_KEY"
headers = {"Authorization": f"Bearer {api_key}"}
response = requests.get(url, headers=headers)
response.raise_for_status() # Fehler sofort erkennen
alerts = response.json() # JSON-Antwort in Python-Daten umwandeln
# Beispiel: Alle kritischen Alarme ausgeben
for alert in alerts.get("data", []):
if alert.get("severity") == "critical":
print(f"Kritischer Alarm: {alert['message']} auf {alert['host']}")
Automatisierte Konfigurationsänderungen¶
Viele Systeme erlauben Änderungen via API, z. B. das Anpassen von Firewall-Regeln oder das Erstellen neuer Cloud-Ressourcen. Hierfür sind POST- oder PUT-Anfragen üblich.
import requests
import json
url = "https://firewall.example.com/api/v1/rules"
api_key = "DEIN_API_KEY"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
# Neue Firewall-Regel definieren
rule = {
"source": "10.0.0.0/24",
"destination": "0.0.0.0/0",
"port": 22,
"action": "allow"
}
response = requests.post(url, headers=headers, data=json.dumps(rule))
response.raise_for_status()
print("Firewall-Regel erfolgreich hinzugefügt.")
Vorteile von Python gegenüber Shell-Skripten¶
- Bessere Fehlerbehandlung:
requests.raise_for_status()und Ausnahmen helfen, Probleme früh zu erkennen. - Strukturierte Daten: JSON-Antworten lassen sich direkt in Python-Objekte umwandeln und leicht verarbeiten.
- Wiederverwendbarkeit: Funktionen und Module erleichtern das Organisieren größerer Automatisierungsprojekte.
- Plattformunabhängigkeit: Python-Skripte laufen auf Windows, Linux und macOS ohne Anpassungen.
Best Practices¶
- API-Keys sicher speichern: Verwenden Sie Umgebungsvariablen oder
.env-Dateien, z. B. mitpython-dotenv, um sensible Daten nicht im Code zu hinterlegen. - Timeouts setzen: Vermeiden Sie hängende Anfragen mit
requests.get(url, timeout=10). - Statuscodes prüfen: Nutzen Sie
raise_for_status()oder prüfen Sieresponse.status_codeexplizit. - Logging einbauen: Protokollieren Sie API-Aufrufe und Antworten für Fehleranalyse.
Zusammenfassung¶
Mit Python und HTTP-APIs lassen sich administrative Abläufe effizient automatisieren. Das Abrufen von Statusdaten, das Anpassen von Konfigurationen oder das Auslösen von Aktionen über Web-APIs reduziert manuellen Aufwand und erhöht die Zuverlässigkeit. Die Kombination aus klarer Syntax, guter Fehlerbehandlung und JSON-Verarbeitung macht Python zum idealen Werkzeug für DevOps- und Infrastrukturaufgaben.