You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用YouTube Data API v3下载字幕遇401未授权问题求助

解决YouTube Data API v3下载字幕时的401 Unauthorized问题

首先得明确:虽然网页播放器能免费查看字幕,但YouTube Data API对字幕下载的权限要求和前端播放器完全不同,这就是你遇到401错误的核心原因。

为什么只用API Key不行?

  • API Key仅适用于无需用户身份验证的公开数据读取操作(比如获取视频标题、搜索视频),但字幕属于受版权保护的内容——哪怕是自动生成的字幕,YouTube也要求下载操作必须通过OAuth 2.0授权来验证用户身份,确保你有合法的访问权限(比如你是视频所有者,或者视频允许观众下载字幕)。
  • 网页播放器的“Open transcript”是YouTube提供的前端服务,它的权限验证逻辑是内部处理的,不需要用户手动授权就能查看,但API遵循更严格的开发者权限规范,必须明确验证用户身份。

解决方案:实现OAuth 2.0授权流程

你需要修改代码,用OAuth 2.0凭据代替单纯的API Key。具体步骤如下:

  1. 在Google Cloud Console创建OAuth客户端凭据

    • 进入你的项目,找到“API和服务”→“凭据”,创建“OAuth客户端ID”,类型选择“桌面应用”。
    • 下载生成的credentials.json文件,放在你的项目路径下。
  2. 修改Java代码,加入OAuth授权逻辑
    下面是完整的可运行代码示例,替换你的视频ID即可:

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.youtube.YouTube;
import com.google.api.services.youtube.model.Caption;
import com.google.api.services.youtube.model.CaptionListResponse;
import com.google.api.services.youtube.model.CaptionSnippet;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.security.GeneralSecurityException;
import java.util.Collections;
import java.util.List;

public class YouTubeCaptionDownloader {
    private static final String APPLICATION_NAME = "YouTube Caption Downloader";
    private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
    private static final String TOKENS_DIRECTORY_PATH = "tokens";

    // 下载字幕所需的权限范围
    private static final List<String> SCOPES = Collections.singletonList("https://www.googleapis.com/auth/youtube.force-ssl");
    private static final String CREDENTIALS_FILE_PATH = "credentials.json"; // 注意路径要正确

    private static Credential getCredentials(final com.google.api.client.http.HttpTransport HTTP_TRANSPORT) throws IOException {
        // 加载客户端密钥文件
        FileInputStream in = new FileInputStream(new File(CREDENTIALS_FILE_PATH));
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

        // 创建授权流,保存令牌到本地
        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(new FileDataStoreFactory(new File(TOKENS_DIRECTORY_PATH)))
                .setAccessType("offline") // 允许离线访问,后续无需重复授权
                .build();
        LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
        return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
    }

    public static void main(String[] args) throws GeneralSecurityException, IOException {
        // 初始化HTTP传输和YouTube服务(带OAuth授权)
        final com.google.api.client.http.HttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
        YouTube youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
                .setApplicationName(APPLICATION_NAME)
                .build();

        String videoId = "YOUR_TARGET_VIDEO_ID"; // 替换成你要下载字幕的视频ID

        // 请求该视频的字幕列表
        YouTube.Captions.List request = youtube.captions().list("snippet", videoId);
        CaptionListResponse response = request.execute();
        List<Caption> captions = response.getItems();

        for (Caption caption : captions) {
            CaptionSnippet snippet = caption.getSnippet();
            System.out.println("===== 字幕信息 =====");
            System.out.println("ID: " + caption.getId());
            System.out.println("名称: " + snippet.getName());
            System.out.println("语言: " + snippet.getLanguage());
            
            String captionID = caption.getId();
            String outputFileName = "captions_" + captionID + ".vtt";

            // 下载并保存字幕到本地文件
            try (OutputStream output = new FileOutputStream(outputFileName)) {
                YouTube.Captions.Download downloadReq = youtube.captions().download(captionID);
                downloadReq.executeMediaAndDownloadTo(output);
                System.out.println("字幕已成功保存到:" + outputFileName);
            } catch (IOException e) {
                System.err.println("下载字幕失败:" + e.getMessage());
            }
        }
    }
}

额外注意事项

  • 确保你已经在Google Cloud Console中启用了YouTube Data API v3,否则会提示API未启用的错误。
  • 第一次运行代码时,会自动打开浏览器让你登录Google账号,授权应用访问你的YouTube数据。授权成功后,令牌会保存在tokens目录下,后续运行不需要再次授权。
  • 不是所有公开视频的字幕都允许下载:如果视频所有者在后台禁用了字幕下载权限,即使你完成了OAuth授权,也会收到403 Forbidden错误,这属于视频所有者的权限设置问题,无法通过代码解决。

内容的提问来源于stack exchange,提问作者Daniel

火山引擎 最新活动