docs: 최소 구성으로 09:00 헤드라인 전달 설계 정리 (naver fetch-headlines)
This commit is contained in:
parent
dac6c973cb
commit
c34dc177fd
@ -1,58 +0,0 @@
|
||||
# 네이버 블로그 RSS 피드 내용 제한 문제
|
||||
|
||||
## 작성일: 2025-09-04
|
||||
## 상태: 🟡 해결방안 제시
|
||||
## 영향: 스타트업 뉴스 자동화 제한
|
||||
|
||||
## 문제
|
||||
- **대상 블로그**: 깡프로 스타트업 트렌드 연구소 (https://blog.naver.com/startupventure)
|
||||
- **RSS 피드**: https://rss.blog.naver.com/startupventure.xml
|
||||
- **증상**: 블로그 본문 20개 뉴스 중 RSS description에는 8개만 포함
|
||||
- **원인**: 네이버 RSS 피드의 description 필드 크기 제한
|
||||
|
||||
## 분석 결과
|
||||
```xml
|
||||
<description>
|
||||
<![CDATA[
|
||||
1. 8월 스타트업 투자, AI/딥테크/블록체인이 이끌었다 https://...
|
||||
2. 버티컬AI 투자 열풍, VC 픽은 리걸테크 https://...
|
||||
...
|
||||
7. 삼성전자부터 뉴로메카....... <!-- 여기서 잘림 -->
|
||||
]]>
|
||||
</description>
|
||||
```
|
||||
|
||||
## 네이버 블로그 파싱 제약
|
||||
1. **JavaScript 동적 렌더링**: 정적 HTML 파싱 불가
|
||||
2. **iframe 구조**: 실제 콘텐츠가 iframe 내부에 위치
|
||||
3. **스크래핑 방지**: User-Agent 체크, Rate limiting
|
||||
|
||||
## 해결 방안
|
||||
|
||||
### 1. Playwright 브라우저 자동화 (추천)
|
||||
- JavaScript 렌더링 완료 후 DOM 파싱
|
||||
- 전체 20개 뉴스 항목 추출 가능
|
||||
- 매일 자동 실행으로 슬랙 뉴스봇 구현
|
||||
|
||||
### 2. RSS + Playwright 하이브리드
|
||||
- RSS로 최신 포스트 URL 획득
|
||||
- Playwright로 해당 URL 방문하여 전체 내용 파싱
|
||||
|
||||
### 3. RSS만 활용 (제한적)
|
||||
- 8개 헤드라인만으로 운영
|
||||
- 중요 뉴스는 대부분 상단에 위치하므로 실용적
|
||||
|
||||
## 테스트 코드 필요
|
||||
Playwright를 사용한 네이버 블로그 파싱 가능성 검증 필요
|
||||
|
||||
## 관련 서비스
|
||||
- skill-news: 뉴스 수집 및 슬랙 전송 서비스
|
||||
- 로빙 슬랙봇: 뉴스 전달 담당
|
||||
|
||||
## 확인된 사실 (핵심)
|
||||
- 대상 RSS: https://rss.blog.naver.com/startupventure.xml (description 필드 크기 제한으로 약 8개 항목만 포함)
|
||||
- 서비스/서버: skill-news (51124, 192.168.219.52), 포트 8505
|
||||
- 헬스/파이프라인 엔드포인트: `GET /health`, `POST /api/news/search`, `POST /api/news/process/all`, `GET /api/news/latest`, `GET /api/news/status`
|
||||
- Chroma 볼륨 매핑(docker-compose): 호스트 `./data` ↔ 컨테이너 `/app/data`
|
||||
- 경로/파일(데이터 영속): 컨테이너 `/app/data/chroma` ↔ 호스트 `/home/admin/ivada_project/skill_news/data/chroma/chroma.sqlite3` (확인 시 ~651KB)
|
||||
- 주요 환경변수(기본값): `CHROMA_DB_PATH=/app/data/chroma`, `CHROMA_COLLECTION_NAME=news_articles`
|
||||
@ -0,0 +1,72 @@
|
||||
# 평일 09:00 Slack 뉴스 전달을 위한 네이버 RSS+Playwright 수집 설계
|
||||
|
||||
## 작성일: 2025-09-05
|
||||
## 상태: 해결방안 확정·구현 계획 수립
|
||||
|
||||
## 목표
|
||||
- 평일 09:00에 컴퍼니엑스 Slack 채널과 각자 DM으로 당일 스타트업 뉴스를 전송한다.
|
||||
- 소스는 네이버 블로그 ‘깡프로 스타트업 트렌드 연구소’의 당일 포스트다.
|
||||
|
||||
## 문제 요약
|
||||
- RSS: https://rss.blog.naver.com/startupventure.xml
|
||||
- RSS `description`이 약 8개 항목에서 절단되어 본문(20개+)이 누락된다.
|
||||
- 실제 본문은 블로그 페이지 내 `PostView.naver` iframe에 포함되어 정적 파싱으로는 불완전하다.
|
||||
|
||||
## 최소 구성(가장 단순)
|
||||
- 목적: 저장을 생략하고, 09:00에 “제목+링크 목록(Slack 텍스트/JSON)”만 생성해 상위가 전송.
|
||||
- 입력: ENV `NAVER_RSS_URL`(기본값), 요청 `date(YYYY-MM-DD)|today`, `format(json|slack)`.
|
||||
- 처리: RSS→당일 포스트 URL→Playwright로 `PostView.naver` iframe 렌더링→제목+원문 링크(+순서) 추출.
|
||||
- 출력: JSON `{success,count,items:[{title,url,position}]}` 또는 Slack 텍스트(`• <url|title>` 리스트).
|
||||
- 저장: 기본 비저장(가장 단순). 옵션 `STORE_MINIMAL=true` 시 Chroma에 최소 메타 저장(idempotent 보조).
|
||||
|
||||
## 확정된 사실(코드/실측)
|
||||
- skill-news 서비스 포트: 8505 (`/health`, `/api/news/...`).
|
||||
- Endpoints: `/api/news/search`, `/latest`, `/summarize`, `/status`, `/process/all`, `/search/similar`.
|
||||
- 데이터 영속: ChromaDB `CHROMA_DB_PATH=/app/data/chroma`, 컬렉션 `news_articles`.
|
||||
- Playwright 사용 가능(Chromium headless, iframe 내 본문 접근 검증 완료).
|
||||
|
||||
## 해결 전략(하이브리드)
|
||||
1) RSS로 당일 포스트 URL만 획득한다.
|
||||
2) 해당 포스트의 `PostView.naver` iframe을 Playwright로 렌더링하여 리스트형 항목의 제목과 기사 원문 링크를 모두 추출한다.
|
||||
3) 추출 항목을 중복 제거·정규화 후 최소 메타데이터로 ChromaDB에 저장(재실행 안전성 확보).
|
||||
4) Slack 포맷 텍스트( `<url|title>` 리스트 )와 JSON을 모두 제공한다.
|
||||
5) 상위 로빙/슬랙봇이 채널/DM 전송을 담당(HTTP API만으로 연동).
|
||||
|
||||
## API 설계(HTTP 전용)
|
||||
- `POST /api/news/naver/fetch-headlines` (최소 경로)
|
||||
- 요청: `{ "date": "YYYY-MM-DD", "source": "startupventure", "format": "json|slack" }`
|
||||
- 응답(JSON): `{ success, count, items: [{title, url}], message? }`
|
||||
- 응답(Slack): `text` 필드에 불릿 리스트 문자열 포함.
|
||||
- `GET /api/news/naver/latest`
|
||||
- 당일/최근 포스트 기준 재생성 없이 캐시된 결과 반환.
|
||||
|
||||
## 파싱 규칙(함수형·환경주입)
|
||||
- 입력: `rss_url`, `date`, `max_items`, `timeout`은 ENV → 요청값으로 오버라이드.
|
||||
- 출력: 순수 데이터(제목, URL) 리스트. 상태 저장은 호출자(데이터 매니저)가 수행.
|
||||
- 셀렉터 전략: 번호형 텍스트 패턴 탐지 + 앵커 태그의 절대 URL 보정.
|
||||
- 예외: 네트워크/구조 변경 시 빈 리스트와 원인 메시지 반환(부작용 없음).
|
||||
|
||||
## 스케줄링/흐름(평일 09:00)
|
||||
1) 스케줄러(Gitea Actions 혹은 상위 컨트롤러)가 09:00에 `POST /api/news/naver/fetch` 호출.
|
||||
2) 응답을 받아 채널용 메시지와 DM용 메시지를 구성(상위 로직).
|
||||
3) Slack 전송 성공/실패 로그를 상위에서 저장. skill-news는 수집·정규화에 집중.
|
||||
|
||||
## 운영 포인트
|
||||
- 재시도: 3회(지수 백오프), 실패 시 캐시 결과 반환.
|
||||
- 속도제한: 항목 간 `sleep(0.5~1.0s)`로 요청 간격 조절.
|
||||
- 중복: 제목+URL 해시로 식별, 이미 저장된 항목은 건너뜀.
|
||||
- 관찰성: `/api/news/status`에 수집/요약 카운터와 최신 시각 반영.
|
||||
|
||||
## 검증 시나리오(curl)
|
||||
- 수집: `curl -X POST http://localhost:8505/api/news/naver/fetch -H 'Content-Type: application/json' -d '{"date":"2025-09-05","source":"startupventure","format":"slack"}'`
|
||||
- 상태: `curl http://localhost:8505/api/news/status`
|
||||
|
||||
## 리스크 및 대응
|
||||
- 네이버 마크업 변경: 셀렉터 다중화, 본문 fallback(전체 body 텍스트) 적용.
|
||||
- 일시적 차단: User-Agent/Referer 설정과 백오프 재시도.
|
||||
- RSS 지연: 당일 포스트 미등재 시 전일 18시~당일 09시 범위 탐색 후 빈 결과 처리.
|
||||
|
||||
## 다음 단계
|
||||
- `naver/fetch` 엔드포인트 구현(함수형), 데이터 매니저에 아이템 최소 저장 로직 보강.
|
||||
- 슬랙 포맷 메시지 빌더 추가 또는 기존 `format=slack` 경로 재사용.
|
||||
- Gitea 스케줄 워크플로에 09:00 평일 트리거 추가(롤백·로그 포함).
|
||||
Loading…
x
Reference in New Issue
Block a user