feat: 제품 이미지 크롤링에 날짜 선택 기능 추가 - 달력으로 날짜 선택 가능 - 해당 날짜 판매 제품 크롤링

This commit is contained in:
thug0bin 2026-03-04 00:55:02 +09:00
parent 51216c582f
commit 30d95c8579
3 changed files with 62 additions and 21 deletions

View File

@ -5767,11 +5767,13 @@ def api_product_image_detail(barcode):
@app.route('/api/admin/product-images/crawl-today', methods=['POST'])
def api_crawl_today():
"""오늘 판매 제품 크롤링"""
"""특정 날짜 판매 제품 크롤링 (date 파라미터 없으면 오늘)"""
try:
from utils.yakkok_crawler import crawl_today_sales
result = crawl_today_sales(headless=True)
return jsonify({'success': True, 'result': result})
from utils.yakkok_crawler import crawl_sales_by_date
data = request.get_json() or {}
date_str = data.get('date') # YYYY-MM-DD 형식
result = crawl_sales_by_date(date_str, headless=True)
return jsonify({'success': True, 'result': result, 'date': date_str or 'today'})
except Exception as e:
logging.error(f"크롤링 오류: {e}")
return jsonify({'success': False, 'error': str(e)}), 500

View File

@ -325,8 +325,9 @@
<header>
<h1>🖼️ 제품 이미지 관리</h1>
<div class="actions">
<button class="btn btn-primary" onclick="crawlToday()">
🔄 오늘 판매 제품 크롤링
<input type="date" id="crawlDate" class="filter-select" style="padding: 8px 12px;">
<button class="btn btn-primary" onclick="crawlByDate()">
🔄 해당일 판매 제품 크롤링
</button>
<button class="btn btn-secondary" onclick="openManualCrawl()">
수동 크롤링
@ -453,6 +454,10 @@
// 초기 로드
document.addEventListener('DOMContentLoaded', () => {
// 오늘 날짜로 기본값 설정
const today = new Date().toISOString().split('T')[0];
document.getElementById('crawlDate').value = today;
loadStats();
loadImages();
});
@ -542,14 +547,25 @@
debounceTimer = setTimeout(loadImages, 300);
}
async function crawlToday() {
if (!confirm('오늘 판매된 제품 이미지를 크롤링합니다. 진행할까요?')) return;
async function crawlByDate() {
const dateInput = document.getElementById('crawlDate').value;
if (!dateInput) {
showToast('날짜를 선택하세요', 'error');
return;
}
showToast('크롤링 시작... 잠시 기다려주세요', 'info');
const dateStr = dateInput.replace(/-/g, '');
const displayDate = `${dateStr.slice(4,6)}/${dateStr.slice(6,8)}`;
if (!confirm(`${displayDate} 판매 제품 이미지를 크롤링합니다. 진행할까요?`)) return;
showToast(`${displayDate} 크롤링 시작... 잠시 기다려주세요`, 'info');
try {
const res = await fetch('/api/admin/product-images/crawl-today', {
method: 'POST'
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ date: dateInput })
});
const data = await res.json();

View File

@ -272,8 +272,12 @@ def crawl_products(products, headless=True):
return results
def get_today_sales_products():
"""오늘 판매된 제품 목록 조회 (MSSQL)"""
def get_sales_products(date_str=None):
"""특정 날짜 판매 제품 목록 조회 (MSSQL)
Args:
date_str: 날짜 문자열 (YYYYMMDD 또는 YYYY-MM-DD), None이면 오늘
"""
try:
# 상위 폴더의 db 모듈 import
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
@ -282,9 +286,14 @@ def get_today_sales_products():
session = db_manager.get_session('PM_PRES')
today = datetime.now().strftime('%Y%m%d')
# 날짜 처리
if date_str:
# YYYY-MM-DD -> YYYYMMDD 변환
target_date = date_str.replace('-', '')
else:
target_date = datetime.now().strftime('%Y%m%d')
# 오늘 판매된 품목 조회 (중복 제거)
# 해당 날짜 판매된 품목 조회 (중복 제거)
query = text("""
SELECT DISTINCT
COALESCE(NULLIF(G.Barcode, ''),
@ -294,11 +303,11 @@ def get_today_sales_products():
ISNULL(G.GoodsName, '알수없음') AS product_name
FROM SALE_SUB S
LEFT JOIN PM_DRUG.dbo.CD_GOODS G ON S.DrugCode = G.DrugCode
WHERE S.SL_NO_order LIKE :today_pattern
WHERE S.SL_NO_order LIKE :date_pattern
AND S.DrugCode IS NOT NULL
""")
result = session.execute(query, {'today_pattern': f'{today}%'}).fetchall()
result = session.execute(query, {'date_pattern': f'{target_date}%'}).fetchall()
products = []
for row in result:
@ -306,7 +315,7 @@ def get_today_sales_products():
if barcode: # 바코드 있는 것만
products.append((barcode, row[1], row[2]))
logger.info(f"[MSSQL] 오늘 판매 품목: {len(products)}")
logger.info(f"[MSSQL] {target_date} 판매 품목: {len(products)}")
return products
except Exception as e:
@ -314,15 +323,29 @@ def get_today_sales_products():
return []
def crawl_today_sales(headless=True):
"""오늘 판매된 제품 이미지 크롤링"""
products = get_today_sales_products()
def get_today_sales_products():
"""오늘 판매된 제품 목록 조회 (하위호환)"""
return get_sales_products(None)
def crawl_sales_by_date(date_str=None, headless=True):
"""특정 날짜 판매 제품 이미지 크롤링
Args:
date_str: 날짜 문자열 (YYYYMMDD 또는 YYYY-MM-DD), None이면 오늘
"""
products = get_sales_products(date_str)
if not products:
return {'total': 0, 'success': 0, 'failed': 0, 'skipped': 0, 'message': '오늘 판매 내역 없음'}
return {'total': 0, 'success': 0, 'failed': 0, 'skipped': 0, 'message': '해당일 판매 내역 없음'}
return crawl_products(products, headless=headless)
def crawl_today_sales(headless=True):
"""오늘 판매된 제품 이미지 크롤링 (하위호환)"""
return crawl_sales_by_date(None, headless=headless)
# CLI 실행
if __name__ == '__main__':
import argparse