fix(insta-lab): replace Google Trends with YouTube Data API (Google API 폐기 대응)

Google이 비공식 trends endpoint 두 가지(/trends/.../rss + /trends/api/dailytrends)
모두 404로 폐기 (NAS에서 직접 호출 시 확정). 대안으로 YouTube Data API v3
mostPopular(regionCode=KR, 50개)로 source 교체:

- source 이름: google_trends → youtube_trending
- 키워드: 영상 제목 정제 (대괄호·이모지 제거, 60자 limit)
- API 키: YOUTUBE_DATA_API_KEY (agent-office와 공유, .env 그대로 활용)
- 키 미설정 시 graceful skip
- docker-compose insta-lab에 환경변수 추가
- 테스트 9/9 pass (기존 6 + youtube 3 신규)
This commit is contained in:
2026-05-17 11:54:31 +09:00
parent cfbb72051f
commit 64fbbb7958
6 changed files with 99 additions and 83 deletions

View File

@@ -77,57 +77,60 @@ def test_classify_keyword_with_cache(monkeypatch):
assert calls["n"] == 1
def test_fetch_google_trends_parses_json_and_classifies(tmp_db, monkeypatch):
import json as _json
def test_fetch_youtube_trending_parses_and_cleans_titles(tmp_db, monkeypatch):
"""YouTube Data API mostPopular 응답 → 제목 정제 + 분류."""
monkeypatch.setattr(trend_collector, "YOUTUBE_DATA_API_KEY", "fake_key")
payload = {
"default": {
"trendingSearchesDays": [
{
"date": "20260517",
"trendingSearches": [
{"title": {"query": "기준금리"}},
{"title": {"query": "BTS 컴백"}},
{"title": {"query": "스트레스 관리"}},
# 다음 날 데이터에 중복 키워드 — 중복 제거 확인
{"title": {"query": "기준금리"}},
],
}
]
}
"items": [
{"snippet": {"title": "[속보] 기준금리 인상 단행 🔥"}},
{"snippet": {"title": "(공식) BTS 컴백 무대 🎤"}},
{"snippet": {"title": "스트레스 관리 5가지 방법"}},
# 중복 제목 — 중복 제거 확인
{"snippet": {"title": "[속보] 기준금리 인상 단행 🔥"}},
]
}
fake_resp = MagicMock()
# 실제 Google 응답 형태: `)]}',\n` XSSI prefix가 앞에 붙음
fake_resp.text = ")]}',\n" + _json.dumps(payload, ensure_ascii=False)
fake_resp.json.return_value = payload
fake_resp.raise_for_status.return_value = None
monkeypatch.setattr(trend_collector.requests, "get", lambda *a, **kw: fake_resp)
monkeypatch.setattr(trend_collector, "classify_keyword",
lambda kw: {"기준금리": "economy", "BTS 컴백": "celebrity",
"스트레스 관리": "psychology"}.get(kw, "uncategorized"))
monkeypatch.setattr(
trend_collector, "classify_keyword",
lambda kw: ("economy" if "금리" in kw else
"celebrity" if "BTS" in kw else
"psychology" if "스트레스" in kw else "uncategorized"),
)
trends = trend_collector.fetch_google_trends()
by_kw = {t["keyword"]: t for t in trends}
assert set(by_kw.keys()) == {"기준금리", "BTS 컴백", "스트레스 관리"} # 중복 제거
assert by_kw["기준금리"]["category"] == "economy"
assert by_kw["BTS 컴백"]["category"] == "celebrity"
assert by_kw["스트레스 관리"]["category"] == "psychology"
assert all(t["source"] == "google_trends" for t in trends)
trends = trend_collector.fetch_youtube_trending()
keywords = [t["keyword"] for t in trends]
assert "기준금리 인상 단행" in keywords # 대괄호·이모지 제거
assert "BTS 컴백 무대" in keywords # 괄호 제거
assert "스트레스 관리 5가지 방법" in keywords # 그대로
assert len(trends) == 3 # 중복 제거됨
assert all(t["source"] == "youtube_trending" for t in trends)
def test_fetch_youtube_trending_no_api_key_returns_empty(monkeypatch):
monkeypatch.setattr(trend_collector, "YOUTUBE_DATA_API_KEY", "")
out = trend_collector.fetch_youtube_trending()
assert out == []
def test_fetch_youtube_trending_graceful_on_api_failure(monkeypatch):
monkeypatch.setattr(trend_collector, "YOUTUBE_DATA_API_KEY", "fake_key")
fake_resp = MagicMock()
fake_resp.raise_for_status.side_effect = RuntimeError("quota exceeded")
monkeypatch.setattr(trend_collector.requests, "get", lambda *a, **kw: fake_resp)
out = trend_collector.fetch_youtube_trending()
assert out == []
def test_collect_all_invokes_both_sources(tmp_db, monkeypatch):
monkeypatch.setattr(trend_collector, "collect_naver_popular_for",
lambda cats: 5)
monkeypatch.setattr(trend_collector, "collect_google_trends",
monkeypatch.setattr(trend_collector, "collect_youtube_trending",
lambda: 3)
out = trend_collector.collect_all(["economy"])
assert out == {"naver_popular": 5, "google_trends": 3}
def test_fetch_google_trends_graceful_on_api_failure(monkeypatch):
fake_resp = MagicMock()
fake_resp.raise_for_status.side_effect = RuntimeError("Google returned 404")
monkeypatch.setattr(trend_collector.requests, "get", lambda *a, **kw: fake_resp)
out = trend_collector.fetch_google_trends()
assert out == []
assert out == {"naver_popular": 5, "youtube_trending": 3}
def test_seeds_for_filters_placeholder(tmp_db, monkeypatch):