diff --git a/youtube_transcript_api/__init__.py b/youtube_transcript_api/__init__.py index baefd02..2d58d34 100644 --- a/youtube_transcript_api/__init__.py +++ b/youtube_transcript_api/__init__.py @@ -10,5 +10,6 @@ TranslationLanguageNotAvailable, NoTranscriptAvailable, CookiePathInvalid, - CookiesInvalid + CookiesInvalid, + FailedToCreateConsentCookie, ) diff --git a/youtube_transcript_api/_api.py b/youtube_transcript_api/_api.py index ad69b90..37bd6b2 100644 --- a/youtube_transcript_api/_api.py +++ b/youtube_transcript_api/_api.py @@ -129,12 +129,11 @@ def get_transcript(cls, video_id, languages=('en',), proxies=None, cookies=None) @classmethod def _load_cookies(cls, cookies, video_id): - cookie_jar = {} try: cookie_jar = cookiejar.MozillaCookieJar() cookie_jar.load(cookies) + if not cookie_jar: + raise CookiesInvalid(video_id) + return cookie_jar except CookieLoadError: raise CookiePathInvalid(video_id) - if not cookie_jar: - raise CookiesInvalid(video_id) - return cookie_jar diff --git a/youtube_transcript_api/_errors.py b/youtube_transcript_api/_errors.py index c3afb32..cd645b5 100644 --- a/youtube_transcript_api/_errors.py +++ b/youtube_transcript_api/_errors.py @@ -40,10 +40,15 @@ class VideoUnavailable(CouldNotRetrieveTranscript): class TooManyRequests(CouldNotRetrieveTranscript): - CAUSE_MESSAGE = ("YouTube is receiving too many requests from this IP and now requires solving a captcha to continue. One of the following things can be done to work around this:\n\ - - Manually solve the captcha in a browser and export the cookie. Read here how to use that cookie with youtube-transcript-api: https://github.com/jdepoix/youtube-transcript-api#cookies\n\ - - Use a different IP address\n\ - - Wait until the ban on your IP has been lifted") + CAUSE_MESSAGE = ( + 'YouTube is receiving too many requests from this IP and now requires solving a captcha to continue. ' + 'One of the following things can be done to work around this:\n\ + - Manually solve the captcha in a browser and export the cookie. ' + 'Read here how to use that cookie with ' + 'youtube-transcript-api: https://github.com/jdepoix/youtube-transcript-api#cookies\n\ + - Use a different IP address\n\ + - Wait until the ban on your IP has been lifted' + ) class TranscriptsDisabled(CouldNotRetrieveTranscript): @@ -70,6 +75,10 @@ class CookiesInvalid(CouldNotRetrieveTranscript): CAUSE_MESSAGE = 'The cookies provided are not valid (may have expired)' +class FailedToCreateConsentCookie(CouldNotRetrieveTranscript): + CAUSE_MESSAGE = 'Failed to automatically give consent to saving cookies' + + class NoTranscriptFound(CouldNotRetrieveTranscript): CAUSE_MESSAGE = ( 'No transcripts were found for any of the requested language codes: {requested_language_codes}\n\n' diff --git a/youtube_transcript_api/_transcripts.py b/youtube_transcript_api/_transcripts.py index 10c5ec0..b0d6f38 100644 --- a/youtube_transcript_api/_transcripts.py +++ b/youtube_transcript_api/_transcripts.py @@ -20,6 +20,7 @@ NotTranslatable, TranslationLanguageNotAvailable, NoTranscriptAvailable, + FailedToCreateConsentCookie, ) from ._settings import WATCH_URL @@ -32,7 +33,7 @@ def fetch(self, video_id): return TranscriptList.build( self._http_client, video_id, - self._extract_captions_json(self._fetch_html(video_id), video_id) + self._extract_captions_json(self._fetch_video_html(video_id), video_id) ) def _extract_captions_json(self, html, video_id): @@ -55,6 +56,21 @@ def _extract_captions_json(self, html, video_id): return captions_json + def _create_consent_cookie(self, html, video_id): + match = re.search('name="v" value="(.*?)"', html) + if match is None: + raise FailedToCreateConsentCookie(video_id) + self._http_client.cookies.set('CONSENT', 'YES+' + match.group(1), domain='.youtube.com') + + def _fetch_video_html(self, video_id): + html = self._fetch_html(video_id) + if 'action="https://consent.youtube.com/s"' in html: + self._create_consent_cookie(html, video_id) + html = self._fetch_html(video_id) + if 'action="https://consent.youtube.com/s"' in html: + raise FailedToCreateConsentCookie(video_id) + return html + def _fetch_html(self, video_id): return self._http_client.get(WATCH_URL.format(video_id=video_id)).text.replace( '\\u0026', '&' diff --git a/youtube_transcript_api/test/assets/youtube_consent_page.html.static b/youtube_transcript_api/test/assets/youtube_consent_page.html.static new file mode 100644 index 0000000..40b4235 --- /dev/null +++ b/youtube_transcript_api/test/assets/youtube_consent_page.html.static @@ -0,0 +1,160 @@ +
Google verwendet Cookies und Daten, um Dienste und Werbung zur Verfügung zu stellen, zu verwalten und zu verbessern. Wenn Sie zustimmen, nutzen wir Cookies für diese Zwecke und dazu, Inhalte und Werbung für Sie zu personalisieren, damit Sie z. B. relevantere Google-Suchergebnisse und relevantere Werbung bei YouTube erhalten. Die Personalisierung erfolgt auf Grundlage Ihrer Aktivitäten, beispielsweise Ihrer Google-Suchanfragen und der Videos, die Sie sich bei YouTube ansehen. Wir verwenden diese Daten auch für Analysen und Messungen. Klicken Sie auf „Anpassen“, um sich weitere Optionen anzusehen, oder besuchen Sie g.co/privacytools. Darüber hinaus haben Sie die Möglichkeit, Ihre Browsereinstellungen so zu konfigurieren, dass einige oder alle Cookies blockiert werden.
Google verwendet Cookies und Daten, um Dienste und Werbung zur Verfügung zu stellen, zu verwalten und zu verbessern. Wenn Sie zustimmen, nutzen wir Cookies für diese Zwecke und dazu, Inhalte und Werbung für Sie zu personalisieren, damit Sie z. B. relevantere Google-Suchergebnisse und relevantere Werbung bei YouTube erhalten. Die Personalisierung erfolgt auf Grundlage Ihrer Aktivitäten, beispielsweise Ihrer Google-Suchanfragen und der Videos, die Sie sich bei YouTube ansehen. Wir verwenden diese Daten auch für Analysen und Messungen. Klicken Sie auf „Anpassen“, um sich weitere Optionen anzusehen, oder besuchen Sie g.co/privacytools. Darüber hinaus haben Sie die Möglichkeit, Ihre Browsereinstellungen so zu konfigurieren, dass einige oder alle Cookies blockiert werden.