SameOS ~/tools/price-tracker-api-lessons.md

쇼핑 검색 API로 가격 추적기 만들 때 배운 것들

작성일 2026-07-07 · SameOS Tools

쇼핑 검색 API(프로그램이 쇼핑 검색 결과를 데이터 형태로 받아 오는 창구)로 상품 가격을 매시간 수집해 시세판을 만드는 프로젝트를 운영하고 있습니다. API 문서만 보면 "검색해서 최저가를 저장하면 끝"처럼 보이지만, 실제로 돌려 보면 데이터 품질과의 싸움이 대부분입니다. 몇 주 운영하며 배운 것들을 정리합니다.

최저가순 정렬을 쓰면 안 되는 이유

가장 먼저 배운 것은 정렬 옵션입니다. 최저가순(asc)으로 검색하면 본품 대신 쿠폰, 액세서리, 구성품 같은 1천 원짜리 결과가 상위를 차지합니다. 정확도순(sim)으로 받은 뒤 프로그램 쪽에서 가격 범위를 걸러내는 편이 훨씬 안정적입니다. 기준가(품목마다 미리 정해 둔 대표 가격)의 40%~200% 밖은 버리는 단순한 규칙만으로도 액세서리 오염 대부분이 사라집니다.

상품명 검증도 필수입니다. "V15"를 검색하면 "V15s"가, "5070"을 검색하면 "5070 Ti"가 섞여 들어옵니다. 품목 이름에서 모델 번호를 뽑아 검색 결과 제목과 대조하고, 변형 접미사(Ti, PRO, 울트라 등)가 붙은 다른 모델은 제외하는 검증 층을 두니 혼입이 크게 줄었습니다.

품절 매물이 최저가를 오염시킨다

가장 교묘한 문제는 품절된 매물이었습니다. 일부 판매처는 품절 상품을 내리지 않아서, 실제로는 살 수 없는 가격이 카탈로그 최저가로 계속 표시됩니다. 저는 "최저가가 그다음 매물과 일정 비율 이상 동떨어진 외톨이면 의심하고, 여러 판매처가 지지하는 가격대로 교체"하는 규칙으로 대응했습니다. 여러 곳이 함께 내린 진짜 특가는 서로 지지하므로 살아남고, 혼자만 싼 유령 가격만 걸러집니다.

실전 예제 코드

// 1) 기준가 밴드: 액세서리·구성품 오염 제거
function in_band(int $price, int $base): bool {
    return $price >= (int)($base * 0.4)
        && $price <= (int)($base * 2.0);
}

// 2) 외톨이 최저가 감지: 품절 유령 가격 교체
//    최저가가 다음 매물과 8% 이상 벌어져 있으면
//    아무도 못 사는 가격일 가능성이 높다
function pick_trusted(array $prices): int {
    sort($prices);
    if (count($prices) >= 3 && $prices[1] > $prices[0] * 1.08) {
        return $prices[1];   // 여러 매장이 지지하는 가격
    }
    return $prices[0];
}

// 3) 모델 변형 혼입 차단 (예: 5070 vs 5070 Ti)
function is_variant(string $title, string $core): bool {
    $suffix = '(?:ti|super|ultra|pro|max|plus|lite|s)';
    return (bool)preg_match(
        '/' . preg_quote($core, '/') . '\s*' . $suffix . '(?![a-z])/iu',
        $title
    );
}

이 규칙들을 실제로 적용해 운영 중인 가격 시세판은 오늘의물가(sisemap.com)에서 볼 수 있습니다. 수집 주기 관리는 cron(정해 둔 시간마다 명령을 자동 실행해 주는 리눅스 스케줄러)으로 하고 있는데, 주기 설정에서 자주 하는 실수는 별도 글로 정리해 두었습니다.

GitHub에서 예제 코드 보기 · View example on GitHub →

오늘의물가 시세판 보기 cron 주기 설정 글 보기