Python으로 YouTube 스크래핑하기: 실제로 통하는 4가지 방법

최종 업데이트: July 2, 2026
Python으로 YouTube 스크래핑하기: 실제로 통하는 4가지 방법

requests.get("https://www.youtube.com/...")로 페이지를 받아 BeautifulSoup으로 영상 제목을 찾아본 분이라면 결과를 이미 아실 거예요. 텅 빈 <div>만 잔뜩 나오고, 쓸 만한 데이터는 한 줄도 없죠.

YouTube를 처음 긁어보는 개발자가 거의 다 똑같이 막히는 지점이에요. YouTube는 싱글 페이지 애플리케이션(SPA)이라 콘텐츠 대부분을 브라우저 쪽 JavaScript로 그려내요. Python 스크립트가 받아 오는 HTML은 사실상 빈 껍데기예요. 진짜 제목과 조회수, 메타데이터는 페이지가 뜬 뒤 JS가 밀어 넣는 거대한 JSON 덩어리 ytInitialData 안에 들어 있어요.

그래서 soup.find("div", class_="ytd-video-renderer") 같은 멀쩡해 보이는 코드도 None만 돌려줘요. 원본 HTTP 응답에 그 요소가 없으니까요. 이 구조만 알면 나머지는 단순해요. 아래 4가지 방법은 수많은 시행착오와 GitHub 이슈를 파헤친 결과예요. 하나씩 짚으며 어떤 상황에 뭘 쓰는지 알려드리고, 마지막엔 환경 설정 없이 데이터만 빠르게 빼는 노코드 지름길도 넣었어요.

왜 굳이 Python으로 YouTube를 스크래핑할까?

YouTube는 그냥 동영상 사이트가 아니라 월간 활성 사용자 25억 8천만 명의 초대형 데이터 창고예요. 영상 50억 개 이상, 매분 500시간 넘게 올라오는 콘텐츠를 기업·연구자·크리에이터가 분석하고 싶어 하는 건 당연하죠.

걸림돌은 YouTube 내장 분석 도구가 내 채널 숫자만 보여준다는 점이에요. 경쟁사 업로드 주기, 우리 업계 트렌드 주제, 남의 영상에 달린 댓글 반응을 보려면 직접 긁는 수밖에 없어요.

현장에서 가장 많이 쓰는 시나리오는 이래요.

사용 사례필요한 사람포함 데이터
경쟁사 분석마케팅 팀, 콘텐츠 전략가조회수, 업로드 빈도, 참여율
리드 생성영업팀, B2B 아웃리치채널 연락처, 설명란의 비즈니스 이메일
시장 조사제품 관리자, 애널리스트트렌딩 주제, 댓글 기반 사용자 반응
콘텐츠 전략유튜버, 에이전시성과가 좋은 포맷, 최적의 제목/태그 패턴
SEO / 키워드 리서치SEO 전문가영상 제목, 태그, 설명, 랭킹 신호
브랜드 모니터링PR 팀, 브랜드 관리자영상 제목·댓글·설명에 등장한 브랜드 언급
학술 연구연구자, 데이터 과학자감성 분석을 위한 댓글 데이터셋 (2025년 한 연구에서는 4.5만 개의 YouTube 댓글로 BERT를 파인튜닝해 93.1% 정확도를 달성)

DJI, GoPro, Insta360를 비교한 경쟁 분석에선 DJI의 YouTube 도달이 3억 9천만 조회수로 두 경쟁사 합계를 넘었다는 결과가 나왔어요. YouTube Studio 안에서는 절대 안 보이는 종류의 인사이트죠.

requests + BeautifulSoup만으로는 왜 YouTube를 못 긁을까?

통하는 방법 전에, 흔한 시도가 왜 실패하는지부터요. 이론이 아니라 몇 시간짜리 삽질을 막아주는 핵심이에요.

겉보기엔 이렇게 하면 될 것 같죠.

import requests
from bs4 import BeautifulSoup

response = requests.get("https://www.youtube.com/@somechannel/videos")
soup = BeautifulSoup(response.text, "html.parser")
videos = soup.find_all("a", id="video-title-link")
print(len(videos))  # 0 — 항상

결과는 늘 0이에요. ScrapeOps의 디버깅 가이드도 “페이지가 동적으로 로드돼서 requests 라이브러리로는 처리되지 않는다”고 설명해요. Teclado의 입문 가이드는 더 직설적이에요. “requests와 BeautifulSoup만으로는 JavaScript를 실행할 수 없다.”

Scrapfly의 2026년 YouTube 분석이 그 원리를 잘 풀어놨어요. YouTube는 SPA라서 기본 HTTP 요청으로는 초기 HTML 껍데기만 오고 실제 콘텐츠는 아직 안 그려진 상태예요. 영상 데이터는 브라우저가 실행해 DOM에 넣는 JavaScript 객체 속에 숨어 있어요.

다행인 점도 있어요. YouTube는 필요한 데이터를 원본 HTML 안에 분명히 넣어 둬요. 단지 DOM 요소가 아니라 <script> 태그 속 두 JSON 블록에 들어 있을 뿐이에요.

  • ytInitialData — 페이지 구조, 영상 목록, 참여 지표, 댓글 continuation token
  • ytInitialPlayerResponse — 핵심 비디오 메타데이터(제목, 설명, 재생 시간, 포맷, 자막)

뽑아서 파싱하는 법만 알면 브라우저 없이 requests.get() 한 번으로 접근할 수 있어요. 바로 아래 1번 방법이 그 방식이에요.

Python으로 YouTube 스크래핑하는 4가지 방법: 한눈에 비교

각 방법을 파헤치기 전에 의사결정 표부터요. 프로젝트에 맞는 도구를 고를 기준으로 네 방법을 전부 테스트해 정리했어요.

기준requests + BS4 (ytInitialData)Selenium / Playwrightyt-dlpYouTube Data API노코드(Thunderbit)
설정 난이도낮음중간낮음중간(API 키 필요)없음
JS 렌더링 처리부분적(JSON 파싱)가능가능해당 없음(구조화 API)가능
속도빠름느림빠름빠름빠름(클라우드)
봇 탐지 위험중간높음낮음없음처리됨
쿼터 / 속도 제한없음(대신 IP 차단 가능)없음(대신 탐지 가능)없음하루 10,000 유닛크레딧 기반
댓글 추출어려움가능하지만 복잡내장내장페이지에 따라 다름
자막/트랜스크립트아니오복잡가능아니오아니오
가장 적합한 용도빠른 메타데이터검색 결과, 동적 페이지대량 메타데이터 + 댓글대규모 구조화 데이터비개발자, 빠른 내보내기

간단 요약: youtube-scraping-methods.webp

실제로 어떤 YouTube 데이터를 뽑을 수 있고, 어떤 방법이 가능한가?

처음 시작할 때 있었으면 했던 비교표예요. 한 방법으로 모든 필드를 커버하진 못해서, 이 글에서 네 방법을 다 다뤄요.

데이터 항목BS4 (ytInitialData)Selenium/Playwrightyt-dlpYouTube APIThunderbit
비디오 제목
조회수
좋아요 수⚠️ 불안정
댓글(텍스트)⚠️ 복잡⚠️
트랜스크립트/자막⚠️
태그⚠️
썸네일 URL
채널 구독자 수⚠️
업로드 날짜
비디오 길이
Shorts 전용 데이터⚠️⚠️⚠️

프로젝트에서 가장 중요한 행이 뭔지 보고 방법을 고르세요. 댓글과 자막이 핵심이면 yt-dlp가 답이에요. 구조화된 통계를 중간 규모로 가져오려면 API가 가장 낫고요. 2분 안에 데이터만 뽑고 싶다면 아래 Thunderbit 섹션을 보시면 돼요.

extracted-data-categories.webp

방법 1: requests + BeautifulSoup로 YouTube 스크래핑하기 (ytInitialData 파싱)

YouTube가 페이지 데이터를 원본 HTML 속 JSON에 통째로 넣어 둔다는 점을 그대로 이용하는 방법이에요. 브라우저는 필요 없고, 어디를 봐야 하는지만 알면 돼요.

  • 난이도: 초급
  • 소요 시간: 약 15분
  • 준비물: Python 3.10+, requests, beautifulsoup4

1단계: YouTube 페이지에 GET 요청 보내기

현실적인 User-Agent 헤더를 함께 넣어 요청하세요. 기본 python-requests/2.x 헤더는 바로 막히는 경우가 많아요. ScrapeOps의 헤더 가이드도 초보자가 가장 자주 밟는 함정이라고 콕 짚어요.

import requests

HEADERS = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/114.0.0.0 Safari/537.36",
    "Accept-Language": "en-US,en;q=0.9",
    "Cookie": "CONSENT=YES+cb",  # EU 동의 화면 우회
}

url = "https://www.youtube.com/@mkbhd/videos"
response = requests.get(url, headers=HEADERS)
print(response.status_code)  # 200이어야 함

CONSENT 쿠키가 핵심이에요. 이게 없으면 EU 지역 요청은 consent.youtube.com으로 리다이렉트되는데, 그쪽 HTML에는 ytInitialData가 아예 없어요.

2단계: HTML을 파싱하고 ytInitialData 스크립트 찾기

BeautifulSoup이나 정규식으로 var ytInitialData =가 들어간 <script> 태그를 찾아요.

import re
import json

# ytInitialData JSON 추출
match = re.search(
    r"var ytInitialData\s*=\s*({.*?});</script>",
    response.text,
    re.DOTALL
)
if match:
    data = json.loads(match.group(1))
    print("ytInitialData를 성공적으로 추출했습니다")
else:
    print("ytInitialData를 찾지 못했습니다 — 헤더/쿠키를 확인하세요")

흔한 실수는 끝 구분자로 };만 쓰는 비탐욕적 .*? 패턴이에요. JSON 안에는 닫는 중괄호가 계속 나오니까 캡처가 너무 일찍 잘려요. Scrapfly의 2026년 예제처럼 };</script>를 끝 지점으로 잡으세요. 그 블록 안에서 마지막 할당이라 정확히 맞아떨어져요.

3단계: JSON 구조를 따라가며 비디오 데이터 추출하기

JSON 중첩이 꽤 깊어요. YouTube가 구조를 살짝만 바꿔도 깨지는 하드코딩 경로 대신, 키를 재귀로 찾는 방식이 훨씬 안전해요. 이런 변경은 자주 일어나는데, yt-dlp 이슈 트래커에도 2023년 이후 포맷 변경 사례가 여러 번 올라와 있어요.

def search_dict(partial, search_key):
    stack = [partial]
    while stack:
        cur = stack.pop()
        if isinstance(cur, dict):
            for k, v in cur.items():
                if k == search_key:
                    yield v
                else:
                    stack.append(v)
        elif isinstance(cur, list):
            stack.extend(cur)

# 채널 페이지에서 비디오 정보 추출
videos = []
for vr in search_dict(data, "videoRenderer"):
    videos.append({
        "video_id": vr.get("videoId"),
        "title": vr["title"]["runs"][0]["text"],
        "views": vr.get("viewCountText", {}).get("simpleText", "N/A"),
        "published": vr.get("publishedTimeText", {}).get("simpleText", "N/A"),
    })

print(f"{len(videos)}개의 비디오를 찾았습니다")
for v in videos[:5]:
    print(f"  {v['title']} — {v['views']}")

이 재귀 방식은 scrapetube, yt-dlp, Scrapfly가 다 같은 결론으로 수렴한 방법이에요. YouTube가 JSON 구조를 자주 바꿔도 비교적 잘 버텨요.

4단계: 스크래핑한 데이터를 CSV 또는 Excel로 내보내기

import csv

with open("youtube_videos.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["video_id", "title", "views", "published"])
    writer.writeheader()
    writer.writerows(videos)

print("데이터를 youtube_videos.csv로 내보냈습니다")

이 방법은 언제 쓰고, 언제 피해야 할까?

추천 대상: 채널이나 영상 페이지 몇 개에서 메타데이터를 빠르게 뽑고 싶을 때, 가벼운 SEO 도구, 제목·조회수·업로드 날짜 정도만 필요한 단발성 분석.

한계: JSON 구조가 자주 바뀌어요. 실제 깨진 사례로는 좋아요 버튼 리팩터링(2023: toggleButtonRenderersegmentedLikeDislikeButtonViewModel), 설명란 리팩터링(2023: description.runs[]attributedDescription.content), 채널 Videos 탭 재설계(2022–2023: gridRendererrichGridRenderer)가 있어요. 데이터센터 IP는 보통 50~200회 요청이면 소프트 차단돼요. 댓글도 자막도 못 가져와요.

방법 2: Selenium 또는 Playwright로 YouTube 스크래핑하기

검색 결과를 스크롤하거나 탭을 누르거나 설명을 펼치는 등 페이지와 직접 부딪혀야 할 때는 브라우저 자동화가 정답이에요.

  • 난이도: 중급
  • 소요 시간: 약 30분
  • 준비물: Python 3.10+, Playwright (pip install playwright && playwright install) 또는 Selenium + ChromeDriver

새 프로젝트라면 Selenium보다 Playwright를 권해요. TestDino의 2026년 벤치마크 기준으로 Playwright는 작업당 약 1.85배 빠르고, 메모리는 약 2.1배 적게 쓰며, 병렬 처리 용량은 약 4배예요. Playwright는 Chrome DevTools Protocol 위에 WebSocket 연결을 계속 유지하고, Selenium은 HTTP 기반 WebDriver를 써서 명령마다 변환 계층이 하나 더 끼어들어요.

1단계: Playwright 설치하기

pip install playwright
playwright install chromium
from playwright.sync_api import sync_playwright

pw = sync_playwright().start()
browser = pw.chromium.launch(headless=False)  # 화면 표시 모드가 일부 탐지를 피하는 데 도움
context = browser.new_context()

# EU 동의 화면 우회를 위해 쿠키 미리 설정
context.add_cookies([{
    "name": "SOCS",
    "value": "CAISNQgDEitib3FfaWRlbnRpdHlmcm9udGVuZHVpc2VydmVyXzIwMjMwODI5LjA3X3AxGgJlbiACGgYIgJnPpwY",
    "domain": ".youtube.com",
    "path": "/",
}])

page = context.new_page()

2단계: YouTube 페이지로 이동하고 콘텐츠가 로드될 때까지 대기하기

page.goto("https://www.youtube.com/@mkbhd/videos")
page.wait_for_selector("a#video-title-link", timeout=15000)
print("페이지 로드 완료 — 비디오 요소가 보입니다")

검색 결과를 긁는다면 https://www.youtube.com/results?search_query=your+query를 쓰세요.

3단계: 무한 스크롤로 더 많은 비디오 로드하기

YouTube의 채널 페이지와 검색 결과는 무한 스크롤이에요. 아래는 Scrapfly의 스크롤 가이드를 바탕으로 정리한 표준 scrollHeight 루프예요.

prev_height = -1
max_scrolls = 20  # 꼭 제한하세요 — 1만 개 영상 채널은 끝없이 스크롤됩니다
scroll_count = 0

while scroll_count < max_scrolls:
    page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
    page.wait_for_timeout(1500)  # 새 콘텐츠 로딩 대기
    new_height = page.evaluate("document.body.scrollHeight")
    if new_height == prev_height:
        break  # 더 이상 새 콘텐츠 없음
    prev_height = new_height
    scroll_count += 1

print(f"{scroll_count}번 스크롤했습니다")

4단계: 렌더링된 페이지에서 비디오 데이터 추출하기

video_elements = page.query_selector_all("a#video-title-link")
videos = []

for el in video_elements:
    title = el.inner_text()
    href = el.get_attribute("href")
    video_id = href.split("v=")[-1] if href else None
    videos.append({"title": title, "video_id": video_id, "url": f"https://www.youtube.com{href}"})

print(f"{len(videos)}개의 비디오를 추출했습니다")

조회수와 업로드 날짜까지 얻으려면 형제 요소를 같이 가져와야 해요. Crawlee의 2025년 가이드id="video-title-link"가 모든 페이지에서 똑같이 쓰이는 게 아니고 YouTube가 페이지 변형을 여럿 제공한다고 경고해요. 더 튼튼한 대안은 a[href*="watch"]예요.

5단계: CSV 또는 Google Sheets로 내보내기

import csv

with open("youtube_playwright.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["title", "video_id", "url"])
    writer.writeheader()
    writer.writerows(videos)

browser.close()
pw.stop()

이 방법은 언제 쓰고, 언제 피해야 할까?

추천 대상: 검색 결과 스크래핑, 탭 클릭이나 설명 펼치기 같은 동적 요소 조작, 완전히 렌더링된 DOM이 필요한 작업.

한계: 느려요. 스크롤 후 추출하는 흐름이면 영상당 약 1.53초가 걸려요. 봇 탐지 위험도 높고요. 기본 Selenium은 navigator.webdriver === true를 노출하는데, JS 측 탐지 로직이 바로 잡아내요. 리소스도 많이 먹어요(브라우저 인스턴스 하나당 RAM 200500MB). 영상 100개면 yt-dlp보다 몇 분 더 걸릴 수 있어요.

방법 3: yt-dlp로 YouTube 스크래핑하기

yt-dlp는 YouTube 스크래핑의 만능 도구예요. youtube-dl의 커뮤니티 포크로 GitHub 스타 15만 7천 개 이상을 받았고, 야간 빌드와 함께 메타데이터, 댓글, 자막, 일괄 스크래핑까지 다 돼요. 브라우저도 API 키도 안 필요해요.

  • 난이도: 초급~중급
  • 소요 시간: 약 10분
  • 준비물: Python 3.10+, pip install yt-dlp

1단계: yt-dlp 설치하기

pip install yt-dlp

브라우저 드라이버도, API 키도, 설정 파일도 없어요.

2단계: 다운로드 없이 비디오 메타데이터 추출하기

import yt_dlp

opts = {
    "quiet": True,
    "skip_download": True,      # 영상 파일은 받지 않고 메타데이터만
    "no_warnings": True,
}

with yt_dlp.YoutubeDL(opts) as ydl:
    info = ydl.extract_info(
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        download=False
    )

print(f"제목: {info['title']}")
print(f"조회수: {info['view_count']:,}")
print(f"좋아요 수: {info.get('like_count', 'N/A')}")
print(f"길이: {info['duration']}초")
print(f"업로드 날짜: {info['upload_date']}")
print(f"채널: {info['channel']} ({info.get('channel_follower_count', 'N/A')}명 구독자)")
print(f"태그: {info.get('tags', [])[:5]}")

보통 extract_info 한 번이면 영상 상태에 따라 id, title, channel, channel_id, channel_follower_count, view_count, like_count, comment_count, upload_date, duration, tags, categories, description, thumbnails, is_live, availability, automatic_captions, subtitles, chapters, heatmap 등 80~120개 필드를 돌려줘요.

3단계: YouTube 영상의 댓글 추출하기

opts = {
    "quiet": True,
    "skip_download": True,
    "getcomments": True,
    "extractor_args": {
        "youtube": {
            "max_comments": ["200", "50", "50", "10"],  # 전체, 상위 댓글, 대댓글/개, 대댓글 총합
            "comment_sort": ["top"],
        }
    },
}

with yt_dlp.YoutubeDL(opts) as ydl:
    info = ydl.extract_info(
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        download=False
    )

comments = info.get("comments", [])
print(f"댓글 {len(comments)}개를 가져왔습니다")
for c in comments[:3]:
    print(f"  [{c.get('like_count', 0)} likes] {c['author']}: {c['text'][:80]}...")

댓글 추출은 느려요. yt-dlp 이슈 #3532에 따르면 댓글을 가져오는 속도는 약 30KB/s 수준이에요. 댓글 10만 개짜리 영상은 몇 시간이 걸릴 수 있어요. 이슈 #11849는 댓글을 다 읽기도 전에 포맷 URL이 약 6시간 만에 만료된 사례도 보여줘요. 큰 영상은 max_comments를 과감하게 제한하는 게 좋아요.

4단계: 트랜스크립트와 자막 추출하기

YouTube Data API도, BS4 파싱도 전체 트랜스크립트는 못 줘요. 이게 yt-dlp만의 강점이에요.

opts = {
    "quiet": True,
    "skip_download": True,
    "writesubtitles": True,
    "writeautomaticsub": True,
    "subtitleslangs": ["en", "en-orig"],
    "subtitlesformat": "json3",   # 기계 파싱에 적합: start/dur(ms) + text
    "outtmpl": "%(id)s.%(ext)s",
}

with yt_dlp.YoutubeDL(opts) as ydl:
    info = ydl.extract_info(
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        download=False
    )

# info 딕셔너리에서 자막 데이터 직접 접근
auto_captions = info.get("automatic_captions", {})
manual_subs = info.get("subtitles", {})
print(f"자동 자막 언어: {list(auto_captions.keys())[:10]}")
print(f"수동 자막 언어: {list(manual_subs.keys())}")

기계 파싱에는 json3 형식이 좋아요. 세그먼트마다 밀리초 단위 start/dur와 텍스트가 들어 있어요. 언어 코드는 BCP-47 형식(en, en-US, zh-Hans, ja, es)이에요.

5단계: 여러 영상 또는 전체 채널을 일괄 스크래핑하기

opts = {
    "quiet": True,
    "skip_download": True,
    "extract_flat": "in_playlist",  # 빠르게 — 비디오 ID와 제목만
    "sleep_interval": 2,
    "max_sleep_interval": 6,
}

with yt_dlp.YoutubeDL(opts) as ydl:
    info = ydl.extract_info(
        "https://www.youtube.com/@mkbhd/videos",
        download=False
    )

entries = info.get("entries", [])
print(f"채널에서 {len(entries)}개의 비디오를 찾았습니다")
for e in entries[:5]:
    print(f"  {e.get('title', 'N/A')} — {e.get('id')}")

채널 URL, 재생목록 URL, 심지어 검색 쿼리(ytsearch10:python scraping)도 넣을 수 있고, 페이징은 yt-dlp가 내부에서 알아서 처리해요.

이 방법은 언제 쓰고, 언제 피해야 할까?

추천 대상: 대량 메타데이터 추출, 댓글, 자막, 영상 다운로드, 채널 전체 스크래핑처럼 필드가 많이 필요한 작업.

한계: 검색 결과 페이지를 긁는 데는 최적이 아니에요(그건 Selenium/Playwright가 나아요). 2024~2026년의 봇 차단 경쟁 탓에 대규모 운영은 더 까다로워졌어요. YouTube가 일부 클라이언트에 BotGuard attestation과 PO Token을 거는 탓이죠. 운영 환경이라면 bgutil-ytdlp-pot-provider 플러그인을 깔고 --cookies-from-browser chrome을 쓰세요. 단, 테스트용 계정으로요. yt-dlp 팀은 실제 Google 계정 쿠키를 쓰면 계정이 막힐 수 있다고 경고해요.

방법 4: YouTube Data API로 YouTube 스크래핑하기

공식 YouTube Data API v3는 YouTube 데이터를 가장 안정적이고 구조화된 형태로 가져오는 길이에요. 응답은 깔끔한 JSON이고, 필드도 문서화돼 있고, 봇 탐지와 머리싸움할 일도 없어요. 다만 대부분의 튜토리얼이 슬쩍 넘어가는 함정이 하나 있어요. 바로 쿼터 제도예요.

  • 난이도: 중급
  • 소요 시간: 약 20분(API 키 설정 포함)
  • 준비물: Python 3.10+, Google Cloud 프로젝트, pip install google-api-python-client

1단계: YouTube Data API 키 받기

  1. Google Cloud Console로 이동
  2. 새 프로젝트 생성(또는 기존 프로젝트 선택)
  3. APIs & Services → Library로 가서 "YouTube Data API v3" 검색 후 Enable
  4. APIs & Services → CredentialsCreate Credentials → API Key
  5. 키를 복사해 아래 코드에서 사용

2단계: 첫 API 호출하기

from googleapiclient.discovery import build

API_KEY = "YOUR_API_KEY_HERE"
youtube = build("youtube", "v3", developerKey=API_KEY)

# 특정 비디오 상세 정보 가져오기
response = youtube.videos().list(
    part="snippet,statistics,contentDetails",
    id="dQw4w9WgXcQ"
).execute()

video = response["items"][0]
print(f"제목: {video['snippet']['title']}")
print(f"조회수: {video['statistics']['viewCount']}")
print(f"좋아요 수: {video['statistics'].get('likeCount', '숨김')}")
print(f"댓글 수: {video['statistics'].get('commentCount', '비활성화')}")
print(f"길이: {video['contentDetails']['duration']}")
print(f"태그: {video['snippet'].get('tags', [])[:5]}")

응답이 깔끔하고, 타입도 분명하고, 문서화도 잘 돼 있어요. JSON 구조를 파고들 필요가 없어요.

3단계: 비디오 상세 정보, 채널 정보, 댓글 추출하기

# 비디오 검색
search_response = youtube.search().list(
    part="snippet",
    q="python web scraping tutorial",
    type="video",
    maxResults=10,
    order="viewCount"
).execute()

for item in search_response["items"]:
    print(f"  {item['snippet']['title']} — {item['id']['videoId']}")

# 댓글 가져오기
comments_response = youtube.commentThreads().list(
    part="snippet",
    videoId="dQw4w9WgXcQ",
    maxResults=20,
    order="relevance"
).execute()

for item in comments_response["items"]:
    comment = item["snippet"]["topLevelComment"]["snippet"]
    print(f"  [{comment['likeCount']} likes] {comment['authorDisplayName']}: {comment['textDisplay'][:80]}")

YouTube API 쿼터의 현실: 아무도 잘 말해 주지 않는 부분

여기가 그냥 복붙 튜토리얼과 진짜 쓸 만한 가이드를 가르는 분기점이에요. 기본 할당량은 하루 10,000 쿼터 유닛이고, 미국 태평양 시간 자정에 초기화돼요. 호출별 비용은 이래요.

API 엔드포인트호출당 쿼터 비용호출당 최대 결과 수
search.list100 유닛50개 결과
videos.list1 유닛비디오 ID 50개(배치)
channels.list1 유닛채널 ID 50개
commentThreads.list1 유닛댓글 100개
captions.list50 유닛해당 없음

계산을 해볼게요. YouTube 검색 결과 1,000개를 긁고 싶다고 칩시다.

  • 검색 호출: 1,000개 ÷ 페이지당 50개 = 20회 호출 × 100 유닛 = 2,000 유닛(하루 예산의 20%가 증발)
  • 그 1,000개 비디오의 상세 정보: 1,000개 ID ÷ 배치당 50개 = 20회 호출 × 1 유닛 = 20 유닛(저렴해요. videos.list 배치가 핵심)
  • 그 1,000개 비디오의 댓글(페이지당 1회 가정): 1,000회 호출 × 1 유닛 = 1,000 유닛

합치면 비교적 소규모 작업인데도 약 3,020 유닛이에요. 그런데 영상마다 댓글이 깊게 달려 있으면(영상당 50페이지 이상) 남은 7,000 유닛도 순식간에 사라져요. 댓글 5만 개짜리 영상 하나가 약 500페이지 = 500 유닛이거든요. 이런 영상 20개만 긁어도 그날 예산은 끝이에요.

쿼터 증액 절차는 꽤 빡빡한 컴플라이언스 심사를 요구해요. 개인정보 처리방침 URL, 약관 URL, 앱 시연 영상, 쿼터 산정 근거까지 내야 해요. 커뮤니티 보고를 보면 Google의 초기 응답은 보통 3~5영업일이지만, 최종 승인까지는 몇 주에서 몇 달이 걸리고, 특히 "분석용으로 데이터가 더 필요하다"는 용도는 거절되는 일이 많아요.

API를 써야 할 때: 소~중간 규모, 구조화되고 믿을 만한 데이터가 필요할 때, 댓글과 채널 통계가 중요할 때, 쿼터 한도를 감수할 수 있을 때.

스크래핑이 더 나은 경우: 대규모 프로젝트(하루 1만 개 이상 영상), API가 안 주는 필드(전체 트랜스크립트 — captions.download는 OAuth와 영상 소유자 권한이 필요), 쿼리당 500개를 넘는 검색 결과가 필요할 때(API가 totalResults를 뭐라 하든 실제 한도는 고정).

노코드 지름길: Thunderbit로 YouTube 스크래핑하기(Python 불필요)

파이프라인에 Python이 꼭 필요하면 위 1~4번을 쓰세요. 하지만 2분 안에 데이터가 필요한 마케터나, 환경 설정 없이 빠르게 빼고 싶은 개발자라면 더 빠른 길이 있어요.

Thunderbit은 코드를 쓰는 게 과하다 싶을 때를 위한 AI 웹 스크래퍼 Chrome 확장 프로그램이에요. 브라우저에서 YouTube 페이지에 바로 작동해요.

Thunderbit로 YouTube를 스크래핑하는 3단계

1단계: Thunderbit Chrome 확장 프로그램을 설치하고 YouTube 채널 페이지, 검색 결과 페이지, 또는 비디오 페이지를 열어요.

2단계: Thunderbit 사이드바에서 **"AI Suggest Fields"**를 눌러요. AI가 페이지를 읽고 비디오 제목, 조회수, 업로드 날짜, 길이, 채널 이름, 썸네일 URL 같은 열을 제안해요. 필요하면 열을 추가, 삭제, 이름 변경할 수 있어요.

3단계: **"Scrape"**를 누른 뒤 Google Sheets, Excel, CSV, Airtable, Notion으로 내보내요. 깔끔한 표 형태로 바로 쓸 수 있어요.

YouTube 스크래핑용 Thunderbit 사용해 보기

이런 분들에게 적합해요

  • 코드를 안 쓰는 마케터지만 경쟁 채널 데이터가 필요한 분
  • 가상환경 설정이나 의존성 설치 없이 데이터를 빠르게 뽑고 싶은 개발자
  • 봇 차단에 막힌 모든 사람 — Thunderbit은 사용자의 로그인된 브라우저 세션 안에서 긁어서 쿠키와 PO 토큰을 그대로 써요. 서버 측 스크래퍼를 괴롭히는 차단 문제를 상당 부분 비껴갈 수 있어요
  • Thunderbit은 서브페이지 스크래핑도 되니까, 영상 페이지를 하나씩 방문해 좋아요 수, 설명, 태그 같은 정보로 표를 더 채울 수 있어요

Thunderbit이 YouTube를 어떻게 다루는지 더 보려면 Thunderbit YouTube Channel Scraper 템플릿Thunderbit YouTube 채널을 확인해 보세요.

Python으로 YouTube를 스크래핑할 때 차단을 피하는 팁

아래 팁은 위 4가지 Python 방법 전부에 통해요. YouTube의 봇 차단은 ScrapeOps 기준 난이도 6/10 수준이고, 핵심 신호는 IP 행동 분석, JS 실행 요구, 자주 바뀌는 HTML 구조예요.

모든 방법 공통:

  • User-Agent 문자열만이 아니라 헤더 세트 전체를 바꾸세요. Accept, Accept-Language, Sec-CH-UA 같은 client hints도 선언한 UA와 맞아야 해요. ScraperAPI의 2026 가이드에 최신 목록이 있어요.
  • 요청 사이에 2~8초 랜덤 지연을 넣으세요. 고정 간격은 그 자체가 탐지 신호예요.
  • 몇 페이지 이상이면 주거용 프록시를 쓰세요. AWS, GCP, Hetzner 같은 데이터센터 IP는 2025~2026년 YouTube 스크래핑에서 사실상 막혔다고 보면 돼요.
  • 세션과 IP를 함께 돌리세요. YouTube는 세션을 IP와 묶어 보고, 같은 세션 쿠키가 두 IP에서 나타나면 위험 신호로 봐요.

requests + BS4용: CONSENT=YES+cb 쿠키를 설정하세요. 없으면 EU 요청이 동의 페이지로 넘어가고 데이터가 안 나와요.

Selenium/Playwright용: Linux 서버에서는 --headless=new보다 xvfb를 써서 headful로 돌리세요. 요즘 headless Chrome도 정교한 탐지기에는 지문을 충분히 남겨요. 우회 기법 약 17개를 적용하는 playwright-stealth도 고려해 볼 만해요.

yt-dlp용: sleep_intervalmax_sleep_interval 옵션을 쓰세요. PO Token 생성용으로 bgutil-ytdlp-pot-provider 플러그인을 설치하고, --cookies-from-browser chrome은 테스트용 계정으로만 쓰세요.

API용: Google Cloud Console에서 쿼터 사용량을 보며 요청을 효율적으로 배치하세요. 비디오 ID 50개를 쉼표로 묶은 videos.list 한 번이면 1 유닛이에요.

Thunderbit용: 브라우저 세션 안에서 긁으니 봇 차단은 알아서 처리돼요. 사실상 수작업을 자동화하는 것과 같아요.

Python으로 YouTube를 스크래핑하는 것이 합법일까?

무엇을, 어떻게 긁는지, 그리고 그 데이터를 어디에 쓰는지에 따라 갈려요.

2024년에 법적 환경이 한 번 바뀌었어요. Meta Platforms v. Bright Data(N.D. Cal., 2024년 1월) 사건에서 Chen 판사는 Meta 약관이 로그인 상태의 스크래핑만 금지하고, 로그아웃 상태의 공개 데이터 스크래핑은 금지하지 않는다고 판시했어요. 이 판결 뒤로 공개 데이터 스크래핑은 "훨씬 덜 위험한" 것으로 받아들여지게 됐어요. 반대로 hiQ v. LinkedInhiQ에 대한 50만 달러 판결로 끝났고, 약관 위반, CFAA 위반(가짜 계정), 동산침해(trespass to chattels)까지 인정되며 영구 금지명령도 나왔어요.

YouTube 자체 이용약관도 분명해요. 사전 서면 허가가 있거나 관련 법이 허용하는 경우를 빼고는 "robots, botnets or scrapers 같은 자동화 수단으로 서비스에 접근해서는 안 된다"고 돼 있어요. 공식적으로 허용된 접근 방식은 YouTube Data API예요.

실무적으로는 이 정도만 지키면 돼요.

  • 공개적으로 보이는 데이터를 개인 연구나 비상업 분석 목적으로 긁는 건 대체로 위험이 낮아요
  • 가장 안전한 길은 API이에요. 명시적으로 허가된 방식이니까요
  • 비공개/로그인 전용 콘텐츠 스크래핑, 저작권 영상 재배포용 다운로드, 댓글 속 개인 데이터를 이용한 개인정보보호법 위반은 피하세요
  • YouTube 댓글에는 GDPR 제4조 1항 기준 개인정보가 들어 있을 수 있어요. EU 데이터 주체 정보를 다룰 땐 특히 조심해야 해요
  • 상업적 스크래핑 프로젝트라면 법률 자문을 받으세요

이 내용은 법률 자문이 아니에요. 이 분야는 변화가 빨라요. 2025~2026년에는 AI 기업이 학습 데이터로 YouTube를 긁은 일을 두고 창작자들이 DMCA §1201 소송을 제기하는 흐름도 생기고 있어요.

Python으로 YouTube를 스크래핑할 때 어떤 방법을 써야 할까?

의사결정 가이드는 이래요.

  • 몇 개 페이지에서 메타데이터만 빠르게 필요하다면? → 1번 방법(requests + BS4). 빠르고 가볍고, requestsbeautifulsoup4 외엔 거의 필요 없어요.
  • 검색 결과를 긁거나 동적 페이지와 상호작용해야 한다면? → 2번 방법(Selenium/Playwright). 완전한 브라우저 렌더링과 무한 스크롤을 지원하지만 느리고 탐지되기 쉬워요.
  • 대량 메타데이터, 댓글, 자막이 필요하다면? → 3번 방법(yt-dlp). 단일 도구 중 가장 다재다능해요. 15만 7천 개 이상 스타가 괜히 있는 게 아니죠.
  • 중간 규모에서 구조적이고 믿을 만한 데이터가 필요하다면? → 4번 방법(YouTube Data API). 공식적이고 깔끔하지만 하루 10,000 유닛 쿼터 한계가 있어요.
  • 코드 없이 2분 만에 데이터가 필요하다면?Thunderbit. 브라우저 기반, AI 기반, 클릭 몇 번으로 Google Sheets로 내보낼 수 있어요.

하나의 방법이 모든 시나리오를 다 풀어주진 않아요. 위의 비교표와 추출 가능한 데이터 항목 표를 북마크해 두세요. 다음 프로젝트에서 시간을 꽤 아껴 줄 거예요. 더 많은 웹 스크래핑 접근법이 궁금하면 Thunderbit 블로그에 Python 스크래핑 튜토리얼부터 Google Sheets로 데이터 스크래핑하기까지 다양한 가이드가 있어요.

YouTube 스크래핑용 Thunderbit 사용해 보기 Get Started Free

FAQ

API 키 없이 YouTube를 스크래핑할 수 있나요?

네. 1번 방법(requests + BS4), 2번 방법(Selenium/Playwright), 3번 방법(yt-dlp)은 API 키가 필요 없어요. 4번 방법(YouTube Data API)만 키가 필요해요. Thunderbit도 API 키 없이 브라우저에서 바로 긁을 수 있어요.

Python으로 YouTube를 가장 빠르게 스크래핑하는 방법은 무엇인가요?

Python 기준이면 yt-dlp와 requests + BS4가 가장 빨라요. 둘 다 브라우저 오버헤드가 없고, 영상당 몇 초면 메타데이터가 나와요. 특히 yt-dlp는 페이징을 내부에서 처리해 배치 작업에 아주 빠르고요. Python을 안 쓴다면 Thunderbit이 설정 시간 자체가 없어서 전체적으로 가장 빨라요.

Python으로 YouTube 댓글은 어떻게 스크래핑하나요?

yt-dlp가 getcomments 옵션으로 댓글 추출을 기본 지원해서 가장 간단해요. YouTube Data API도 commentThreads.list로 댓글을 가져올 수 있어요(호출당 1 유닛, 페이지당 최대 100개). Selenium/Playwright로도 스크롤해서 렌더링된 댓글 요소를 뽑을 순 있지만, 느리고 잘 깨져요.

Python으로 YouTube Shorts도 스크래핑할 수 있나요?

네. yt-dlp는 Shorts 메타데이터를 잘 다루고, 일반 영상에 Shorts 전용 필드를 더 붙여 처리해요. YouTube Data API도 부분 지원해요(Shorts 조회수 집계는 2025년 4월 30일에 바뀌어 이제 재생 시작/재생 반복도 조회수에 포함). BS4와 Selenium/Playwright는 Shorts shelf가 다른 DOM 구조를 써서 지원이 제한적이에요.

하루에 YouTube 영상을 몇 개까지 스크래핑할 수 있나요?

YouTube Data API는 하루 약 10,000 쿼터 유닛으로 제한돼요. 배치 videos.list 호출(한 번에 50개 ID, 1 유닛)을 쓰면 하루 최대 50만 건의 비디오 통계 조회가 가능하지만, search.list는 호출당 100유닛이라 예산을 금방 까먹어요. 스크래핑 방식(BS4, Selenium, yt-dlp)은 고정 상한보다 실무적 한계가 더 중요해요. 프록시 설정과 요청 패턴에 따라 IP 차단은 보통 IP당 하루 수백~수천 요청 뒤에 와요. Thunderbit은 플랜에 연동된 크레딧 시스템을 써요.

더 알아보기

Ke
Ke
Thunderbit CTO | 시니어 데이터 사이언티스트 & ML 전문가 머신러닝과 데이터 과학 분야에서 약 10년에 가까운 경험을 쌓아온 Ke Shen은 컬럼비아 대학교 출신이며, 전 Walmart Labs의 시니어 데이터 사이언티스트였습니다. Python, R, Java, 통계 분야에서 동료들에게도 인정받는 깊은 전문성을 바탕으로, 복잡한 AI 알고리즘을 이론에서 실제 운영 수준의 아키텍처로 전환하는 데 필요한 실전 인사이트를 공유합니다.
목차

말 한마디로 웹페이지를 스크래핑하세요

원하는 걸 평범한 영어로 말하면 됩니다. 아니면 아무 말도 안 해도 괜찮아요.

Thunderbit 사용해보기 무료
AI로 데이터 추출하기
Google Sheets, Airtable, Notion으로 데이터를 손쉽게 منتقل하세요
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week