如何透過一次 API 呼叫取得 YouTube、TikTok、Reels、X 及 Podcast 逐字稿,以及 youtube-transcript-api 腳本為何在伺服器上失效
Get transcripts from YouTube, TikTok, Reels, X and podcasts in one API call (and why your youtube-transcript-api script dies on a server)
RS Automation Labs 介紹跨平台逐字稿擷取流程,涵蓋 DIY 程式碼及其自建的 Apify Actor Video Transcripts + AI Summaries。
Disclosure: I build the Apify Actor shown in part 2 (it's paid, pay-per-use). Part 1 is free DIY code you can use without it.
If you've ever tried to pull transcripts at scale, you've probably hit this sequence:
-
youtube-transcript-apiworks perfectly on your laptop. - You deploy it to AWS, Vercel, Railway or n8n Cloud.
- Every call raises
RequestBlocked/IpBlocked. YouTube blocks most cloud and datacenter IPs. - Then someone asks for TikTok and Instagram Reels too, and those mostly have no captions at all.
This post covers the DIY route first (it's fine for a laptop or a one-off backfill), then the hosted route I built for when you need mixed platforms from a server.
Part 1: DIY
YouTube videos that have captions
# pip install youtube-transcript-api
from youtube_transcript_api import YouTubeTranscriptApi
api = YouTubeTranscriptApi()
t = api.fetch("jNQXAC9IVRw", languages=["en"])
for s in t:
print(f"{s.start:6.1f}s {s.text}")
This works from a home connection. From a cloud server you need rotating residential proxies (the library supports WebshareProxyConfig and GenericProxyConfig). Datacenter proxies get blocked for the same reason your server does, and so do "static residential" ones.
TikTok, Reels, X, and YouTube videos without captions
There are no captions to fetch, so you have to download the audio and run speech-to-text:
# pip install yt-dlp faster-whisper (ffmpeg must be installed)
import yt_dlp
from faster_whisper import WhisperModel
url = "https://www.tiktok.com/@spacedotcom/video/7629097281974848782"
with yt_dlp.YoutubeDL({"format": "bestaudio", "outtmpl": "clip.%(ext)s"}) as y:
info = y.extract_info(url, download=True)
path = y.prepare_filename(info)
model = WhisperModel("small", compute_type="int8") # CPU is fine for short clips
segments, _ = model.transcribe(path)
for s in segments:
print(f"{s.start:6.1f}s {s.text}")
Things that bite you in production:
- Instagram often needs cookies or a residential IP to download reels. Don't put your personal account's cookies on a server.
- Music-only clips: Whisper happily "transcribes" music into nonsense ("Thank you for watching!"). You need a no-speech check.
- Long podcasts: split the audio into chunks (I use 5-minute chunks), transcribe them in parallel, and shift each chunk's timestamps by its offset. Otherwise you're waiting minutes per episode and timestamps drift.
-
Podcasts often already have transcripts. Many feeds publish a Podcasting 2.0
<podcast:transcript>tag. Check for it before paying for speech-to-text.
Part 2: the hosted route (one call, any platform)
I packaged all of the above into an Apify Actor: Video Transcripts + AI Summaries. You paste a mixed list of URLs and get one row per URL with the same schema, whatever the platform:
- It uses native captions first (YouTube manual/auto captions, TikTok/X subtitles, podcast transcript tags). That path is fast, exact and cheap.
- It falls back to AI speech-to-text only when no captions exist.
- It's built to survive blocking: it rotates YouTube player clients and falls back to residential proxy automatically.
- It can add an optional AI summary, key points and timestamped chapters.
-
Failed URLs are free. Deleted, private and music-only posts get an error row with a code like
NOT_FOUND,LOGIN_REQUIREDorNO_SPEECH, and you're not charged for them.
Input
{
"urls": [
"https://www.youtube.com/watch?v=arj7oStGLkU",
"https://www.tiktok.com/@spacedotcom/video/7629097281974848782",
"https://www.instagram.com/nasa/reel/ClmOrBujnxG/",
"https://x.com/SpaceX/status/2112502543947325773",
"https://feeds.npr.org/500005/podcast.xml"
],
"outputFormats": ["text", "segments", "srt"],
"aiSummary": true,
"maxEpisodesPerFeed": 1
}
Output (one real row, trimmed)
{
"url": "https://www.tiktok.com/@spacedotcom/video/7629097281974848782",
"platform": "tiktok",
"status": "ok",
"transcriptSource": "speech-to-text",
"language": "en",
"durationSeconds": 50,
"segments": [
{ "start": 0.0, "end": 4.0, "text": "What was it like being inside the Orion spacecraft during Artemis 2?" },
{ "start": 4.0, "end": 12.0, "text": "This is space.com here at Space Symposium in Colorado Springs, where Lockheed Martin has this amazing Orion spacecraft simulator." }
],
"summary": "Space.com reports from the Space Symposium in Colorado Springs, where Lockheed Martin is showcasing a mixed reality simulator of the Orion spacecraft...",
"chapters": [
{ "timestamp": "0:00", "title": "Introduction to the Orion simulator" },
{ "timestamp": "0:25", "title": "Exploring the interior features" }
]
}
Calling it from code (Python, n8n, anything with HTTP)
import requests, os
r = requests.post(
"https://api.apify.com/v2/acts/rs-automation-labs~video-transcripts-ai-summaries/run-sync-get-dataset-items",
params={"token": os.environ["APIFY_TOKEN"]},
json={"urls": ["https://www.youtube.com/watch?v=arj7oStGLkU"]},
timeout=300,
)
for row in r.json():
print(row["status"], row.get("text", "")[:200])
In n8n, Make or Zapier, use the Apify integration (or a plain HTTP Request node) with the same JSON. Your workflow then never talks to YouTube directly, so n8n Cloud IP blocks stop mattering.
What it costs
The Actor charges per event:
| Event | Price |
|---|---|
| Transcript (per URL that succeeds) | $0.004 |
| Audio minute (only when speech-to-text was needed) | $0.006 per started minute |
| AI summary (only if you turn it on) | $0.003 |
Worked examples:
- 100 YouTube videos with captions: 100 × $0.004 = $0.40.
- A 1-minute TikTok with no captions: $0.004 + $0.006 = $0.010, plus the AI model cost at OpenRouter price (a fraction of a cent on paid Apify plans).
- A 30-minute podcast episode without a published transcript: about $0.18 plus model cost.
Apify's free plan includes $5 of monthly usage, which covers roughly a thousand captioned YouTube videos. One caveat to know up front: on Apify's free plan, AI model usage through Apify's OpenRouter proxy is billed at a markup. If you'll do a lot of speech-to-text, add your own OpenRouter API key in the input and you pay OpenRouter directly.
Honest limitations
- Long-audio speech-to-text is Beta. Short clips have been reliable in my tests. Long multi-chunk episodes have failed often enough upstream (provider HTTP 500s) that I label them Beta. Failed episodes aren't charged, and a retry usually works.
- No private, login-only, age-restricted or DRM content (Spotify-exclusive episodes return
DRM_PROTECTED). - Gemini speech-to-text timestamps are approximate (about 1–2 s). If you need tighter timestamps, use Whisper with your own OpenRouter key.
Which route should you pick?
-
A few hundred YouTube videos, from your laptop: use
youtube-transcript-api. It's free. - YouTube from a server: use the library plus a rotating residential proxy, or a hosted API.
- Mixed platforms, no-caption clips, podcasts, or you want summaries and chapters in the same JSON: that's the case the Actor is built for. Try it on Apify.
If you hit a URL it can't handle, tell me in the comments. Error rows include a code, so it's quick to debug.
來源:DEV Community · dev.to