YouTube-Transkripte mit Python holen (ohne API-Quotas)

Die YouTube Data API lässt Transkripte aus, und youtube-transcript-api wird auf Cloud-Servern per IP blockiert. Ein Setup für 1 Credit pro Video, August 2026.

Du willst den gesprochenen Text eines YouTube-Videos: für einen Datensatz, für die Suche, für Untertitel. Das stellt sich als schwerer heraus, als es sein sollte, aus zwei Gründen, die nichts mit deinem Code zu tun haben.

Warum gibt dir die YouTube Data API das nicht einfach?

Die offizielle YouTube Data API hat eine captions-Ressource, aber captions.download braucht eine OAuth-Authentifizierung als der Video-Owner selbst. Sie wurde gebaut, damit Kanalbetreiber ihre eigenen Untertitelspuren verwalten können, nicht damit Dritte Transkripte für Videos abrufen, die ihnen nicht gehören. Für alle anderen gibt es keinen quotenbasierten, offiziellen Weg, ein Transkript über die Data API zu ziehen. Diese Lücke ist der Grund, warum eine ganze Kategorie inoffizieller Bibliotheken existiert.

Warum bricht youtube-transcript-api auf einem Server?

youtube-transcript-api funktioniert, indem es mit einem internen, inoffiziellen YouTube-Endpoint spricht, und läuft auf einem Laptop einwandfrei. Deployst du denselben Code auf AWS, GCP oder Azure, wirft es plötzlich RequestBlocked- oder IpBlocked-Fehler, weil YouTube die IP-Bereiche blockiert, die bekanntermaßen zu Cloud-Anbietern gehören. Das ist kein Bug in der Bibliothek: Es ist dokumentiertes Verhalten, diskutiert in den eigenen GitHub Issues des Projekts als anhaltendes Problem bis in 2026 hinein (Issue #593, Issue #511). Statische Proxys werden nach moderater Nutzung gebannt; nur rotierende residentielle Proxys halten durch, und diese Infrastruktur selbst zu betreiben ist ein eigenes Projekt, wenn Transkripte nicht dein Produkt sind.

Der ehrliche Stand der Dinge also: Die offizielle API macht das nicht, und die freie Bibliothek, die die Lücke füllt, übersteht den Kontakt mit einem Produktionsserver nicht.

Die Version, die funktioniert

Schicke die Video-ID an eine API, die das IP-Problem schon gelöst hat, und bekomme das Transkript als JSON zurück:

import requests

API_KEY = "faf_live_..."  # dein FastAF-Key

resp = requests.get(
    "https://api.fastaf.co/v1/youtube",
    params={"v": "dQw4w9WgXcQ", "language": "en"},
    headers={"Authorization": f"Bearer {API_KEY}"},
    timeout=60,
)
resp.raise_for_status()
data = resp.json()

full_text = " ".join(segment["text"] for segment in data["transcripts"])
print(full_text[:500])

Eine Anfrage kostet 1 Credit, unabhängig von der Videolänge. v ist die YouTube-Video-ID (der Teil nach v= in der URL), language fordert eine bestimmte Untertitelspur an, wenn das Video mehr als eine hat, und country grenzt die Anfrage auf eine Region ein, wenn Verfügbarkeit oder Standard-Untertitel eines Videos je Markt unterschiedlich sind.

Was kannst du damit bauen?

Datensätze für LLM-Fine-Tuning oder RAG. Transkripte sind sauberes, zeitgestempeltes natürliches Sprache zu einem Bruchteil der Kosten manueller Transkription. Zieh einmal das Backkatalog eines Kanals, speichere den Text, chunke ihn so, wie es deine Pipeline erwartet.

Untertitel für deine eigene Video-Pipeline. Wenn du Videoinhalte neu veröffentlichst, schneidest oder synchronisierst, ist ein Transkript mit Timing der Ausgangspunkt für eingebrannte Untertitel oder einen Übersetzungsdurchgang, ohne dass ein Mensch aus Audio transkribieren muss.

Suche innerhalb von Videoinhalten. Produktdemos, Podcasts, Vorlesungsreihen: Transkripte lassen dich Videos durchsuchen wie Text. Indexiere das Transkript, und “in welcher Folge wurde X erwähnt” wird zu einer Suchanfrage statt zu einer Durchsuch-Session.

Ein minimaler Batch-Job für den ersten Fall:

import sqlite3
import time

conn = sqlite3.connect("transcripts.db")
conn.execute("""
    CREATE TABLE IF NOT EXISTS transcripts (
        video_id TEXT PRIMARY KEY,
        text TEXT,
        fetched_at INTEGER
    )
""")

def fetch_transcript(video_id, language="en"):
    resp = requests.get(
        "https://api.fastaf.co/v1/youtube",
        params={"v": video_id, "language": language},
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=60,
    )
    resp.raise_for_status()
    return " ".join(seg["text"] for seg in resp.json()["transcripts"])

video_ids = ["dQw4w9WgXcQ", "9bZkp7q19f0"]  # deine Liste

for vid in video_ids:
    text = fetch_transcript(vid)
    conn.execute(
        "INSERT OR REPLACE INTO transcripts VALUES (?, ?, ?)",
        (vid, text, int(time.time())),
    )
    conn.commit()

Tausend Videos so verarbeitet sind 1.000 Credits: Der Free Tier (500 Credits, keine Karte) deckt die ersten 500 für einen Test ab, und alles Größere ist ein Rundungsfehler auf dem Starter-Paket.

Kurzversion

Die offizielle API wurde nicht dafür gebaut, und die freie Bibliothek bricht in dem Moment, in dem sie deinen Laptop verlässt. Per Video-ID über eine normale HTTPS-Anfrage abzurufen umgeht beide Probleme, kostet 1 Credit pro Video unabhängig von der Länge, und gibt dir zeitgestempelten Text, den du direkt in einen Datensatz, eine Untertitelspur oder einen Suchindex einspeisen kannst. In den Docs findest du die vollständige Antwortstruktur.