Il s'agit d'une API Python qui permet d'extraire les transcriptions/sous-titres d'une vidéo YouTube donnée. Elle fonctionne également avec les sous-titres générés automatiquement, prend en charge la traduction des sous-titres et ne nécessite pas de navigateur headless, contrairement aux solutions basées sur Selenium !
La maintenance de ce projet est rendue possible grâce à tous les contributeurs et sponsors. Si vous souhaitez sponsoriser ce projet et voir votre avatar ou le logo de votre entreprise apparaître ci-dessous, cliquez ici. 💖
Il est recommandé d'installer ce module via pip :
pip install youtube-transcript-api
Vous pouvez soit intégrer ce module dans une application existante soit l'utiliser via une interface en ligne de commande (CLI).
Le moyen le plus simple d'obtenir une transcription pour une vidéo donnée est d'exécuter :
from youtube_transcript_api import YouTubeTranscriptApi
ytt_api = YouTubeTranscriptApi()
ytt_api.fetch(video_id)
Remarque : Par défaut, cette commande tentera d'accéder à la transcription anglaise de la vidéo. Si votre vidéo est dans une autre langue ou si vous souhaitez récupérer une transcription dans une autre langue, veuillez lire la section ci-dessous.
Remarque : Indiquez l'ID de la vidéo, PAS l'URL. Pour une vidéo avec l'URL
https://www.youtube.com/watch?v=12345
, l'ID est12345
.
Cette commande renverra un objet FetchedTranscript
ressemblant à ceci :
FetchedTranscript(
snippets=[
FetchedTranscriptSnippet(
text="Hey there",
start=0.0,
duration=1.54,
),
FetchedTranscriptSnippet(
text="how are you",
start=1.54,
duration=4.16,
),
# ...
],
video_id="12345",
language="English",
language_code="en",
is_generated=False,
)
Cet objet implémente la plupart des interfaces d'une List
:
ytt_api = YouTubeTranscriptApi()
fetched_transcript = ytt_api.fetch(video_id)
# is iterable
for snippet in fetched_transcript:
print(snippet.text)
# indexable
last_snippet = fetched_transcript[-1]
# provides a length
snippet_count = len(fetched_transcript)
Si vous préférez manipuler les données brutes de la transcription, vous pouvez appeler fetched_transcript.to_raw_data()
, qui renverra une liste de dictionnaires :
[
{
'text': 'Hey there',
'start': 0.0,
'duration': 1.54
},
{
'text': 'how are you',
'start': 1.54
'duration': 4.16
},
# ...
]
Vous pouvez ajouter le paramètre languages
si vous souhaitez vous assurer que les transcriptions sont récupérées dans la langue de votre choix (par défaut en anglais).
YouTubeTranscriptApi().fetch(video_id, languages=['de', 'en'])
Il s'agit d'une liste de codes de langue par ordre de priorité décroissante. Dans cet exemple, il tentera d'abord de récupérer la transcription allemande ('de'
), puis la transcription anglaise ('en'
) en cas d'échec. Si vous souhaitez connaître les langues disponibles, consultez list()
.
Si vous ne voulez qu'une seule langue, vous devez tout de même formater l'argument languages
comme une liste :
YouTubeTranscriptApi().fetch(video_id, languages=['de'])
Vous pouvez également ajouter preserve_formatting=True
si vous souhaitez conserver les éléments de formatage HTML tels que <i>
(italique) et <b>
(gras).
YouTubeTranscriptApi().fetch(video_ids, languages=['de', 'en'], preserve_formatting=True)
Si vous souhaitez lister toutes les transcriptions disponibles pour une vidéo donnée, vous pouvez appeler :
ytt_api = YouTubeTranscriptApi()
transcript_list = ytt_api.list(video_id)
Cette commande renverra un objet TranscriptList
qui est itérable et fournit des méthodes pour filtrer la liste des transcriptions par langues et types spécifiques, comme :
transcript = transcript_list.find_transcript(['de', 'en'])
Par défaut, ce module choisit toujours les transcriptions créées manuellement plutôt que celles générées automatiquement, si une transcription dans la langue demandée est disponible à la fois manuellement et automatiquement. L'objet TranscriptList
vous permet de contourner ce comportement par défaut en recherchant des types de transcription spécifiques :
# filter for manually created transcripts
transcript = transcript_list.find_manually_created_transcript(['de', 'en'])
# or automatically generated ones
transcript = transcript_list.find_generated_transcript(['de', 'en'])
Les méthodes find_generated_transcript
, find_manually_created_transcript
, find_transcript
renvoient des objets Transcript
. Ils contiennent des métadonnées concernant la transcription :
print(
transcript.video_id,
transcript.language,
transcript.language_code,
# whether it has been manually created or generated by YouTube
transcript.is_generated,
# whether this transcript can be translated or not
transcript.is_translatable,
# a list of languages the transcript can be translated to
transcript.translation_languages,
)
et fournissent la méthode qui permet de récupérer les données réelles de la transcription :
transcript.fetch()
Cette commande renvoie un objet FetchedTranscript
, tout comme YouTubeTranscriptApi().fetch()
.
YouTube propose une fonctionnalité permettant de traduire automatiquement les sous-titres. Ce module permet également d'accéder à cette fonctionnalité. Pour ce faire, les objets Transcript
fournissent une méthode translate()
, qui renvoie un nouvel objet Transcript
traduit :
transcript = transcript_list.find_transcript(['en'])
translated_transcript = transcript.translate('de')
print(translated_transcript.fetch())
from youtube_transcript_api import YouTubeTranscriptApi
ytt_api = YouTubeTranscriptApi()
# retrieve the available transcripts
transcript_list = ytt_api.list('video_id')
# iterate over all available transcripts
for transcript in transcript_list:
# the Transcript object provides metadata properties
print(
transcript.video_id,
transcript.language,
transcript.language_code,
# whether it has been manually created or generated by YouTube
transcript.is_generated,
# whether this transcript can be translated or not
transcript.is_translatable,
# a list of languages the transcript can be translated to
transcript.translation_languages,
)
# fetch the actual transcript data
print(transcript.fetch())
# translating the transcript will return another transcript object
print(transcript.translate('en').fetch())
# you can also directly filter for the language you are looking for, using the transcript list
transcript = transcript_list.find_transcript(['de', 'en'])
# or just filter for manually created transcripts
transcript = transcript_list.find_manually_created_transcript(['de', 'en'])
# or automatically generated ones
transcript = transcript_list.find_generated_transcript(['de', 'en'])
RequestBlocked
ou IpBlocked
)Malheureusement, YouTube a commencé à bloquer la plupart des IPs connues pour appartenir à des fournisseurs de cloud (comme AWS, Google Cloud Platform, Azure, etc.), ce qui signifie que vous rencontrerez très probablement des exceptions ReuquestBlocked
ou IpBlocked
lorsque vous déploierez votre code sur des solutions cloud. La même chose peut arriver à l'IP de votre solution auto-hébergée si vous effectuez trop de requêtes. Vous pouvez contourner ces bannissements d'IP en utilisant des proxies. Cependant, comme YouTube bannira les proxies statiques après une utilisation prolongée, opter pour des proxies résidentiels rotatifs est l'option la plus fiable.
Il existe différents fournisseurs qui proposent des proxies résidentiels rotatifs, mais après avoir testé différentes offres, j'ai trouvé Webshare comme étant la plus fiable et l'ai donc intégrée dans ce module pour faciliter sa configuration.
Une fois que vous avez créé un compte Webshare et acheté un package de proxies "Résidentiels" adapté à votre charge de travail (assurez-vous de NE PAS acheter "Proxy Server" ou "Static Residential" !), ouvrez les Paramètres de proxy Webshare pour récupérer votre "Nom d'utilisateur proxy" et "Mot de passe proxy". Avec ces informations, vous pouvez initialiser YouTubeTranscriptApi
comme suit :
from youtube_transcript_api import YouTubeTranscriptApi
from youtube_transcript_api.proxies import WebshareProxyConfig
ytt_api = YouTubeTranscriptApi(
proxy_config=WebshareProxyConfig(
proxy_username="<proxy-username>",
proxy_password="<proxy-password>",
)
)
# all requests done by ytt_api will now be proxied through Webshare
ytt_api.fetch(video_id)
L'utilisation de WebshareProxyConfig
utilisera par défaut des proxies résidentiels rotatifs et ne nécessite aucune configuration supplémentaire.
Notez que des liens de parrainage sont utilisés ici et tout achat effectué via ces liens soutiendra ce projet Open Source, ce qui est très apprécié ! 💖😊🙏💖
Cependant, vous êtes bien sûr libre d'intégrer votre propre solution de proxy en utilisant la classe GenericProxyConfig
, si vous préférez utiliser un autre fournisseur ou implémenter votre propre solution, comme couvert dans la section suivante.
Alternativement à Webshare, vous pouvez configurer n'importe quel proxy HTTP/HTTPS/SOCKS générique en utilisant la classe GenericProxyConfig
:
from youtube_transcript_api import YouTubeTranscriptApi
from youtube_transcript_api.proxies import GenericProxyConfig
ytt_api = YouTubeTranscriptApi(
proxy_config=GenericProxyConfig(
http_url="http://user:[email protected]:port",
https_url="https://user:[email protected]:port",
)
)
# all requests done by ytt_api will now be proxied using the defined proxy URLs
ytt_api.fetch(video_id)
Sachez que l'utilisation d'un proxy ne garantit pas que vous ne serez pas bloqué, car YouTube peut toujours bloquer l'IP de votre proxy ! Par conséquent, vous devriez toujours choisir une solution qui alterne entre un pool d'adresses proxy si vous souhaitez maximiser la fiabilité.
Lors de l'initialisation d'un objet YouTubeTranscriptApi
, il créera une requests.Session
qui sera utilisée pour toutes les requêtes HTTP(S). Cela permet de mettre en cache les cookies lors de la récupération de plusieurs requêtes. Cependant, vous pouvez optionnellement passer un objet requests.Session
dans son constructeur, si vous souhaitez partager manuellement des cookies entre différentes instances de YouTubeTranscriptApi
, remplacer les valeurs par défaut, définir des en-têtes personnalisés, spécifier des certificats SSL, etc.
from requests import Session
http_client = Session()
# set custom header
http_client.headers.update({"Accept-Encoding": "gzip, deflate"})
# set path to CA_BUNDLE file
http_client.verify = "/path/to/certfile"
ytt_api = YouTubeTranscriptApi(http_client=http_client)
ytt_api.fetch(video_id)
# share same Session between two instances of YouTubeTranscriptApi
ytt_api_2 = YouTubeTranscriptApi(http_client=http_client)
# now shares cookies with ytt_api
ytt_api_2.fetch(video_id)
Certaines vidéos sont soumises à des restrictions d'âge, ce module ne pourra donc pas y accéder sans une forme d'authentification. Malheureusement, certains changements récents de l'API YouTube ont cassé l'implémentation actuelle de l'authentification par cookie, cette fonctionnalité n'est donc pas disponible pour le moment.
Les formateurs sont conçus comme une couche supplémentaire de traitement de la transcription que vous leur passez. L'objectif est de convertir un objet FetchedTranscript
en une chaîne de caractères cohérente d'un "format" donné. Comme un texte basique (.txt
) ou même des formats ayant une spécification définie comme JSON (.json
), WebVTT (.vtt
), SRT (.srt
), format séparé par des virgules (.csv
), etc...
Le sous-module formatters
fournit quelques formateurs de base, qui peuvent être utilisés tels quels ou étendus selon vos besoins :
Voici comment importer depuis le module formatters
.
# the base class to inherit from when creating your own formatter.
from youtube_transcript_api.formatters import Formatter
# some provided subclasses, each outputs a different string format.
from youtube_transcript_api.formatters import JSONFormatter
from youtube_transcript_api.formatters import TextFormatter
from youtube_transcript_api.formatters import WebVTTFormatter
from youtube_transcript_api.formatters import SRTFormatter
Imaginons que nous souhaitions récupérer une transcription et la stocker dans un fichier JSON. Cela ressemblerait à ceci :
# your_custom_script.py
from youtube_transcript_api import YouTubeTranscriptApi
from youtube_transcript_api.formatters import JSONFormatter
ytt_api = YouTubeTranscriptApi()
transcript = ytt_api.fetch(video_id)
formatter = JSONFormatter()
# .format_transcript(transcript) turns the transcript into a JSON string.
json_formatted = formatter.format_transcript(transcript)
# Now we can write it out to a file.
with open('your_filename.json', 'w', encoding='utf-8') as json_file:
json_file.write(json_formatted)
# Now should have a new JSON file that you can easily read back into Python.
Passage d'arguments supplémentaires
Puisque JSONFormatter utilise json.dumps()
, vous pouvez également transmettre des arguments supplémentaires dans .format_transcript(transcript)
, comme rendre votre fichier de sortie plus lisible en transmettant l'argument indent=2
.
json_formatted = JSONFormatter().format_transcript(transcript, indent=2)
Vous pouvez implémenter votre propre classe de formateur. Il suffit d'hériter de la classe de base Formatter
et de vous assurer d'implémenter les méthodes format_transcript(self, transcript: FetchedTranscript, **kwargs) -> str
et format_transcripts(self, transcripts: List[FetchedTranscript], **kwargs) -> str
qui doivent finalement renvoyer une chaîne de caractères lorsqu'elles sont appelées sur votre instance de formateur.
class MyCustomFormatter(Formatter):
def format_transcript(self, transcript: FetchedTranscript, **kwargs) -> str:
# Do your custom work in here, but return a string.
return 'your processed output data as a string.'
def format_transcripts(self, transcripts: List[FetchedTranscript], **kwargs) -> str:
# Do your custom work in here to format a list of transcripts, but return a string.
return 'your processed output data as a string.'
Exécutez le script CLI en utilisant les IDs des vidéos comme paramètres et les résultats seront affichés sur la ligne de commande :
youtube_transcript_api <first_video_id> <second_video_id> ...
La CLI vous donne également la possibilité de fournir une liste de langues préférées :
youtube_transcript_api <first_video_id> <second_video_id> ... --languages de en
Vous pouvez également spécifier si vous souhaitez exclure les sous-titres générés automatiquement ou créés manuellement :
youtube_transcript_api <first_video_id> <second_video_id> ... --languages de en --exclude-generated
youtube_transcript_api <first_video_id> <second_video_id> ... --languages de en --exclude-manually-created
Si vous préférez écrire dans un fichier ou rediriger vers une autre application, vous pouvez également afficher les résultats au format json en utilisant la ligne suivante :
youtube_transcript_api <first_video_id> <second_video_id> ... --languages de en --format json > transcripts.json
La traduction des transcriptions via la CLI est également possible :
youtube_transcript_api <first_video_id> <second_video_id> ... --languages en --translate de
Si vous n'êtes pas sûr des langues disponibles pour une vidéo donnée, vous pouvez appeler, pour lister toutes les transcriptions disponibles :
youtube_transcript_api --list-transcripts <first_video_id>
Si l'ID d'une vidéo commence par un trait d'union, vous devrez masquer le trait d'union avec \
pour éviter que la CLI ne le confonde avec un nom d'argument. Par exemple, pour obtenir la transcription de la vidéo avec l'ID -abc123
, exécutez :
youtube_transcript_api "\-abc123"
Si vous rencontrez des erreurs ReqestBlocked
ou IpBlocked
parce que YouTube bloque votre IP, vous pouvez contourner cela en utilisant des proxies résidentiels comme expliqué dans Contourner les bannissements d'IP. Pour utiliser les proxies "Résidentiels" Webshare via la CLI, vous devrez créer un compte Webshare et acheter un package de proxy "Résidentiel" adapté à votre charge de travail (assurez-vous de NE PAS acheter "Proxy Server" ou "Static Residential" !). Ensuite, vous pouvez utiliser le "Nom d'utilisateur proxy" et le "Mot de passe proxy" que vous trouverez dans vos Paramètres de proxy Webshare, pour exécuter la commande suivante :
youtube_transcript_api <first_video_id> <second_video_id> --webshare-proxy-username "username" --webshare-proxy-password "password"
Si vous préférez utiliser une autre solution de proxy, vous pouvez configurer un proxy HTTP/HTTPS générique en utilisant la commande suivante :
youtube_transcript_api <first_video_id> <second_video_id> --http-proxy http://user:pass@domain:port --https-proxy https://user:pass@domain:port
Pour vous authentifier en utilisant des cookies via la CLI comme expliqué dans Authentification par cookie, exécutez :
youtube_transcript_api <first_video_id> <second_video_id> --cookies /path/to/your/cookies.txt
Ce code utilise une partie non documentée de l'API YouTube, appelée par le client web de YouTube. Il n'y a donc aucune garantie qu'il ne cessera pas de fonctionner demain, s'ils changent le fonctionnement. Cependant, je ferai de mon mieux pour que cela fonctionne à nouveau dès que possible si cela arrive. Donc si cela cesse de fonctionner, faites-le-moi savoir !
Pour configurer le projet localement, exécutez les commandes suivantes (nécessite l'installation de poetry) :
poetry install --with test,dev
Il y a des tâches poe pour exécuter les tests, la couverture, le linter et le formateur (vous devrez passer toutes ces étapes pour que la build réussisse) :
poe test
poe coverage
poe format
poe lint
Si vous voulez simplement vous assurer que votre code passe tous les contrôles nécessaires pour obtenir une build verte, vous pouvez simplement exécuter :
poe precommit
Si ce projet vous rend heureux en réduisant votre temps de développement, vous pouvez me rendre heureux en m'offrant une tasse de café, ou en devenant un Sponsor de ce projet :)