유튜브 자막 추출기 — Python으로 만들기
왜 만들었나
유튜브 영상 내용을 텍스트로 뽑아야 할 때가 있다. 강의 요약, 번역, AI 분석 등 용도가 다양하다. youtube-transcript-api 라이브러리를 쓰면 YouTube Data API 키 없이 자막을 바로 가져올 수 있다. 여기에 CLI 인터페이스를 붙여서 실용적인 스크립트로 만들었다.
구현 기능:
- YouTube URL 또는 Video ID로 자막 추출
- 언어 우선순위 지정 (기본: 한국어 → 영어)
- 타임스탬프 포함/미포함 선택
- 파일 저장 또는 터미널 출력
- 사용 가능한 자막 언어 목록 확인
기술 상세
youtube-transcript-api
YouTube의 자막 요청은 공개 엔드포인트를 통해 이루어진다. youtube-transcript-api는 이 과정을 추상화한 라이브러리다. API 키 불필요, 설치 후 바로 사용 가능하다.
v1.2.0부터 인스턴스 기반 API로 변경됐다.
| 버전 | 사용 방식 |
|---|---|
| v0.x | YouTubeTranscriptApi.get_transcript(id) (클래스 메서드) |
| v1.x | YouTubeTranscriptApi().fetch(id) (인스턴스 메서드) |
구조
main.py
├── extract_video_id() ← URL/ID 파싱 (정규식 4종)
├── format_timestamp() ← 초 → HH:MM:SS
├── list_available_languages() ← 자막 언어 목록 출력
├── fetch_transcript() ← 자막 fetch + 폴백 처리
├── build_output() ← 엔트리 → 문자열 변환
└── main() ← CLI argparse 진입점
단일 파일로 전체 로직을 담았다. requirements.txt 하나면 설치 끝이다.
핵심 소스 코드
URL에서 Video ID 추출
def extract_video_id(url_or_id: str) -> str:
# 이미 ID 형식이면 그대로 반환
if re.fullmatch(r'[a-zA-Z0-9_-]{11}', url_or_id):
return url_or_id
patterns = [
r'(?:v=)([a-zA-Z0-9_-]{11})', # ?v=ID
r'(?:youtu\.be/)([a-zA-Z0-9_-]{11})', # youtu.be/ID
r'(?:embed/)([a-zA-Z0-9_-]{11})', # /embed/ID
r'(?:shorts/)([a-zA-Z0-9_-]{11})', # /shorts/ID
]
for pattern in patterns:
match = re.search(pattern, url_or_id)
if match:
return match.group(1)
raise ValueError(f"유효한 YouTube URL 또는 Video ID가 아닙니다: {url_or_id}")
YouTube Video ID는 항상 11자리 [a-zA-Z0-9_-] 조합이다. 일반 URL, 단축 URL, 임베드 URL, Shorts까지 4가지 패턴을 처리한다.
자막 fetch + 폴백 처리
def fetch_transcript(api: YouTubeTranscriptApi, video_id: str, languages: list[str]) -> list[dict]:
try:
fetched = api.fetch(video_id, languages=languages)
return [{'text': s.text, 'start': s.start, 'duration': s.duration} for s in fetched]
except NoTranscriptFound:
# 요청 언어가 없으면 첫 번째 사용 가능한 자막으로 대체
transcript_list = api.list(video_id)
fallback = next(iter(transcript_list))
print(f"[info] 요청 언어 없음. '{fallback.language_code}' 자막으로 대체합니다.", file=sys.stderr)
fetched = fallback.fetch()
return [{'text': s.text, 'start': s.start, 'duration': s.duration} for s in fetched]
api.fetch()는 FetchedTranscript 객체를 반환한다. Snippet 객체의 .text, .start, .duration을 dict로 변환해서 이후 처리를 단순하게 만들었다.
타임스탬프 출력
def format_timestamp(seconds: float) -> str:
total = int(seconds)
h = total // 3600
m = (total % 3600) // 60
s = total % 60
if h:
return f"{h:02d}:{m:02d}:{s:02d}"
return f"{m:02d}:{s:02d}"
--timestamp 플래그를 주면 각 자막 구간 앞에 [MM:SS] 또는 [HH:MM:SS]를 붙인다.
CLI 설계
parser.add_argument('url', help='YouTube URL 또는 Video ID')
parser.add_argument('-l', '--lang', nargs='+', default=['ko', 'en'])
parser.add_argument('-o', '--output', metavar='FILE')
parser.add_argument('--timestamp', action='store_true')
parser.add_argument('--list', action='store_true')
argparse의 nargs='+'를 쓰면 -l ko en ja 식으로 여러 언어를 한 번에 지정할 수 있다. 앞에 있을수록 우선순위가 높다.
실행 결과
# 사용 가능한 자막 언어 확인
$ python main.py VIDEO_ID --list
[수동 자막]
en English
ja Japanese
[자동 생성 자막]
en English (auto-generated)
# 한국어 우선, 없으면 영어로 추출
$ python main.py VIDEO_ID -l ko en
# 타임스탬프 포함 파일로 저장
$ python main.py VIDEO_ID --timestamp -o transcript.txt
[완료] 'transcript.txt' 저장됨 (12,847자, 253개 구간)
기술 선택 비교
| 방법 | API 키 | 속도 | 한계 |
|---|---|---|---|
| youtube-transcript-api (이번) | 불필요 | 빠름 | 자막 없는 영상 불가 |
| YouTube Data API v3 | 필요 | 빠름 | 할당량 제한 |
| yt-dlp + --write-sub | 불필요 | 느림 | yt-dlp 설치 필요 |
| Whisper (OpenAI) | 불필요 | 매우 느림 | GPU/시간 필요, 오류율 있음 |
자막이 있는 영상이라면 youtube-transcript-api가 가장 빠르고 간편하다.
삽질 기록
1. v1.x에서 클래스 메서드 사라짐
YouTubeTranscriptApi.get_transcript(id) 방식이 v1.0에서 제거됐다. YouTubeTranscriptApi().fetch(id) 인스턴스 방식으로 변경됐다. 라이브러리 설치 후 버전 확인 필수.
2. FetchedTranscript가 dict가 아님
fetched[0]['text'] 접근이 안 됐다. v1.x에서는 Snippet 객체를 반환한다. .text, .start, .duration 속성으로 접근하거나, 명시적으로 dict로 변환해야 한다.
3. 자동 생성 자막과 수동 자막 구분
api.list(video_id)로 가져온 TranscriptList를 순회하면 t.is_generated 속성으로 자동/수동을 구분할 수 있다.
마무리
이 스크립트 하나면 강의 유튜브를 텍스트로 변환해서 AI 요약에 넘기거나, 자막 파일을 만들거나, 번역 작업 소스로 쓸 수 있다. youtube-transcript-api 덕분에 핵심 로직이 30줄도 안 된다.
다음 단계로 확장하면: --format srt 옵션 추가, 여러 영상 일괄 처리, Claude API로 자동 요약 연결.
기술 스택: Python 3.13, youtube-transcript-api 1.2.x, argparse
소스 코드: GitHub
'튜토리얼 > 자동화' 카테고리의 다른 글
| [n8n + Make] 블로그 포스팅 자동화 — Markdown push → 티스토리 자동 발행 (0) | 2026.03.05 |
|---|---|
| [Python + Ollama] API 키 없이 PDF 요약 자동화 스크립트 (0) | 2026.03.05 |
| [Python] Telegram 봇 만들기 — 명령어, 날씨 API, 인라인 버튼, 메모 (1) | 2026.03.04 |
| [Python] BeautifulSoup으로 웹 스크래퍼 만들기 — 파싱, 페이지네이션, CSV 저장 (0) | 2026.03.04 |
| [Python] openpyxl로 엑셀 보고서 자동 생성하기 — 스타일링, 수식, 차트까지 (0) | 2026.03.03 |