# YouTube 트랜스크립트 추출 가이드 ## 아키텍처 ``` ┌──────────────────────────────────────────────────┐ │ 사용자 Chrome 브라우저 │ │ (VNC에서 직접 YouTube 로그인된 상태) │ │ --remote-debugging-port=9222 │ │ --remote-allow-origins=* │ └──────────────┬───────────────────────────────────┘ │ CDP (Chrome DevTools Protocol) ┌──────────────▼───────────────────────────────────┐ │ PlaywrightBrowserService │ │ playwright.chromium().connectOverCDP() │ │ → 사용자 Chrome의 세션/쿠키를 그대로 사용 │ └──────────────┬───────────────────────────────────┘ │ ┌──────────────▼───────────────────────────────────┐ │ YouTubeTranscriptService │ │ 1차: youtube-transcript-api 라이브러리 │ │ 2차: Playwright → 사용자 Chrome 탭으로 추출 │ └──────────────────────────────────────────────────┘ ``` ## 핵심: 왜 사용자 Chrome인가? ### Playwright 자체 브라우저의 한계 - Playwright가 실행하는 Chromium에는 `--enable-automation` 플래그가 붙음 - YouTube가 이를 감지하여 **봇으로 판정** → 자막 API 차단 - 쿠키를 로드해도, 직접 로그인을 시도해도 차단됨 - Google 로그인 자체가 "안전하지 않은 브라우저"로 거부됨 ### 사용자 Chrome + CDP 방식 - VNC에서 일반 Chrome으로 YouTube에 로그인 - 백엔드가 CDP로 해당 Chrome에 연결하여 새 탭을 열어 작업 - **로그인 세션이 그대로 유지**되므로 봇 판정 우회 - Chrome 자체는 종료하지 않고 연결만 관리 ## Chrome 실행 방법 ### 필수 옵션 ```bash DISPLAY=:1 google-chrome \ --remote-debugging-port=9222 \ --remote-allow-origins=* \ --user-data-dir=/tmp/chrome-debug-profile \ --no-default-browser-check \ "https://www.youtube.com" ``` | 옵션 | 설명 | |------|------| | `--remote-debugging-port=9222` | CDP 접속 포트 | | `--remote-allow-origins=*` | CDP WebSocket 연결 허용 | | `--user-data-dir` | 프로필 디렉토리 (기본과 다른 경로 필요) | ### Chrome 프로필 복사 (기존 로그인 유지) ```bash cp -r /home/opc/.config/google-chrome /tmp/chrome-debug-profile ``` ### CDP 연결 확인 ```bash curl -s http://localhost:9222/json/version | python3 -m json.tool ``` ## YouTube 로그인 1. VNC로 접속 (`vnc://공인IP:5901`) 2. Chrome에서 YouTube가 열려있는지 확인 3. YouTube에 Google 계정으로 로그인 4. 로그인 상태 유지 — Chrome을 닫지 않음 > Chrome을 닫으면 CDP 연결이 끊기고 백엔드가 재연결을 시도함. > Chrome을 다시 시작하면 다시 로그인 필요. ## 트랜스크립트 추출 흐름 ### 1차: youtube-transcript-api 라이브러리 ``` videoId → TranscriptApi.listTranscripts() → 수동 자막(ko, en) 우선 → 자동 생성 자막 fallback ``` - 서버 IP가 봇으로 판정되면 실패 (대부분 실패) ### 2차: Playwright + 사용자 Chrome ``` 1. 사용자 Chrome에 새 탭 열기 (DOMCONTENTLOADED, 60초 타임아웃) 2. DOM 렌더링 대기 (3초) 3. 동영상 재생 시작 (playVideo) - 쿠키 동의 팝업 닫기 - 마우스 호버 → 재생 버튼 클릭 4. 광고 대기 (waitForAdsToFinish, 최대 60초) - 스킵 버튼 자동 클릭 - 광고 끝날 때까지 반복 확인 5. 실제 영상 재생 확인 (waitForVideoPlaying, 최대 15초) - video.currentTime > 0.5 확인 - 일시정지면 재시도 6. ytInitialPlayerResponse에서 자막 URL 추출 + fetch (fetchTranscriptFromPageJs) 7. 실패 시 자막 패널 열기 (extractTranscriptFromPanel) - 'Show transcript' 버튼 클릭 - 자막 세그먼트 DOM에서 텍스트 추출 - 최대 30초 반복 확인 8. 완료 후 about:blank로 이동 (탭 유지) ``` ## 광고 처리 ### 감지 방법 - `#movie_player.ad-showing` 클래스 확인 (가장 신뢰할 수 있음) - `.ytp-ad-player-overlay` 오버레이 확인 - 광고 텍스트 배지 확인 (`.ytp-ad-text`) ### 스킵 버튼 셀렉터 ```css .ytp-skip-ad-button, .ytp-ad-skip-button, .ytp-ad-skip-button-modern, .ytp-ad-skip-button-container button ``` ### 주의사항 - 광고 스킵 후 두 번째 광고가 나올 수 있음 → `no_ad` 상태 확인까지 반복 - 광고 중에는 `NETWORKIDLE`에 도달하지 못함 → `DOMCONTENTLOADED` 사용 ## 쿠키 관리 ### CDP 방식에서는 쿠키 파일 불필요 - 사용자 Chrome에 직접 연결하므로 `cookies.txt` 불필요 - Chrome 세션의 쿠키가 자동으로 사용됨 ### Chrome 쿠키 수동 export (참고용) Chrome을 `--remote-debugging-port=9222`로 실행 후: ```python import json, websocket, urllib.request tabs = json.loads(urllib.request.urlopen("http://localhost:9222/json").read()) ws_url = tabs[0]["webSocketDebuggerUrl"] ws = websocket.create_connection(ws_url) ws.send(json.dumps({"id": 1, "method": "Network.getAllCookies"})) result = json.loads(ws.recv()) cookies = result["result"]["cookies"] ws.close() ``` > Chrome의 쿠키 DB(`~/.config/google-chrome/Default/Cookies`)는 암호화되어 있어 직접 읽기 어려움. > CDP를 통해 복호화된 쿠키를 가져오는 것이 가장 확실한 방법. ## PM2 + Chrome 자동 시작 Chrome이 서버 재부팅 시에도 자동 시작되도록: ```bash # pm2로 Chrome 관리하지 않음 (GUI 앱이라 적합하지 않음) # 대신 VNC 시작 시 자동 실행하도록 ~/.vnc/xstartup에 추가: ``` `~/.vnc/xstartup`: ```bash #!/bin/bash exec startxfce4 & # Chrome을 CDP 모드로 자동 시작 sleep 5 google-chrome --remote-debugging-port=9222 \ --remote-allow-origins=* \ --user-data-dir=/tmp/chrome-debug-profile \ --no-default-browser-check \ "https://www.youtube.com" & ``` ## 트러블슈팅 ### Chrome CDP 연결 실패 ``` Chrome CDP 연결 실패: Chrome이 --remote-debugging-port=9222로 실행 중인지 확인하세요. ``` → Chrome 재시작: ```bash DISPLAY=:1 google-chrome --remote-debugging-port=9222 --remote-allow-origins=* \ --user-data-dir=/tmp/chrome-debug-profile --no-default-browser-check "https://www.youtube.com" & ``` ### 자막 패널이 ghost-cards만 표시 - YouTube가 자막 데이터 로드를 차단한 상태 - Chrome에서 YouTube 로그인이 풀렸는지 VNC에서 확인 - 로그인 상태라면 Chrome 재시작 후 다시 로그인 ### "안전하지 않은 브라우저" 로그인 거부 - Playwright 자체 브라우저에서 발생 (정상) - **사용자 Chrome**에서만 로그인 가능 - CDP 방식으로 전환하면 해결 ### 광고 중에 페이지가 닫힘 - YouTube 페이지 로드 시 `NETWORKIDLE` 사용하면 광고 때문에 타임아웃 - **`DOMCONTENTLOADED`** + 60초 타임아웃으로 변경하여 해결 ## 관련 파일 | 파일 | 역할 | |------|------| | `PlaywrightBrowserService.java` | 사용자 Chrome에 CDP 연결, 탭 관리 | | `YouTubeTranscriptService.java` | 자막 추출 로직 (API → Playwright fallback) | | `youtube-transcript-extract.js` | 자막 패널 DOM 추출 JS | | `youtube-transcript-from-page.js` | ytInitialPlayerResponse 기반 자막 추출 JS | | `~/.vnc/xstartup` | VNC 시작 시 Chrome 자동 실행 |