# task-1193.1 — 인포키워드 작업리포트 캡쳐 정확성 개선

**팀**: dev3-team (다그다)
**일시**: 2026-03-28
**작업자**: 루(백엔드)

---

## SCQA

**S**: InfoKeyword 작업리포트의 스크린샷 캡쳐가 task-1013.1에서 블로그 URL 파라미터를 수정했으나, 카페 탭 URL 불일치 및 정보성 판단 대상 블로그 포스트 미캡쳐 문제가 운영 환경에서 지속됨.

**C**: 3가지 구조적 문제가 잔존: (1) 카페 URL 파라미터 불일치(`sm=tab_jum` vs `where=cafe`), (2) 정보성 체크에 사용되는 개별 블로그 포스트 스크린샷 누락, (3) 키워드 URL 인코딩 불일치. 이로 인해 리포트의 스크린샷이 실제 분석 대상과 다른 페이지를 보여줌.

**Q**: 크롤러가 실제 판단에 사용하는 URL과 동일한 페이지를 캡쳐하여 리포트 정확도를 보장할 수 있는가?

**A**: 3개 파일(screenshot.py, analyzer.py, report_generator.py)을 수정하여 해결. 카페 URL을 `where=cafe`로 정렬하고, 정보성 블로그 포스트 캡쳐를 추가하고, 키워드 URL 인코딩을 적용함. 페이지 로딩 대기를 셀렉터 기반으로 개선. 기존 18개 테스트 전체 통과.

---

## 수정 내용

### 1. screenshot.py — URL 정렬 + 인코딩 + 대기 전략 개선 (4건)

- **카페 URL 정렬**: `_NAVER_TAB_URLS["cafe"]`를 `ssc=tab.cafe.all&where=cafe&query={keyword}`로 변경하여 `cafe_search.py`의 `_CAFE_SEARCH_URL`과 일치
- **키워드 URL 인코딩**: `capture_naver_search`에서 `quote(keyword, safe="")`로 인코딩 적용 (크롤러와 동일 방식)
- **페이지 로딩 대기 개선**: 고정 2초 대기 → `wait_for_selector`(5초 타임아웃) + 1.5초 추가 대기로 변경 (네이버 SPA 렌더링 대응)
- **`capture_cafe_search()` 함수 추가**: 카페 크롤러가 사용한 동일 URL로 스크린샷 촬영하는 전용 함수

### 2. analyzer.py — 정보성 블로그 캡쳐 + 카페 순차 실행 (4건)

- **정보성 블로그 포스트 캡쳐 추가**: step5 분석 완료 후, 정보성(비홍보성+비광고+네이버블로그) 상위 1개 블로그 포스트를 `capture_blog_post()`로 캡쳐
- **카페 스크린샷 순차 실행**: `asyncio.gather` 병렬 → 순차 실행으로 변경. `_safe_capture_cafe_search()` 헬퍼가 `cafe_search.py`의 `_CAFE_SEARCH_URL`을 import하여 동일 URL 구성
- **스크린샷 매핑에 `step5_informational_blog` 추가**: GCS 업로드 대상에 정보성 블로그 스크린샷 포함
- **import 업데이트**: `capture_cafe_search` import 추가

### 3. report_generator.py — 정보성 블로그 스크린샷 표시 (1건)

- Step 5 카드에 `step5_informational_blog` 스크린샷 섹션 추가 (검색 결과 → 정보성 예시 → 홍보성 예시 순서)

---

## 발견 이슈 및 해결

### 자체 해결 (5건)

1. **카페 URL 파라미터 불일치** — `screenshot.py`의 카페 URL을 `where=cafe`로 변경하여 `cafe_search.py`와 일치시킴
   - 상세: screenshot.py:32 `sm=tab_jum` → `where=cafe`
2. **정보성 블로그 포스트 스크린샷 미캡쳐** — `analyzer.py`에서 step5 분석 후 정보성 블로그 상위 1개를 `capture_blog_post()`로 캡쳐하도록 추가
   - 상세: analyzer.py:395-402 info_blogs 필터링 + 캡쳐 로직 추가
3. **키워드 URL 인코딩 불일치** — `screenshot.py`의 `capture_naver_search`에서 `quote(keyword, safe="")`로 인코딩 적용
   - 상세: screenshot.py:112 `format(keyword=keyword)` → `format(keyword=quote(keyword, safe=""))`
4. **페이지 로딩 대기 전략 부족** — 고정 2초 대기를 셀렉터 기반 5초 대기 + 1.5초 여유로 변경
   - 상세: screenshot.py:83-90 `wait_for_selector` 추가
5. **카페 스크린샷과 크롤러 병렬 실행** — `asyncio.gather`를 순차 실행으로 변경하여 타이밍 차이 제거
   - 상세: analyzer.py:414-416 순차 실행으로 변경

### 범위 외 미해결 (0건)

---

## 셀프 QC 체크리스트

- [x] 1. 영향 파일: screenshot.py, analyzer.py, report_generator.py (3개 파일 상호 의존적 변경)
- [x] 2. 엣지 케이스: 정보성 블로그 0개 시 info_blogs 비어있어 캡쳐 스킵 (정상), 특수문자 키워드는 URL 인코딩 처리
- [x] 3. 작업 지시 일치: 블로그 정보성 URL 캡쳐 + 카페 대표뱃지 URL 정렬 모두 구현
- [x] 4. 에러 처리: try/except로 스크린샷 실패 시 None 반환, 분석 결과 미영향
- [x] 5. 테스트: 기존 18개 테스트 전체 통과 (test_blog_search 9건 + test_contract 9건)
- [x] 6. 발견 이슈 5건 모두 자체 해결 완료
- [x] 7. 코드 아키텍처 원칙 확인: SRP 준수 (capture_cafe_search 분리), DRY 위반 없음
- [x] 8. 인터페이스 변경: capture_cafe_search 함수 신규 추가, 기존 함수 시그니처 변경 없음

---

## 산출물 파일

- `/home/jay/projects/InfoKeyword/worker/reporter/screenshot.py`
- `/home/jay/projects/InfoKeyword/worker/pipeline/analyzer.py`
- `/home/jay/projects/InfoKeyword/worker/reporter/report_generator.py`
- `/home/jay/workspace/memory/reports/task-1193.1.md`

---

## QC 자동 검증

- **결과**: Gate PASS (5 PASS, 5 SKIP, 2 WARN)
- **file_check**: PASS — 3개 파일 존재 + 보고서 존재 확인
- **data_integrity**: PASS — task-timers.json 상태 일치
- **test_runner**: SKIP — 관련 테스트 파일 자동 추론 0개 (정당한 SKIP)
- **pyright_check**: WARN — 20건 모두 기존 `worker` 모듈 import 해결 실패 (reportMissingImports). 본 작업 도입 에러 0건.
- **style_check**: WARN → black+isort 적용 후 해소
- **critical_gap**: PASS
- **spec_compliance**: PASS
- **duplicate_check**: PASS (최대 유사도 13.2%)
- **.done 파일**: qc_verify.py --gate에 의해 자동 생성됨
