이론은 끝났다. 이제 실제로 만든다.
전체 구조
수집 → 필터링 → 저장 → 알림 → 반복
이 5단계를 코드로 구현한다.
1단계: 기본 수집 코드
가격 모니터링 예시
const { chromium } = require('playwright');
async function checkPrice() {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://example.com/product/12345');
// 가격 추출
const price = await page.locator('.price').textContent();
const priceNumber = parseInt(price.replace(/[^0-9]/g, ''));
await browser.close();
return priceNumber;
}
핵심:
headless: true→ 화면 안 띄우고 백그라운드 실행.locator()→ 자동 대기 포함- 브라우저 닫기 필수
2단계: 필터링 로직
const TARGET_PRICE = 50000;
async function monitorPrice() {
const currentPrice = await checkPrice();
if (currentPrice < TARGET_PRICE) {
console.log(`🚨 가격 하락! ${currentPrice}원`);
sendAlert(currentPrice);
} else {
console.log(`현재 가격: ${currentPrice}원 (대기 중)`);
}
}
3단계: 데이터 저장
JSON 파일 저장
const fs = require('fs');
function saveData(price) {
const data = {
timestamp: new Date().toISOString(),
price: price,
};
// 기존 데이터 읽기
let history = [];
if (fs.existsSync('price_history.json')) {
history = JSON.parse(fs.readFileSync('price_history.json'));
}
// 새 데이터 추가
history.push(data);
// 저장
fs.writeFileSync('price_history.json', JSON.stringify(history, null, 2));
}
SQLite 저장 (추천)
const sqlite3 = require('sqlite3');
const db = new sqlite3.Database('prices.db');
// 테이블 생성
db.run(`
CREATE TABLE IF NOT EXISTS prices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_id TEXT,
price INTEGER,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
// 데이터 삽입
function saveToDb(productId, price) {
db.run(
'INSERT INTO prices (product_id, price) VALUES (?, ?)',
[productId, price]
);
}
4단계: 알림 전송
텔레그램 봇
const axios = require('axios');
const TELEGRAM_BOT_TOKEN = 'your_bot_token';
const CHAT_ID = 'your_chat_id';
async function sendTelegramAlert(message) {
const url = `https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`;
await axios.post(url, {
chat_id: CHAT_ID,
text: message,
parse_mode: 'Markdown'
});
}
// 사용
await sendTelegramAlert(`🚨 가격 하락!\n현재: ${price}원`);
이메일 (Gmail)
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'your_email@gmail.com',
pass: 'your_app_password'
}
});
async function sendEmail(price) {
await transporter.sendMail({
from: 'your_email@gmail.com',
to: 'customer@example.com',
subject: '🚨 목표 가격 도달!',
html: `<h2>현재 가격: ${price}원</h2><a href="구매링크">바로 구매하기</a>`
});
}
5단계: 스케줄링 (반복 실행)
Node.js 기본
setInterval(async () => {
await monitorPrice();
}, 1000 * 60 * 30); // 30분마다
node-cron (추천)
const cron = require('node-cron');
// 매일 오전 9시, 오후 3시, 오후 9시 실행
cron.schedule('0 9,15,21 * * *', async () => {
console.log('가격 체크 시작...');
await monitorPrice();
});
전체 통합 코드
const { chromium } = require('playwright');
const cron = require('node-cron');
const axios = require('axios');
const TARGET_PRICE = 50000;
const TELEGRAM_TOKEN = 'your_token';
const CHAT_ID = 'your_chat_id';
async function checkPrice() {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://example.com/product/12345');
const price = await page.locator('.price').textContent();
const priceNumber = parseInt(price.replace(/[^0-9]/g, ''));
await browser.close();
return priceNumber;
}
async function sendAlert(price) {
const url = `https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage`;
await axios.post(url, {
chat_id: CHAT_ID,
text: `🚨 가격 하락!\n현재: ${price.toLocaleString()}원\n\n👉 [구매하기](링크)`
});
}
async function monitor() {
try {
const price = await checkPrice();
console.log(`현재 가격: ${price}원`);
if (price < TARGET_PRICE) {
await sendAlert(price);
}
} catch (error) {
console.error('에러:', error);
}
}
// 매 30분마다 실행
cron.schedule('*/30 * * * *', monitor);
console.log('모니터링 시작...');
배포 방법
1) 로컬 서버 24시간 가동
# pm2 설치
npm install -g pm2
# 실행
pm2 start monitor.js --name price-monitor
# 재부팅 시 자동 실행
pm2 startup
pm2 save
2) 클라우드 (AWS EC2)
# EC2 인스턴스 생성 (Ubuntu)
# Node.js 설치
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
# Playwright 의존성 설치
npx playwright install-deps
# 코드 업로드 후 실행
pm2 start monitor.js
3) GitHub Actions (무료)
# .github/workflows/monitor.yml
name: Price Monitor
on:
schedule:
- cron: '0 */1 * * *' # 매시간
jobs:
monitor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm install
- run: npx playwright install chromium
- run: node monitor.js
장점: 무료, 설정 간단
단점: 최대 6시간마다만 가능
비용 구조
로컬 서버
- 전기세 정도
- 초기 투자 거의 없음
AWS EC2 (t2.micro)
- 프리티어: 1년 무료
- 이후: 소규모 운영 가능
GitHub Actions
- 퍼블릭 레포: 완전 무료
- 프라이빗: 월 2000분 무료
성능 최적화
1) 컨텍스트 재사용
// ❌ 매번 브라우저 새로 띄움
async function wrong() {
const browser = await chromium.launch();
// ... 작업
await browser.close();
}
// ✅ 브라우저 하나로 컨텍스트만 생성
const browser = await chromium.launch();
async function right() {
const context = await browser.newContext();
const page = await context.newPage();
// ... 작업
await context.close();
}
결과: 메모리 사용량 70% 감소
2) 병렬 처리
// 여러 상품 동시 체크
const products = ['12345', '67890', '11111'];
await Promise.all(
products.map(id => checkPrice(id))
);
에러 처리
async function safeMonitor() {
const MAX_RETRIES = 3;
for (let i = 0; i < MAX_RETRIES; i++) {
try {
return await monitor();
} catch (error) {
console.error(`시도 ${i + 1} 실패:`, error);
if (i === MAX_RETRIES - 1) {
// 마지막 시도도 실패 시 알림
await sendAlert('⚠️ 모니터링 시스템 오류 발생');
}
// 1분 대기 후 재시도
await new Promise(r => setTimeout(r, 60000));
}
}
}
틀린 방식 vs 맞는 방식
❌ 틀린 방식
- 매번 브라우저 새로 띄움
- 에러 처리 없음
- 수동으로 실행
- 로그 없음
✅ 맞는 방식
- 컨텍스트 재사용
- 3회 재시도 + 알림
- cron 자동 실행
- 모든 동작 로깅
파이프라인을 만들었으면, 이제 돌리기만 하면 된다.
실제로 운영하면서 발견한 노하우는 AI 사업 실험실에서 계속 업데이트할 예정이다.
'AI 자동화' 카테고리의 다른 글
| AI 드라마 제작 완전 가이드 - 무료로 시작해서 3분 영상 뽑는 법 (2026년 최신) (0) | 2026.04.21 |
|---|---|
| Playwright로 크롤링 수익 모델 만들기 (0) | 2026.04.20 |
| 개발자들이 “메타 하네스”를 고민하는 진짜 이유 (0) | 2026.04.04 |
| AI 사업은 하나로 수렴한다: Medvi부터 소상공인 AI까지 (0) | 2026.04.03 |
| AI 제품 만들기 전에 꼭 써야 하는 GPT (시간 낭비 줄이는 방법) (0) | 2026.03.31 |