세상에 영원한 것은 없다. 변화 혹은 흐름만이 영속적이다. 유장하기 이를 데 없는 산도 바다도 변한다. 산은 계절에 따라 다른 옷을 입고 세상과 마주한다. 바다는 끊임없이 출렁임으로 싱싱함을 유지한다. 굳건해 보이는 바위가 허물어져 모래가 되고 그것이 변하여 토양이 되기도 한다. 늙은 바위는 자기 위에 떨어진 씨앗을 위해 자기 몸 일부를 열어준다.
- 김기석의 《최소한의 품격》 중에서 -
* 세상의 모든 것은 지속적이지 않습니다. 늘 변합니다. 사람도 자연도 단단한 바위도 변합니다. '영원히 변하지 않겠다'는 맹세도 변합니다. 조건 따라 상황 따라 모든 것은 있다가도 사라집니다. 놀라운 것은 그 과정에서 새로운 생명이 탄생하는 것입니다. 언젠가는 흙으로 돌아갈 늙은 바위는 자기 몸으로 씨앗을 키웁니다. 위대한 변화입니다.
""" 유튜브 자막 가져오기
pip install youtube-transcript-api
-- 최신 버전으로 업데이트
pip install --upgrade youtube-transcript-api
https://www.youtube.com/watch?v=XyljmT8dGA4
자막있는 동영상 : https://www.youtube.com/watch?v=zRz9q8dPjC4
"""
from youtube_transcript_api import YouTubeTranscriptApi
# youtube_transcript_api._errors 에서 TooManyRequests를 제외하고 임포트합니다.
# TooManyRequests는 더 이상 직접 임포트할 수 없는 것으로 보입니다.
from youtube_transcript_api._errors import NoTranscriptFound, TranscriptsDisabled, VideoUnavailable
def get_youtube_transcript(video_id, languages=['ko', 'en']):
"""
주어진 YouTube 동영상 ID와 언어 목록에 대해 자막을 가져옵니다.
자동 생성 자막과 공식 자막을 모두 시도합니다.
"""
try:
# 우선 공식 자막을 시도
transcript_list = YouTubeTranscriptApi.list_transcripts(video_id)
# 사용 가능한 언어 목록에서 요청한 언어 중 하나를 찾아 가져옵니다.
chosen_transcript = None
for lang_code in languages:
for transcript in transcript_list:
if transcript.language_code == lang_code:
chosen_transcript = transcript
break
if chosen_transcript:
break
if chosen_transcript:
print(f"[{video_id}] {chosen_transcript.language} ({chosen_transcript.language_code}) 자막을 가져옵니다.")
# fetch()는 이제 FetchedTranscript 객체를 반환하며, 이는 이터러블합니다.
transcript_segments = chosen_transcript.fetch()
return transcript_segments
else:
raise NoTranscriptFound(
f"No suitable official transcript found for video {video_id} in languages {languages}.",
video_id
)
except NoTranscriptFound:
print(f"[{video_id}] 공식 자막을 찾을 수 없습니다. 자동 생성 자막을 시도합니다.")
try:
for lang_code in languages:
try:
# get_transcript() 역시 이터러블한 객체를 반환하는 것으로 가정합니다.
transcript_segments = YouTubeTranscriptApi.get_transcript(video_id, languages=[lang_code], preserve_formatting=True)
print(f"[{video_id}] {lang_code} 자동 생성 자막을 가져왔습니다.")
return transcript_segments
except NoTranscriptFound:
continue # 다음 언어로 시도
print(f"[{video_id}] 요청된 언어 ({languages})로 자동 생성 자막도 찾을 수 없습니다.")
return None # 적합한 자막을 찾지 못함
except TranscriptsDisabled:
print(f"[{video_id}] 이 동영상은 자막이 비활성화되어 있습니다.")
return None
except VideoUnavailable:
print(f"[{video_id}] 동영상을 사용할 수 없거나 비공개/삭제되었습니다.")
return None
except Exception as e: # TooManyRequests를 포함한 모든 예외를 잡습니다.
# 이 부분에서 TooManyRequests 에러를 포함하여 일반적인 오류를 처리합니다.
print(f"[{video_id}] 자막을 가져오는 중 예기치 않은 오류가 발생했습니다: {e}")
return None
except TranscriptsDisabled:
print(f"[{video_id}] 이 동영상은 자막이 비활성화되어 있습니다.")
return None
except VideoUnavailable:
print(f"[{video_id}] 동영상을 사용할 수 없거나 비공개/삭제되었습니다.")
return None
except Exception as e: # TooManyRequests를 포함한 모든 예외를 잡습니다.
# 이 부분에서 TooManyRequests 에러를 포함하여 일반적인 오류를 처리합니다.
print(f"[{video_id}] 자막을 가져오는 중 예기치 않은 오류가 발생했습니다: {e}")
return None
if __name__ == "__main__":
# 예시 동영상 ID (실제 존재하는 동영상 ID로 변경해야 합니다)
# 제가 추천해 드렸던 URL에서 ID를 추출했습니다.
video_id_with_subtitle = "XyljmT8dGA4" # "모바일 유튜브 자동번역 한글자막 보는 방법"
video_id_auto_caption = "XyljmT8dGA4" # 짧은 영상 (자동 생성 자막 가능성)
#video_id_invalid = "invalid_video_id_123"
video_id_invalid = "XyljmT8dGA4"
print("--- 예제 1: 자막이 있는 동영상 ---")
transcript_data = get_youtube_transcript(video_id_with_subtitle, languages=['ko', 'en'])
if transcript_data:
# segment.start, segment.duration, segment.text와 같이 속성으로 접근합니다.
for i, segment in enumerate(transcript_data[:5]): # 슬라이싱은 여전히 가능해야 합니다.
print(f"[{segment.start:.2f}-{segment.start + segment.duration:.2f}] {segment.text}")
print(f"... (총 {len(list(transcript_data))}개 세그먼트)") # len()을 위해 list로 변환
# 전체 자막 텍스트만 추출하고 싶다면:
full_text = " ".join([segment.text for segment in transcript_data])
print("\n--- 전체 자막 텍스트 (예제 1) ---")
print(full_text[:500] + "...")
else:
print("자막을 가져오지 못했습니다.")
print("\n--- 예제 2: 자동 생성 자막을 시도할 수 있는 동영상 ---")
transcript_data_auto = get_youtube_transcript(video_id_auto_caption, languages=['en', 'ko'])
if transcript_data_auto:
for i, segment in enumerate(transcript_data_auto[:5]):
print(f"[{segment.start:.2f}-{segment.start + segment.duration:.2f}] {segment.text}")
print(f"... (총 {len(list(transcript_data_auto))}개 세그먼트)")
else:
print("자막을 가져오지 못했습니다.")
print("\n--- 예제 3: 존재하지 않는 동영상 ID ---")
transcript_data_invalid = get_youtube_transcript(video_id_invalid)
if transcript_data_invalid:
print("자막을 가져왔습니다.")
else:
print("자막을 가져오지 못했습니다.")
"이 기분을 잊지 말렴. 네가 태어난 건 정말 기적같은 일이란 걸 한시도 잊지 말거라. 그리고 네가 태어나서 온 세상이 기뻐하고 있다는 것도 꼭 기억해! 매일 살아 있음이 얼마나 놀라운 일인지, 모든 곳에 친척과 친구가 있음이 얼마나 놀라운 일인지, 네가 꼭 알기를 바란다. 인간, 동물, 식물, 돌도 다 우리의 친구란다. 이제 알겠니? 진정한 마법이 무엇인지?
- 디르크 그로서, 제니 아펠의《너는 절대 혼자가 아니야》중에서 -
* 친구 하나를 얻는 것도 마법 같은 일입니다. 하물며 한 생명이 탄생한다는 것은 그 자체만으로 마법입니다. 또 하나의 작은 우주가 태어난다는 뜻이니까요. 자연물도 같습니다. '꽃을 한 송이 꺾으면 지구가 전율한다'는 시구는 과장된 표현이 아닙니다. 한 알의 모래알에서 우주를 보고 영원을 읽어야 합니다. 모든 것은 친구처럼 더불어 살아가며, 더불어 기뻐합니다.
잊지 마렴, 네가 태어난 건 기적이야!
"이 기분을 잊지 말렴. 네가 태어난 건 정말 기적 같은 일이란 걸 한시도 잊지 말거라. 그리고 네가 태어나서 온 세상이 기뻐하고 있다는 것도 꼭 기억해!"
이 아름다운 문장은 디르크 그로서와 제니 아펠의 《너는 절대 혼자가 아니야》에 나오는 구절입니다. 우리는 이 세상에 태어난 순간부터 이미 기적 그 자체였습니다. 우리가 존재한다는 것만으로 온 세상이 기뻐하고 있다는 사실, 늘 기억해야 할 소중한 진실이죠.
살아있음의 놀라운 마법
매일 숨 쉬며 살아간다는 것, 그 자체로 얼마나 놀라운 일인가요? 우리 주변에 있는 가족, 친구들과 함께한다는 것은 또 얼마나 감사한 일인가요. 인간뿐만 아니라 동물, 식물, 심지어 길가의 돌멩이 하나까지도 모두 우리의 친구입니다. 이 모든 존재와 더불어 살아가는 것이 바로 진정한 마법이 아닐까요?
작고 사소한 것에서 우주를 보다
친구 한 명을 얻는 것조차 마법 같은 일인데, 한 생명이 탄생한다는 것은 그야말로 우주가 새로 생겨나는 것과 같습니다. 이렇듯 자연의 모든 것도 마찬가지입니다. **'꽃을 한 송이 꺾으면 지구가 전율한다'**는 시구는 결코 과장된 표현이 아닙니다.
우리는 한 알의 모래알에서 우주를 보고 영원을 읽을 수 있어야 합니다. 모든 존재는 서로 친구처럼 더불어 살아가며, 함께 기뻐하는 놀라운 연결고리를 가지고 있습니다. 작은 것 하나에서도 큰 의미를 발견하는 삶, 그것이 바로 우리가 누릴 수 있는 가장 큰 행복일 것입니다.