이 Python API는 주어진 YouTube 동영상의 자막/대본을 추출할 수 있게 해줍니다. 자동 생성된 자막도 지원하며, Selenium 기반 솔루션과 달리 헤드리스 브라우저가 필요하지 않습니다! 또한 자막 번역 기능도 제공합니다.
이 프로젝트의 유지보수는 모든 기여자와 스폰서 덕분에 가능합니다. 이 프로젝트를 후원하고 아바타나 회사 로고를 아래에 표시하고 싶으시면 여기를 클릭하세요. 💖
이 모듈은 pip를 사용하여 설치하는 것을 권장합니다:
pip install youtube-transcript-api
이 모듈을 기존 애플리케이션에 통합하거나 CLI를 통해 사용할 수 있습니다.
주어진 동영상의 대본을 얻는 가장 쉬운 방법은 다음과 같이 실행하는 것입니다:
from youtube_transcript_api import YouTubeTranscriptApi
ytt_api = YouTubeTranscriptApi()
ytt_api.fetch(video_id)
참고: 기본적으로 이는 동영상의 영어 대본에 접근하려고 시도합니다. 동영상이 다른 언어로 되어 있거나 다른 언어의 대본을 가져오고 싶다면 아래 섹션을 참조하세요.
참고: 동영상 URL이 아닌 동영상 ID를 전달하세요. URL이
https://www.youtube.com/watch?v=12345
인 동영상의 ID는12345
입니다.
이렇게 하면 다음과 같은 FetchedTranscript
객체가 반환됩니다:
FetchedTranscript(
snippets=[
FetchedTranscriptSnippet(
text="Hey there",
start=0.0,
duration=1.54,
),
FetchedTranscriptSnippet(
text="how are you",
start=1.54,
duration=4.16,
),
# ...
],
video_id="12345",
language="English",
language_code="en",
is_generated=False,
)
이 객체는 List
의 대부분 인터페이스를 구현합니다:
ytt_api = YouTubeTranscriptApi()
fetched_transcript = ytt_api.fetch(video_id)
# is iterable
for snippet in fetched_transcript:
print(snippet.text)
# indexable
last_snippet = fetched_transcript[-1]
# provides a length
snippet_count = len(fetched_transcript)
원시 대본 데이터를 직접 처리하고 싶다면 fetched_transcript.to_raw_data()
를 호출할 수 있으며, 이는 다음과 같은 딕셔너리 리스트를 반환합니다:
[
{
'text': 'Hey there',
'start': 0.0,
'duration': 1.54
},
{
'text': 'how are you',
'start': 1.54
'duration': 4.16
},
# ...
]
원하는 언어로 대본을 가져오고 싶다면 languages
매개변수를 추가할 수 있습니다 (기본값은 영어입니다).
YouTubeTranscriptApi().fetch(video_id, languages=['de', 'en'])
이는 내림차순 우선순위의 언어 코드 리스트입니다. 이 예제에서는 먼저 독일어 대본('de'
)을 가져오려고 시도하고, 실패할 경우 영어 대본('en'
)을 가져옵니다. 사용 가능한 언어를 확인하려면 list()
를 참조하세요.
하나의 언어만 원하는 경우에도 languages
인수를 리스트 형식으로 제공해야 합니다.
YouTubeTranscriptApi().fetch(video_id, languages=['de'])
<i>
(기울임꼴) 및 <b>
(굵게)와 같은 HTML 형식 요소를 유지하고 싶다면 preserve_formatting=True
를 추가할 수 있습니다.
YouTubeTranscriptApi().fetch(video_ids, languages=['de', 'en'], preserve_formatting=True)
주어진 동영상에 대해 사용 가능한 모든 대본을 나열하려면 다음과 같이 호출할 수 있습니다:
ytt_api = YouTubeTranscriptApi()
transcript_list = ytt_api.list(video_id)
이는 반복 가능한 TranscriptList
객체를 반환하며, 특정 언어 및 유형으로 대본 목록을 필터링하는 메서드를 제공합니다:
transcript = transcript_list.find_transcript(['de', 'en'])
기본적으로 이 모듈은 요청된 언어로 수동 생성된 대본과 자동 생성된 대본이 모두 있는 경우 수동 생성된 대본을 선택합니다. TranscriptList
를 사용하면 특정 대본 유형을 검색하여 이 기본 동작을 우회할 수 있습니다:
# filter for manually created transcripts
transcript = transcript_list.find_manually_created_transcript(['de', 'en'])
# or automatically generated ones
transcript = transcript_list.find_generated_transcript(['de', 'en'])
find_generated_transcript
, find_manually_created_transcript
, find_transcript
메서드는 Transcript
객체를 반환합니다. 이 객체는 대본에 대한 메타데이터를 포함합니다:
print(
transcript.video_id,
transcript.language,
transcript.language_code,
# whether it has been manually created or generated by YouTube
transcript.is_generated,
# whether this transcript can be translated or not
transcript.is_translatable,
# a list of languages the transcript can be translated to
transcript.translation_languages,
)
그리고 실제 대본 데이터를 가져올 수 있는 메서드를 제공합니다:
transcript.fetch()
이는 YouTubeTranscriptApi().fetch()
와 마찬가지로 FetchedTranscript
객체를 반환합니다.
YouTube는 자막을 자동으로 번역하는 기능을 제공합니다. 이 모듈을 통해 이 기능에 접근할 수도 있습니다. 이를 위해 Transcript
객체는 translate()
메서드를 제공하며, 이는 새로운 번역된 Transcript
객체를 반환합니다:
transcript = transcript_list.find_transcript(['en'])
translated_transcript = transcript.translate('de')
print(translated_transcript.fetch())
from youtube_transcript_api import YouTubeTranscriptApi
ytt_api = YouTubeTranscriptApi()
# retrieve the available transcripts
transcript_list = ytt_api.list('video_id')
# iterate over all available transcripts
for transcript in transcript_list:
# the Transcript object provides metadata properties
print(
transcript.video_id,
transcript.language,
transcript.language_code,
# whether it has been manually created or generated by YouTube
transcript.is_generated,
# whether this transcript can be translated or not
transcript.is_translatable,
# a list of languages the transcript can be translated to
transcript.translation_languages,
)
# fetch the actual transcript data
print(transcript.fetch())
# translating the transcript will return another transcript object
print(transcript.translate('en').fetch())
# you can also directly filter for the language you are looking for, using the transcript list
transcript = transcript_list.find_transcript(['de', 'en'])
# or just filter for manually created transcripts
transcript = transcript_list.find_manually_created_transcript(['de', 'en'])
# or automatically generated ones
transcript = transcript_list.find_generated_transcript(['de', 'en'])
RequestBlocked
또는 IpBlocked
예외 처리)유감스럽게도 YouTube는 AWS, Google Cloud Platform, Azure 등과 같은 클라우드 제공업체에 속한 대부분의 IP를 차단하기 시작했으며, 이는 코드를 클라우드 솔루션에 배포할 때 ReuquestBlocked
또는 IpBlocked
예외가 발생할 가능성이 높다는 것을 의미합니다. 너무 많은 요청을 하는 경우 자체 호스팅 솔루션의 IP에도 동일한 문제가 발생할 수 있습니다. 프록시를 사용하여 이러한 IP 차단을 우회할 수 있습니다. 그러나 YouTube는 정적 프록시를 장기간 사용한 후 차단하므로, 회전하는 주거용 프록시를 사용하는 것이 가장 신뢰할 수 있는 옵션입니다.
회전하는 주거용 프록시를 제공하는 다양한 공급자가 있지만, 여러 제품을 테스트한 결과 Webshare가 가장 신뢰할 수 있는 것으로 확인되어 이 모듈에 통합하여 설정을 최대한 쉽게 만들었습니다.
Webshare 계정을 생성하고 작업량에 적합한 "Residential" 프록시 패키지를 구매한 후 ("Proxy Server" 또는 "Static Residential"을 구매하지 않도록 주의하세요!), Webshare Proxy Settings에서 "Proxy Username"과 "Proxy Password"를 확인하세요. 이 정보를 사용하여 다음과 같이 YouTubeTranscriptApi
를 초기화할 수 있습니다:
from youtube_transcript_api import YouTubeTranscriptApi
from youtube_transcript_api.proxies import WebshareProxyConfig
ytt_api = YouTubeTranscriptApi(
proxy_config=WebshareProxyConfig(
proxy_username="<proxy-username>",
proxy_password="<proxy-password>",
)
)
# all requests done by ytt_api will now be proxied through Webshare
ytt_api.fetch(video_id)
WebshareProxyConfig
를 사용하면 회전하는 주거용 프록시를 기본으로 사용하며 추가 구성이 필요하지 않습니다.
여기서는 추천 링크가 사용되었으며 이 링크를 통해 이루어진 모든 구매는 이 오픈 소스 프로젝트를 지원하게 되어 매우 감사합니다! 💖😊🙏💖
그러나 다른 공급자를 사용하거나 자신만의 솔루션을 구현하고 싶다면 다음 섹션에서 다루는 GenericProxyConfig
클래스를 사용하여 자체 프록시 솔루션을 통합할 수도 있습니다.
Webshare 대신 GenericProxyConfig
클래스를 사용하여 일반적인 HTTP/HTTPS/SOCKS 프록시를 설정할 수 있습니다:
from youtube_transcript_api import YouTubeTranscriptApi
from youtube_transcript_api.proxies import GenericProxyConfig
ytt_api = YouTubeTranscriptApi(
proxy_config=GenericProxyConfig(
http_url="http://user:[email protected]:port",
https_url="https://user:[email protected]:port",
)
)
# all requests done by ytt_api will now be proxied using the defined proxy URLs
ytt_api.fetch(video_id)
프록시를 사용한다고 해서 차단되지 않을 것이라는 보장은 없으며, YouTube는 언제든지 프록시의 IP를 차단할 수 있습니다! 따라서 신뢰성을 극대화하려면 프록시 주소 풀을 회전시키는 솔루션을 선택해야 합니다.
YouTubeTranscriptApi
객체를 초기화할 때 모든 HTTP(S) 요청에 사용될 requests.Session
이 생성됩니다. 이는 여러 요청을 검색할 때 쿠키를 캐시할 수 있게 해줍니다. 그러나 requests.Session
객체를 생성자에 전달하여 YouTubeTranscriptApi
의 다른 인스턴스 간에 쿠키를 수동으로 공유하거나 기본값을 덮어쓰거나 사용자 정의 헤더를 지정하거나 SSL 인증서를 지정할 수 있습니다.
from requests import Session
http_client = Session()
# set custom header
http_client.headers.update({"Accept-Encoding": "gzip, deflate"})
# set path to CA_BUNDLE file
http_client.verify = "/path/to/certfile"
ytt_api = YouTubeTranscriptApi(http_client=http_client)
ytt_api.fetch(video_id)
# share same Session between two instances of YouTubeTranscriptApi
ytt_api_2 = YouTubeTranscriptApi(http_client=http_client)
# now shares cookies with ytt_api
ytt_api_2.fetch(video_id)
일부 동영상은 연령 제한이 있어 이 모듈은 인증 없이는 해당 동영상에 접근할 수 없습니다. 불행히도 YouTube API의 최근 변경 사항으로 인해 쿠키 기반 인증의 현재 구현이 중단되어 이 기능은 현재 사용할 수 없습니다.
포매터는 전달한 대본에 대한 추가 처리 계층으로 사용됩니다. 목표는 FetchedTranscript
객체를 주어진 "형식"의 일관된 문자열로 변환하는 것입니다. 기본 텍스트(.txt
) 또는 JSON(.json
), WebVTT(.vtt
), SRT(.srt
), 쉼표로 구분된 형식(.csv
) 등과 같이 정의된 사양이 있는 형식까지 가능합니다.
formatters
서브모듈은 몇 가지 기본 포매터를 제공하며, 그대로 사용하거나 필요에 따라 확장할 수 있습니다:
다음은 formatters
모듈에서 가져오는 방법입니다.
# the base class to inherit from when creating your own formatter.
from youtube_transcript_api.formatters import Formatter
# some provided subclasses, each outputs a different string format.
from youtube_transcript_api.formatters import JSONFormatter
from youtube_transcript_api.formatters import TextFormatter
from youtube_transcript_api.formatters import WebVTTFormatter
from youtube_transcript_api.formatters import SRTFormatter
대본을 검색하여 JSON 파일로 저장하려는 경우 다음과 같이 할 수 있습니다:
# your_custom_script.py
from youtube_transcript_api import YouTubeTranscriptApi
from youtube_transcript_api.formatters import JSONFormatter
ytt_api = YouTubeTranscriptApi()
transcript = ytt_api.fetch(video_id)
formatter = JSONFormatter()
# .format_transcript(transcript) turns the transcript into a JSON string.
json_formatted = formatter.format_transcript(transcript)
# Now we can write it out to a file.
with open('your_filename.json', 'w', encoding='utf-8') as json_file:
json_file.write(json_formatted)
# Now should have a new JSON file that you can easily read back into Python.
추가 키워드 인수 전달
JSONFormatter는 json.dumps()
를 활용하므로 .format_transcript(transcript)
에 indent=2
와 같은 키워드 인수를 전달하여 파일 출력을 보기 좋게 만들 수 있습니다.
json_formatted = JSONFormatter().format_transcript(transcript, indent=2)
자신만의 포매터 클래스를 구현할 수 있습니다. Formatter
기본 클래스를 상속받고 format_transcript(self, transcript: FetchedTranscript, **kwargs) -> str
및 format_transcripts(self, transcripts: List[FetchedTranscript], **kwargs) -> str
메서드를 구현하기만 하면 됩니다. 이 메서드는 최종적으로 포매터 인스턴스에서 호출될 때 문자열을 반환해야 합니다.
class MyCustomFormatter(Formatter):
def format_transcript(self, transcript: FetchedTranscript, **kwargs) -> str:
# Do your custom work in here, but return a string.
return 'your processed output data as a string.'
def format_transcripts(self, transcripts: List[FetchedTranscript], **kwargs) -> str:
# Do your custom work in here to format a list of transcripts, but return a string.
return 'your processed output data as a string.'
동영상 ID를 매개변수로 사용하여 CLI 스크립트를 실행하면 결과가 명령줄에 출력됩니다:
youtube_transcript_api <first_video_id> <second_video_id> ...
CLI는 또한 선호하는 언어 목록을 제공할 수 있는 옵션을 제공합니다:
youtube_transcript_api <first_video_id> <second_video_id> ... --languages de en
자동 생성된 자막이나 수동 생성된 자막을 제외할지 여부를 지정할 수도 있습니다:
youtube_transcript_api <first_video_id> <second_video_id> ... --languages de en --exclude-generated
youtube_transcript_api <first_video_id> <second_video_id> ... --languages de en --exclude-manually-created
결과를 파일에 쓰거나 다른 애플리케이션으로 파이프하려면 다음 줄을 사용하여 결과를 json으로 출력할 수도 있습니다:
youtube_transcript_api <first_video_id> <second_video_id> ... --languages de en --format json > transcripts.json
CLI를 사용하여 대본을 번역하는 것도 가능합니다:
youtube_transcript_api <first_video_id> <second_video_id> ... --languages en --translate de
주어진 동영상에 대해 어떤 언어가 사용 가능한지 확실하지 않은 경우 다음을 호출하여 사용 가능한 모든 대본을 나열할 수 있습니다:
youtube_transcript_api --list-transcripts <first_video_id>
동영상 ID가 하이픈으로 시작하는 경우 CLI가 이를 인수 이름으로 오해하지 않도록 \
를 사용하여 하이픈을 마스킹해야 합니다. 예를 들어 ID가 -abc123
인 동영상의 대본을 가져오려면 다음과 같이 실행하세요:
youtube_transcript_api "\-abc123"
YouTube가 IP를 차단하여 ReqestBlocked
또는 IpBlocked
오류가 발생하는 경우 IP 차단 우회에서 설명한 대로 주거용 프록시를 사용하여 이를 우회할 수 있습니다. CLI를 통해 Webshare "Residential" 프록시를 사용하려면 Webshare 계정을 생성하고 작업량에 적합한 "Residential" 프록시 패키지를 구매해야 합니다 ("Proxy Server" 또는 "Static Residential"을 구매하지 않도록 주의하세요!). 그런 다음 Webshare Proxy Settings에서 찾을 수 있는 "Proxy Username"과 "Proxy Password"를 사용하여 다음 명령을 실행하세요:
youtube_transcript_api <first_video_id> <second_video_id> --webshare-proxy-username "username" --webshare-proxy-password "password"
다른 프록시 솔루션을 사용하려는 경우 다음 명령을 사용하여 일반 HTTP/HTTPS 프록시를 설정할 수 있습니다:
youtube_transcript_api <first_video_id> <second_video_id> --http-proxy http://user:pass@domain:port --https-proxy https://user:pass@domain:port
쿠키 인증에서 설명한 대로 CLI를 통해 쿠키를 사용하여 인증하려면 다음을 실행하세요:
youtube_transcript_api <first_video_id> <second_video_id> --cookies /path/to/your/cookies.txt
이 코드는 YouTube 웹 클라이언트에서 호출되는 YouTube API의 문서화되지 않은 부분을 사용합니다. 따라서 YouTube가 작동 방식을 변경하면 내일 작동이 중단될 수 있다는 보장이 없습니다. 그러나 그런 일이 발생하면 가능한 한 빨리 다시 작동하도록 최선을 다할 것입니다. 따라서 작동이 중단되면 알려주세요!
로컬에서 프로젝트를 설정하려면 다음을 실행하세요 (poetry 설치 필요):
poetry install --with test,dev
테스트, 커버리지, 린터 및 포매터를 실행하는 poe 작업이 있습니다 (빌드가 성공하려면 이 모든 것을 통과해야 합니다):
poe test
poe coverage
poe format
poe lint
코드가 빌드를 성공시키기 위해 필요한 모든 검사를 통과하는지 확인하고 싶다면 간단히 다음을 실행할 수 있습니다:
poe precommit
이 프로젝트가 개발 시간을 단축하여 기쁨을 준다면, 커피 한 잔을 사주거나 이 프로젝트의 스폰서가 되어 기쁨을 나눠주세요 :)