科学工具
科学工具让世界更美好
让世界更美好

Youtube 字幕提取工具 youtube-transcript-api 使用手册Youtube 字幕提取工具 youtube-transcript-api 使用手册

这是一个 Python API,可用来获取 YouTube 视频的字幕或文本记录,能处理自动生成的字幕,支持翻译字幕。和其他基于 Selenium 的解决方案不同,它不需要无头浏览器。

安装

建议通过 pip 安装这个模块:

pip install youtube-transcript-api

你可以把这个模块集成到现有的应用程序中,也能通过命令行界面使用它。

API 用法

获取给定视频字幕的简单方法是执行以下代码:

from youtube_transcript_api import YouTubeTranscriptApi

ytt_api = YouTubeTranscriptApi()
ytt_api.fetch(video_id)

默认情况下,它会尝试访问视频的英文转录本。如果你的视频有其他语言,或者你想获取其他语言的转录本,请阅读下面的部分。

传入的是视频 ID,而不是视频 URL。对于 URL 为 https://www.youtube.com/watch?v=12345 的视频,其 ID 是 12345

将返回一个 FetchedTranscript 对象:

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,
)

这个对象实现了 List<代码开始> 的大多数接口:

ytt_api = YouTubeTranscriptApi()
fetched_transcript = ytt_api.fetch(video_id)

# 可迭代
for snippet in fetched_transcript:
    print(snippet.text)

# 可索引
last_snippet = fetched_transcript[-1]

# 可获取长度
snippet_count = len(fetched_transcript)

如果你更倾向于处理原始的字幕数据,可以调用 fetched_transcript.to_raw_data(),它会返回一个字典列表:

[
    {
        'text': 'Hey there',
        'start': 0.0,
        'duration': 1.54
    },
    {
        'text': 'how are you',
        'start': 1.54,
        'duration': 4.16
    },
    # ...

]

检索不同语言的字幕

如果你想确保以所需语言检索字幕,可以添加 languages 参数(默认是英文)。

YouTubeTranscriptApi().fetch(video_id, languages=['de', 'en'])

这是一个按优先级降序排列的语言代码列表。在这个例子中,它会先尝试获取德语字幕(de),如果失败,再获取英语字幕(en)。如果你想先了解有哪些可用语言,可以看看 list() 方法。

如果你只需要一种语言,仍然需要将 languages 参数格式化为列表:

YouTubeTranscriptApi().fetch(video_id, languages=['de'])

保留格式

如果你想保留 HTML 格式元素,比如 <i>(斜体)和 <b>(粗体),也可以添加 preserve_formatting=True

YouTubeTranscriptApi().fetch(video_ids, languages=['de', 'en'], preserve_formatting=True)

列出可用的字幕

如果你想列出给定视频的所有可用字幕,可以调用:

ytt_api = YouTubeTranscriptApi()
transcript_list = ytt_api.list(video_id)

将返回一个 TranscriptList 对象,它是可迭代的,并提供了按特定语言和类型过滤字幕列表的方法,例如:

transcript = transcript_list.find_transcript(['de', 'en'])

默认情况下,如果请求的语言同时有手动创建和自动生成的字幕,该模块总是选择手动创建的字幕。TranscriptList 允许你绕过这个默认行为,搜索特定的字幕类型:

# 过滤手动创建的字幕
transcript = transcript_list.find_manually_created_transcript(['de', 'en'])

# 或自动生成的字幕
transcript = transcript_list.find_generated_transcript(['de', 'en'])

find_generated_transcriptfind_manually_created_transcriptfind_transcript 方法返回 Transcript 对象。它们包含关于字幕的元数据:

print(
    transcript.video_id,
    transcript.language,
    transcript.language_code,
    # 它是手动创建的还是由 YouTube 生成的
    transcript.is_generated,
    # 这个字幕是否可以翻译
    transcript.is_translatable,
    # 这个字幕可以翻译成的语言列表
    transcript.translation_languages,
)

提供了允许你获取实际字幕数据的方法:

transcript.fetch()

这将返回一个 FetchedTranscript 对象,就像 YouTubeTranscriptApi().fetch() 所做的那样。

翻译字幕

YouTube 有一个允许你自动翻译字幕的功能,这个模块也使访问这个功能成为可能。为此,Transcript 对象提供了一个 translate() 方法,它返回一个新的已翻译的 Transcript 对象:

transcript = transcript_list.find_transcript(['en'])
translated_transcript = transcript.translate('de')
print(translated_transcript.fetch())

示例

from youtube_transcript_api import YouTubeTranscriptApi

ytt_api = YouTubeTranscriptApi()

# 检索可用的字幕
transcript_list = ytt_api.list('video_id')

# 遍历所有可用的字幕
for transcript in transcript_list:
    # Transcript 对象提供元数据属性
    print(
        transcript.video_id,
        transcript.language,
        transcript.language_code,
        # 它是手动创建的还是由 YouTube 生成的
        transcript.is_generated,
        # 这个字幕是否可以翻译
        transcript.is_translatable,
        # 这个字幕可以翻译成的语言列表
        transcript.translation_languages,
    )

    # 获取实际的字幕数据
    print(transcript.fetch())

    # 翻译字幕将返回另一个字幕对象
    print(transcript.translate('en').fetch())

# 你也可以直接使用字幕列表过滤你要找的语言
transcript = transcript_list.find_transcript(['de', 'en'])

# 或只是过滤手动创建的字幕
transcript = transcript_list.find_manually_created_transcript(['de', 'en'])

# 或自动生成的字幕
transcript = transcript_list.find_generated_transcript(['de', 'en'])

解决 IP 封禁问题(RequestBlockedIpBlocked 异常)

不幸的是,YouTube 已经开始阻止大多数已知属于云提供商(如 AWS、Google Cloud Platform、Azure 等)的 IP,这意味着当你将代码部署到任何云解决方案时,很可能会遇到 ReuquestBlockedIpBlocked 异常。如果你的自托管解决方案发出太多请求,其 IP 也可能遇到这种情况。你可以使用代理来解决这些 IP 封禁问题。然而,由于 YouTube 会在长时间使用后封禁静态代理,因此使用旋转住宅代理是可靠的选择。

有不同的提供商提供旋转住宅代理,但在测试了不同的产品后,我发现 Webshare 是可靠的,因此将其集成到这个模块中,使其设置起来容易。

使用 Webshare

一旦你创建了一个 Webshare 账户并购买了适合你工作负载的“住宅”代理包(确保不要购买“代理服务器”或“静态住宅”!),打开 Webshare 代理设置以检索你的“代理用户名”和“代理密码”。使用此信息,你可以按如下方式初始化 YouTubeTranscriptApi

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

# ytt_api 完成的所有请求现在都将通过 Webshare 代理
ytt_api.fetch(video_id)

使用 WebshareProxyConfig 将默认使用旋转住宅代理,无需进一步配置。

使用其他代理解决方案

除了使用 Webshare,你还可以使用 GenericProxyConfig 类设置任何通用的 HTTP/HTTPS/SOCKS 代理:

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

# ytt_api 完成的所有请求现在都将使用定义的代理 URL 进行代理
ytt_api.fetch(video_id)

请注意,使用代理并不能保证你不会被阻止,因为 YouTube 总是可以阻止你代理的 IP!因此,如果你想最大化可靠性,你应该始终选择一个通过代理地址池轮换的解决方案。

覆盖请求默认值

初始化 YouTubeTranscriptApi 对象时,它将创建一个 requests.Session,用于所有 HTTP(S) 请求。这允许在检索多个请求时缓存 cookie。但是,如果你想在不同的 YouTubeTranscriptApi 实例之间手动共享 cookie、覆盖默认值、设置自定义标头、指定 SSL 证书等,你可以选择将 requests.Session 对象传入其构造函数。

from requests import Session

http_client = Session()

# 设置自定义标头
http_client.headers.update({"Accept-Encoding": "gzip, deflate"})

# 设置 CA_BUNDLE 文件的路径
http_client.verify = "/path/to/certfile"

ytt_api = YouTubeTranscriptApi(http_client=http_client)
ytt_api.fetch(video_id)

# 在两个 YouTubeTranscriptApi 实例之间共享同一个 Session
ytt_api_2 = YouTubeTranscriptApi(http_client=http_client)
# 现在与 ytt_api 共享 cookie
ytt_api_2.fetch(video_id)

使用格式化工具

格式化工具旨在作为你传递给它的字幕的额外处理层,目的是将 FetchedTranscript 对象转换为给定“格式”的一致字符串,例如基本文本(.txt),甚至是具有定义规范的格式,如 JSON(.json)、WebVTT(.vtt)、SRT(.srt)、逗号分隔格式(.csv)等。

formatters 子模块提供了一些基本的格式化工具,可以直接使用或根据需要进行扩展: • JSONFormatter • PrettyPrintFormatter • TextFormatter • WebVTTFormatter • SRTFormatter

下面是如何从 formatters 模块导入:

# 创建自己的格式化工具时要继承的基类
from youtube_transcript_api.formatters import Formatter

# 一些提供的子类,每个子类输出不同的字符串格式
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

格式化工具示例

假设我们想检索一个字幕并将其存储到 JSON 文件中,这看起来像这样:

# 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) 将字幕转换为 JSON 字符串
json_formatted = formatter.format_transcript(transcript)

# 现在我们可以将其写入文件
with open('your_filename.json', 'w', encoding='utf-8') as json_file:
    json_file.write(json_formatted)

# 现在应该有一个新的 JSON 文件,你可以轻松地读回 Python

传递额外的关键字参数

由于 JSONFormatter 利用了 json.dumps(),你还可以将关键字参数转发到 .format_transcript(transcript) 中,例如通过转发 indent=2 关键字参数使文件输出更美观。

json_formatted = JSONFormatter().format_transcript(transcript, indent=2)

自定义格式化工具示例

你可以实现自己的格式化工具类,只需继承 Formatter 基类,并确保实现 format_transcript(self, transcript: FetchedTranscript, **kwargs) -> strformat_transcripts(self, transcripts: List[FetchedTranscript], **kwargs) -> str 方法,当在你的格式化工具实例上调用时,这些方法最终应该返回一个字符串。

class MyCustomFormatter(Formatter):
    def format_transcript(self, transcript: FetchedTranscript, **kwargs) -> str:
        # 在这里完成你的自定义工作,但要返回一个字符串
        return 'your processed output data as a string.'

    def format_transcripts(self, transcripts: List[FetchedTranscript], **kwargs) -> str:
        # 在这里完成你的自定义工作以格式化字幕列表,但要返回一个字符串
        return 'your processed output data as a string.'

命令行界面(CLI)

使用视频 ID 作为参数执行 CLI 脚本,结果将打印到命令行:

youtube_transcript_api <first_video_id> <second_video_id> ...

CLI 还为你提供了提供首选语言列表的选项:

youtube_transcript_api <first_video_id> <second_video_id> ... --languages de en

你还可以指定是否要排除自动生成或手动创建的字幕:

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

如果你更愿意将其写入文件或将其管道传输到另一个应用程序,你还可以使用以下行以 json 格式输出结果:

youtube_transcript_api <first_video_id> <second_video_id> ... --languages de en --format json > transcripts.json

使用 CLI 翻译字幕也是可能的:

youtube_transcript_api <first_video_id> <second_video_id> ... --languages en --translate de

如果你不确定给定视频有哪些可用语言,你可以调用以下命令列出所有可用字幕:

youtube_transcript_api --list-transcripts <first_video_id>

如果视频的 ID 以连字符开头,你必须使用 \< 来屏蔽连字符,以防止 CLI 将其误认为参数名称。例如,要获取 ID 为 -abc123 的视频的字幕,请运行:

youtube_transcript_api "\-abc123"

使用 CLI 解决 IP 封禁问题

如果你遇到 ReqestBlockedIpBlocked 错误,因为 YouTube 阻止了你的 IP,你可以按照“解决 IP 封禁问题”中解释的那样使用住宅代理来解决这个问题。要通过 CLI 使用 Webshare“住宅”代理,你必须创建一个 Webshare 账户并购买适合你工作负载的“住宅”代理包(确保不要购买“代理服务器”或“静态住宅”!)。然后你可以使用你在 Webshare 代理设置中找到的“代理用户名”和“代理密码”来运行以下命令:

youtube_transcript_api <first_video_id> <second_video_id> --webshare-proxy-username "username" --webshare-proxy-password "password"

如果你更喜欢使用其他代理解决方案,你可以使用以下命令设置通用的 HTTP/HTTPS 代理:

youtube_transcript_api <first_video_id> <second_video_id> --http-proxy http://user:pass@domain:port --https-proxy https://user:pass@domain:port

使用 CLI 进行 cookie 身份验证

要通过 CLI 按照“cookie 身份验证”中解释的那样使用 cookie 进行身份验证,请运行:

youtube_transcript_api <first_video_id> <second_video_id> --cookies /path/to/your/cookies.txt