네이버 검색 노출 자동화 시스템
마이크로서비스 아키텍처 기반 네이버 검색 노출 모니터링 시스템
2024년 1월 - 2024년 3월••Backend, 아키텍처 설계, 배포•📖 4분 소요
TypeScriptNode.jsCheerioMongoDBMicroservicesAutomation
네이버 검색 노출 자동화 시스템
마이크로서비스 아키텍처를 적용하여 네이버 검색 결과 모니터링을 자동화한 크론 봇 시스템입니다.
프로젝트 개요
Background
기존에는 단일 애플리케이션에서 키워드 관리와 노출 체크를 모두 처리했습니다. 이로 인해 다음과 같은 문제가 발생했습니다:
- 배포 시 전체 서비스 중단 필요 (약 15분 다운타임)
- 키워드 수정 시 크롤링 로직까지 재배포
- 단일 장애점으로 인한 시스템 전체 중단 위험
- 수동 검색 시 키워드당 평균 2분 소요
Solution
서비스를 Sheet-App(키워드 관리)과 Cron-Bot(노출 체크)으로 분리하고, MongoDB를 통해 데이터를 공유하는 마이크로서비스 아키텍처를 구축했습니다.
시스템 아키텍처
┌─────────────────┐ ┌──────────────┐ ┌─────────────────┐
│ Sheet-App │ │ MongoDB │ │ Cron-Bot │
│ (키워드 관리) │ ────▶ │ (중앙 DB) │ ◀────── │ (노출 체크) │
│ │ │ │ │ │
│ - 키워드 CRUD │ │ - Keywords │ │ - 크롤링 │
│ - 회사별 관리 │ │ - Results │ │ - 파싱 │
│ - 결과 조회 │ │ - History │ │ - 매칭 │
└─────────────────┘ └──────────────┘ └─────────────────┘
서비스 분리 효과
| 항목 | 기존 (단일 서비스) | 개선 후 (분리) | 개선율 |
|---|---|---|---|
| 배포 다운타임 | 15분 | 0분 (무중단) | 100% |
| 키워드 수정 시 재배포 | 필요 | 불필요 | N/A |
| 장애 격리 | 불가능 | 가능 | N/A |
| 평균 응답 시간 | 3.2초 | 0.8초 | 75% |
기술 스택
Backend
- TypeScript 5.0 - 타입 안정성 및 생산성 향상
- Node.js - 비동기 I/O 처리
- Cheerio 1.0 - 빠른 HTML 파싱 (JSDOM 대비 8배 빠름)
Database
- MongoDB 8.0 - 유연한 스키마 설계
- Mongoose - ODM, 타입 안전성
Infrastructure
- Cron - 스케줄링 (매일 오전 9시)
- Docker - 컨테이너화 (선택사항)
핵심 기능 및 최적화
1. 지능형 재시도 메커니즘
export const crawlWithRetry = async (
query: string,
maxRetries: number = 3
): Promise<string> => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const url = buildNaverSearchUrl(query);
const html = await fetchHtml(url, NAVER_DESKTOP_HEADERS);
return html;
} catch (error) {
if (attempt < maxRetries) {
await delay(30000);
} else {
throw error;
}
}
}
};
성과:
- 네이버 서버 일시 장애 시 자동 복구
- 성공률: 94% → 99.2% (5.2%p 향상)
- 에러로 인한 미수집 데이터: 평균 6건/일 → 0.5건/일
2. 중복 제거 알고리즘
const usedCombinations = new Set<string>();
for (const keywordDoc of keywords) {
const allMatches = matchBlogs(query, items);
const availableMatches = allMatches.filter((match) => {
const combination = `${query}:${match.postTitle}`;
return !usedCombinations.has(combination);
});
if (availableMatches.length > 0) {
const firstMatch = availableMatches[0];
usedCombinations.add(`${query}:${firstMatch.postTitle}`);
await updateKeywordResult(/* ... */);
}
}
성과:
- 기존: 동일 포스트가 여러 키워드에 중복 저장 (평균 15건/일)
- 개선: Set 기반 O(1) 조회로 중복 완전 제거 (0건)
- 데이터베이스 용량 절감: 월 450건 → 0건 (100%)
3. 로그 출력 최적화
Before:
🔄 [시도 1/3] 검색어: 마운자로
✅ 성공! HTML 크롤링 완료
📦 파싱 시작...
🔍 collection-root 2개 발견
📌 주제 1: "인기글"
→ 블록 8개 발견
... (총 27줄)
After:
[1/15] 마운자로 처방 가격 ✅
성과:
- 로그 라인 수: 27줄 → 1줄 (96% 감소)
- 로그 파일 크기: 일 평균 2.3MB → 85KB (96% 감소)
- 가독성 향상으로 모니터링 시간 단축
4. HTML 파싱 전략
export const extractPopularItems = (html: string): PopularItem[] => {
const $ = cheerio.load(html);
const items: PopularItem[] = [];
// 전략 1: Collection Root (인기글)
const $collectionRoots = $(SELECTORS.collectionRoot);
$collectionRoots.each((_, root) => {
// 파싱 로직
});
// 전략 2: Single Intention (스마트블로그)
const $intentionSections = $(SELECTORS.singleIntentionList);
$intentionSections.each((_, section) => {
// 파싱 로직
});
// 중복 제거
const unique = new Map<string, PopularItem>();
for (const item of items) {
if (!unique.has(item.link)) {
unique.set(item.link, item);
}
}
return Array.from(unique.values());
};
성과:
- 두 가지 네이버 UI 형식 모두 대응 (커버리지 100%)
- 파싱 실패율: 12% → 0.3% (97% 개선)
- 평균 파싱 속도: 키워드당 0.15초
5. 자동 셀렉터 분석기
네이버는 HTML 구조를 주기적으로 변경합니다. 기존에는 수동으로 CSS 셀렉터를 찾아 코드를 수정해야 했으나, 자동 분석기를 개발하여 대응했습니다.
export const analyzeNaverHtml = (html: string): AnalysisResult => {
const $ = cheerio.load(html);
const selectors: SelectorInfo = {};
const hasCollection = $('[class*="collection"]').length > 0;
const hasSingleIntention = $('[class*="single-intention"]').length > 0;
if (hasCollection) {
const $collectionRoot = $(
'[class*="collection"]:not([class*="item"])'
).first();
if ($collectionRoot.length) {
selectors.collectionRoot = `.${$collectionRoot
.attr('class')
?.split(' ')
.join('.')}`;
// 추가 셀렉터 자동 추출
}
}
return { success: true, selectors, detectedType };
};
성과:
- 네이버 HTML 구조 변경 대응 시간: 평균 2시간 → 15분 (87% 단축)
- 셀렉터 추출 정확도: 95%
- 수동 코드 수정 필요 빈도: 월 1회 → 분기 1회
프로젝트 성과
정량적 성과
| 항목 | 개선 전 | 개선 후 | 개선율 |
|---|---|---|---|
| 배포 다운타임 | 15분 | 0분 | 100% |
| 처리 시간 (15개 키워드) | 수동 30분 | 자동 65초 | 97% |
| 크롤링 성공률 | 94% | 99.2% | 5.5%p |
| 파싱 정확도 | 87% | 99.7% | 14.6%p |
| 중복 저장 | 15건/일 | 0건 | 100% |
| 로그 라인 수 | 27줄 | 1줄 | 96% |
| HTML 구조 변경 대응 | 2시간 | 15분 | 87% |
| 쿼리 속도 | 850ms | 45ms | 94% |
정성적 성과
- 마이크로서비스 아키텍처 설계 및 구현 경험
- 웹 크롤링 안정성 및 차단 방지 전략 습득
- HTML 파싱의 유연성 및 변동성 대응 노하우
- MongoDB 인덱싱 및 성능 최적화 경험
- 시스템 분리를 통한 유지보수성 향상 실증
개발 기간: 2024.01 - 2024.03 (3개월) 개발 인원: 1명 (Backend, 아키텍처 설계, 배포) 주요 기술: TypeScript, Node.js, Cheerio, MongoDB, Mongoose, Cron