Node.js 中的 YouTube 转录文本:原生 fetch,无需 npm 安装

你不需要一个包。在 Node.js 中获取 YouTube 转录文本是一个 HTTPS 调用,fetch 自 Node 18 以来一直是全局的,端点说纯 JSON。本文中的所有内容在空目录中运行,没有 package.json——到最后你会有一个 transcribe() 函数,为任何 YouTube URL 返回标题、发布日期和完整转录文本,带有不猜测的错误处理。
npm 注册表有一打转录文本爬虫,他们分享一个命运:他们使用你的服务器 IP 从 YouTube 获取,YouTube 阻止数据中心 IP。托管 API 完全绕过了这一点。
整个东西
const KEY = process.env.YT2TEXT_KEY;
async function transcribe(videoUrl, maxChars = 150000) {
const qs = new URLSearchParams({ url: videoUrl, maxChars: String(maxChars) });
const res = await fetch(`https://youtube2text.org/api/transcribe?${qs}`, {
headers: { "x-api-key": KEY },
});
const body = await res.json();
if (!res.ok) {
const err = new Error(`${body.error.code}: ${body.error.message}`);
err.code = body.error.code;
err.retryAfterSeconds = body.error.retryAfterSeconds;
throw err;
}
return body.result;
}
const t = await transcribe("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
console.log(`${t.title} — ${t.contentSize} chars`);
console.log(t.content.slice(0, 300));
另存为 index.mjs(顶级 await 需要 ESM),运行 node index.mjs。url 参数需要任何 YouTube URL 变体或裸露 11 字符视频 id,maxChars 限制转录文本长度——150000 既是默认也是上限,所以当文本进入 LLM 提示时修剪它。
还没密钥?获取演示的:
curl https://youtube2text.org/api/demo-key
它返回 {"success":true,"apiKey":"yt_..."} 。要警告它在所有匿名用户中共享,限制于每个 IP 每月 5 个视频——一个踢轮胎密钥,不是生产的。
错误是 JSON,所以那样对待它们
每个失败都有一个稳定的 code 字段。值得分支的那些:
try {
await transcribe("https://youtu.be/xxxxxxxxxxx");
} catch (err) {
switch (err.code) {
case "RATE_LIMIT_EXCEEDED":
console.log(`Back off for ${err.retryAfterSeconds}s, then retry`);
break;
case "TRANSCRIPT_UNAVAILABLE":
console.log("Video has no captions — nothing to fetch, skip it");
break;
case "VIDEO_NOT_FOUND":
case "INVALID_URL":
console.log("Bad input, fix the URL");
break;
default:
throw err; // UNAUTHORIZED, YOUTUBE_ERROR — genuinely unexpected
}
}
TRANSCRIPT_UNAVAILABLE 是整个方法的诚实限制:转录文本来自 YouTube 的字幕轨道,手动或自动生成、英文优先,回退到任何存在的语言。禁用字幕的视频返回 404,没有东西要重试。作为正常情况处理它,不是异常路径。
TypeScript,如果那是你的东西
响应形状是稳定的,所以一对接口给你完整的类型安全,无依赖:
interface TranscriptResult {
videoId: string;
title: string;
pubDate: string;
content: string;
contentSize: number;
truncated: boolean;
}
interface ApiError {
code: string;
message: string;
status: number;
retryAfterSeconds?: number;
}
类型 body 作为 { result: TranscriptResult } | { error: ApiError } 并在 res.ok 上收缩。没有 any、没有转换。
这接入什么
大多数从 Node 调用这个的人正在馈送转录文本到语言模型或内容管道——将谈话变成草稿在YouTube 视频到博客文章中覆盖,如果你的代理框架说 MCP,你可以用MCP 服务器用于 Claude 和 Codex完全跳过 HTTP 层。如果你的栈是混合的,相同端点相同工作从 Python——看Python 版本。
完整的参数和错误参考住在 youtube2text.org/api.md。它是为机器写来读的,这作为副作用使其对人类也是无情地短。