네이버 쇼핑 오픈API 어댑터(크롤링 불필요) + 핸들러를 다중 소스로 확장.
쿠팡(브라우저)+네이버(API)를 동시 검색·병합해 교차 최저가를 뽑는다.
- search/naver/adapter: httpx + 오픈API + 키 로테이션(429/403 순환), .env 키 로드
- search/naver/transform: 순수 변환(태그/엔티티 정리, lprice). 가격비교(catalog) lprice 는
'여러 판매자 중 최저가'라 최저가 솔루션엔 핵심 → 유지
- handler: asyncio.gather 동시 검색 + 소스별 실패 격리(일부 죽어도 결과) + 전체 실패 시 잡 실패
- worker_main: adapters={coupang, naver}
- tests: 네이버 변환 + 병합/실패격리/전체실패 4건 → 전체 31/31
- 라이브: 쿠팡30+네이버30 병합 top-N 최저가(소스 라벨 포함)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
20 lines
1.0 KiB
Python
20 lines
1.0 KiB
Python
"""네이버 응답 변환 테스트 (순수, 네트워크 불필요)."""
|
|
|
|
from services.search.naver.transform import transform_items
|
|
|
|
|
|
def test_transform_strips_tags_and_keeps_catalog():
|
|
items = [
|
|
{"title": "로지텍 <b>무선</b> 마우스 & 키보드", "link": "https://search.shopping.naver.com/catalog/1",
|
|
"image": "img1", "lprice": "13500", "mallName": "네이버", "maker": "로지텍", "productId": "1"},
|
|
{"title": "0원상품", "link": "https://x", "lprice": "0"}, # 가격 0 → 제외
|
|
{"title": "가격없음", "link": "https://y", "lprice": "abc"}, # 파싱 실패 → 제외
|
|
]
|
|
out = transform_items(items)
|
|
assert len(out) == 1
|
|
p = out[0]
|
|
assert p.name == "로지텍 무선 마우스 & 키보드" # <b> 제거 + 엔티티 복원
|
|
assert p.price == 13500 and p.source == "naver"
|
|
assert p.mall_name == "네이버" and p.manufacturer == "로지텍" and p.external_id == "1"
|
|
assert "catalog/1" in p.detail_url # 가격비교(catalog) 최저가 유지
|