如何使用JavaScript实现YouTube字幕下载功能?
实现Web端JavaScript下载YouTube视频字幕的方案
1. 获取可用字幕列表
通过解析YouTube视频页面的配置数据提取字幕轨道信息,注意浏览器同源策略限制,需通过代理转发请求。
async function getAvailableCaptions(videoId) { try { // 替换为你的代理地址,规避CORS问题 const proxyUrl = 'http://localhost:3000/proxy?url='; const targetUrl = `https://www.youtube.com/watch?v=${videoId}&hl=en&has_verified=1&bpctr=9999999999`; const response = await fetch(proxyUrl + encodeURIComponent(targetUrl)); const html = await response.text(); const captionMatch = html.match(/ytplayer\.config\s*=\s*({.*?});/); if (!captionMatch) throw new Error('无法提取字幕配置'); const config = JSON.parse(captionMatch[1]); const captionTracks = config.args.player_response.captions?.playerCaptionsTracklistRenderer?.captionTracks || []; return captionTracks.map(track => ({ label: track.name.simpleText, languageCode: track.languageCode, baseUrl: track.baseUrl })); } catch (err) { console.error('获取字幕列表失败:', err); return []; } }
2. 渲染语言选择器
动态生成下拉菜单供用户选择目标字幕语言:
<input type="text" id="videoIdInput" placeholder="输入YouTube视频ID"> <button onclick="loadCaptions()">加载字幕选项</button> <select id="languageSelect"></select> <button onclick="downloadSelectedCaption()">下载SRT字幕</button>
async function loadCaptions() { const videoId = document.getElementById('videoIdInput').value.trim(); if (!videoId) { alert('请输入视频ID'); return; } const captions = await getAvailableCaptions(videoId); const select = document.getElementById('languageSelect'); select.innerHTML = ''; captions.forEach(caption => { const option = document.createElement('option'); option.value = caption.baseUrl; option.textContent = `${caption.label} (${caption.languageCode})`; select.appendChild(option); }); }
3. 转换字幕为SRT格式
请求字幕XML数据并解析转换为标准SRT格式:
async function fetchAndConvertToSrt(captionUrl) { const proxyUrl = 'http://localhost:3000/proxy?url='; const targetUrl = `${captionUrl}&fmt=srv3`; // fmt参数指定返回兼容SRT的XML格式 const response = await fetch(proxyUrl + encodeURIComponent(targetUrl)); const xmlText = await response.text(); const xmlDoc = new DOMParser().parseFromString(xmlText, 'text/xml'); const cues = xmlDoc.getElementsByTagName('text'); let srtContent = ''; let index = 1; for (const cue of cues) { const start = parseFloat(cue.getAttribute('start')); const duration = parseFloat(cue.getAttribute('dur')); const end = start + duration; const text = cue.textContent.replace(/\n+/g, ' ').trim(); if (!text) continue; srtContent += `${index}\n${formatSrtTime(start)} --> ${formatSrtTime(end)}\n${text}\n\n`; index++; } return srtContent; } // 将秒数转换为SRT时间格式:00:00:00,000 function formatSrtTime(seconds) { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = seconds % 60; return [ String(hours).padStart(2, '0'), String(minutes).padStart(2, '0'), secs.toFixed(3).padStart(6, '0').replace('.', ',') ].join(':'); }
4. 触发浏览器下载
生成Blob对象并通过a标签触发下载:
async function downloadSelectedCaption() { const select = document.getElementById('languageSelect'); const selectedUrl = select.value; if (!selectedUrl) { alert('请选择字幕语言'); return; } try { const srtContent = await fetchAndConvertToSrt(selectedUrl); const blob = new Blob([srtContent], { type: 'application/x-subrip' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'youtube-subtitle.srt'; document.body.appendChild(a); a.click(); URL.revokeObjectURL(url); document.body.removeChild(a); } catch (err) { console.error('下载失败:', err); alert('字幕下载失败,请检查视频ID或代理配置'); } }
关键注意事项
- CORS代理:浏览器禁止直接跨域请求YouTube,必须搭建代理服务器转发请求。以下是简单的Node.js代理示例:
const express = require('express'); const fetch = require('node-fetch'); const app = express(); app.get('/proxy', async (req, res) => { const url = decodeURIComponent(req.query.url); try { const response = await fetch(url); const data = await response.text(); res.set('Content-Type', response.headers.get('Content-Type')); res.send(data); } catch (err) { res.status(500).send('代理请求失败'); } }); app.listen(3000, () => console.log('代理服务器运行在 http://localhost:3000'));
- API替代方案:如果需要更高稳定性,可使用YouTube Data API v3的
captions.list接口获取字幕,但需API密钥,且有请求配额限制。 - 字幕格式适配:部分视频的字幕XML结构可能不同,需根据实际返回的标签调整解析逻辑(比如有的用
<p>标签替代<text>)。
内容的提问来源于stack exchange,提问作者Rebaz Xoshnaw
相关产品推荐
相关产品推荐

