11 Commits

Author SHA1 Message Date
72a12ac29f requirements.txt 추가 및 lib.py > common.py 수정과 리팩토링 2025-07-14 13:14:38 +09:00
e396c08f6b 실행파일 2025-07-11 11:06:06 +09:00
e58fa0bd57 잘못된 경로, 잘못된 변수 이름 수정 2025-07-11 11:05:56 +09:00
3b73517cfa 파일명 주석 추가 2025-07-11 09:31:01 +09:00
f760723067 | 항목 | 개선 전 | 개선 후 |
| ----------- | ---------------------- | ------------------------- |
| 예외 처리       | `except:`              | `except Exception:` 으로 제한 |
| 디버깅 출력      | `print()` 섞여 있음        | `debug()` 함수로 통일          |
| 메시지 전송      | 반복적 `MessageSender()`  | 공통화                       |
| 중복 제거       | `작성자/작성일/내용` key 반복 비교 | 튜플 키 비교 유지, 주석 보완         |
| 리뷰 추출 실패 로그 | 단순 출력                  | `place_id` 정보 포함          |
| 메시지 포맷      | biz와 형식 동일             | 동일한 스타일 유지                |
2025-07-11 09:30:49 +09:00
bbb17ef362 재귀 제거 run() 내부 재호출 제거, 루프 재시도 구조로 개선
except 범위 명확화 except: → except Exception:
리뷰 날짜 파싱 안전화 strptime 사용 시 예외 대비
중복 로직 함수화 작성일 추출, 본문 추출 등 함수로 분리
디버그 로그 함수 추가 debug() 함수로 로깅 통일
메시지 전송 실패시 명확한 알림 실패 시에도 로그 + 전송 시도
2025-07-11 09:27:48 +09:00
c3488e7bc9 파일명 주석 추가 2025-07-11 09:26:40 +09:00
698e0736fc 환경 변수 로딩을 config.py 에서 처리하도록 수정. 2025-07-11 09:26:19 +09:00
66bf05e11d 일부 줄 통합 및 가독성 강화 2025-07-11 09:26:03 +09:00
77d209d6fc KST가 정확하게 반영되지 않는 부분 수정. 2025-07-11 09:25:33 +09:00
27fcea070a Update README.md 2025-07-10 15:16:11 +09:00
10 changed files with 212 additions and 137 deletions

View File

@ -16,7 +16,7 @@ NAVER_PW=Login_Password
# 메시지 전송 플랫폼 선택 # 메시지 전송 플랫폼 선택
# mattermost, synology_chat, telegram 중 선택(콤마로 구분) 또는 빈 값(발송 안함) # mattermost, synology_chat, telegram 중 선택(콤마로 구분) 또는 빈 값(발송 안함)
MESSAGE_PLATFORM=mattermost,telegram MESSAGE_PLATFORMS=mattermost,telegram
# Mattermost 설정 # Mattermost 설정
# MATTERMOST_URL은 마지막에 '/' 없이 입력 # MATTERMOST_URL은 마지막에 '/' 없이 입력
@ -27,7 +27,7 @@ MATTERMOST_CHANNEL_ID=CHANNEL_ID
MATTERMOST_BOT_TOKEN=BOT_TOKEN MATTERMOST_BOT_TOKEN=BOT_TOKEN
# Synology Chat Webhook URL (사용 시 설정) # Synology Chat Webhook URL (사용 시 설정)
SYNology_CHAT_WEBHOOK_URL=https://synology.chat/webhook/your_webhook_url Synology_CHAT_WEBHOOK_URL=https://synology.chat/webhook/your_webhook_url
# Telegram 설정 (사용 시 설정) # Telegram 설정 (사용 시 설정)
TELEGRAM_BOT_TOKEN=your_bot_token TELEGRAM_BOT_TOKEN=your_bot_token

View File

@ -1,7 +1,7 @@
# 네이버 리뷰 크롤러 # 네이버 리뷰 크롤러
- 네이버 비즈니스, 네이버 map 기준 리뷰를 크롤링해 메시지를 보내줌 - 네이버 비즈니스, 네이버 map 기준 리뷰를 크롤링해 메시지를 보내줌
# 폴더 구조 # 폴더 구조
``` bash ```bash
/ /
├── .env_sample # 환경변수 샘플 파일 (.env_sample) ├── .env_sample # 환경변수 샘플 파일 (.env_sample)
├── .gitignore # Git 무시 파일 목록 ├── .gitignore # Git 무시 파일 목록
@ -19,3 +19,15 @@
``` ```
# 빌드(Windows 11 기준)
```bash
pyinstaller --onefile `
--add-data ".env;.env" `
--add-data "conf;conf" `
--add-data "lib;lib" `
--add-data "data;data" `
run.py
```
- 환경 변수를 포함하여 빌드하므로 `.env` 파일을 사전에 생성해 두어야 함
- 동작 확인을 위해 `--noconsloe` 옵션 제거

View File

@ -1,4 +1,25 @@
import os import os
import sys
import time
from dotenv import load_dotenv
# 프로젝트 루트 기준으로 .env 위치 지정
BASE_DIR = getattr(sys, '_MEIPASS', os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
ENV_PATH = os.path.join(BASE_DIR, '.env')
load_dotenv(dotenv_path=ENV_PATH)
# ✅ 타임존 설정
TZ = os.getenv("TZ", "Asia/Seoul")
os.environ["TZ"] = TZ
try:
time.tzset()
except AttributeError:
pass
try:
time.tzset()
except AttributeError:
pass
def parse_bool(value): def parse_bool(value):
if isinstance(value, bool): if isinstance(value, bool):
@ -17,14 +38,14 @@ MAX_REVIEWS = int(os.getenv("MAX_REVIEWS", "100"))
NAVER_ID = os.getenv("NAVER_ID", "") NAVER_ID = os.getenv("NAVER_ID", "")
NAVER_PW = os.getenv("NAVER_PW", "") NAVER_PW = os.getenv("NAVER_PW", "")
MESSAGE_PLATFORMS = parse_list(os.getenv("MESSAGE_PLATFORM", "")) MESSAGE_PLATFORMS = parse_list(os.getenv("MESSAGE_PLATFORMS", ""))
MATTERMOST_URL = os.getenv("MATTERMOST_URL", "") MATTERMOST_URL = os.getenv("MATTERMOST_URL", "")
MATTERMOST_WEBHOOK_URL = os.getenv("MATTERMOST_WEBHOOK_URL", "") MATTERMOST_WEBHOOK_URL = os.getenv("MATTERMOST_WEBHOOK_URL", "")
MATTERMOST_CHANNEL_ID = os.getenv("MATTERMOST_CHANNEL_ID", "") MATTERMOST_CHANNEL_ID = os.getenv("MATTERMOST_CHANNEL_ID", "")
MATTERMOST_BOT_TOKEN = os.getenv("MATTERMOST_BOT_TOKEN", "") MATTERMOST_BOT_TOKEN = os.getenv("MATTERMOST_BOT_TOKEN", "")
SYNology_CHAT_WEBHOOK_URL = os.getenv("SYNology_CHAT_WEBHOOK_URL", "") Synology_CHAT_WEBHOOK_URL = os.getenv("Synology_CHAT_WEBHOOK_URL", "")
TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN", "") TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN", "")
TELEGRAM_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID", "") TELEGRAM_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID", "")

View File

@ -1,3 +1,4 @@
# biz_crawler.py
import os, sys import os, sys
import time import time
from datetime import datetime from datetime import datetime
@ -13,7 +14,7 @@ from conf.config import (
MESSAGE_PLATFORMS, MATTERMOST_URL, MATTERMOST_BOT_TOKEN, MATTERMOST_CHANNEL_ID MESSAGE_PLATFORMS, MATTERMOST_URL, MATTERMOST_BOT_TOKEN, MATTERMOST_CHANNEL_ID
) )
from lib.send_message import MessageSender from lib.send_message import MessageSender
from lib.lib import ( from lib.common import (
create_mobile_driver, create_mobile_driver,
save_cookies, save_cookies,
load_cookies, load_cookies,
@ -22,6 +23,10 @@ from lib.lib import (
clean_html_text clean_html_text
) )
def debug(msg):
if DEBUG:
print(f"[DEBUG] {msg}")
class NaverReviewCollector: class NaverReviewCollector:
def __init__(self, headless=HEADLESS): def __init__(self, headless=HEADLESS):
self.headless = headless self.headless = headless
@ -41,7 +46,7 @@ class NaverReviewCollector:
try: try:
modal = wait.until(EC.presence_of_element_located((By.ID, "modal-root"))) modal = wait.until(EC.presence_of_element_located((By.ID, "modal-root")))
modal.find_element(By.XPATH, './/button').click() modal.find_element(By.XPATH, './/button').click()
except: except Exception:
pass pass
try: try:
@ -49,7 +54,6 @@ class NaverReviewCollector:
self.driver.find_element(By.ID, 'pw').send_keys(NAVER_PW) self.driver.find_element(By.ID, 'pw').send_keys(NAVER_PW)
self.driver.find_element(By.XPATH, '//button[@type="submit"]').click() self.driver.find_element(By.XPATH, '//button[@type="submit"]').click()
except Exception: except Exception:
self.driver.quit()
return False return False
time.sleep(3) time.sleep(3)
@ -70,9 +74,32 @@ class NaverReviewCollector:
EC.presence_of_element_located((By.XPATH, '//*[starts-with(@class, "Header_btn_select_")]')) EC.presence_of_element_located((By.XPATH, '//*[starts-with(@class, "Header_btn_select_")]'))
) )
return el.text.strip() return el.text.strip()
except: except Exception:
return "알수없음" return "알수없음"
def extract_written_date(self, spans, li):
labels = [s.text.strip() for s in spans]
try:
if "작성일" in labels:
idx = labels.index("작성일")
return spans[idx + 1].find_element(By.TAG_NAME, "time").text.strip()
elif "예약자" in labels:
return li.find_element(By.XPATH, ".//div[3]/div[1]/span[2]/time").text.strip()
except Exception:
return None
def extract_review_text(self, li):
for i in range(4, 7):
try:
el = li.find_element(By.XPATH, f"./div[{i}]/a")
if el:
text = el.text.strip()
return clean_html_text(el.get_attribute("innerHTML")) if text else "내용 없음"
except Exception:
continue
return "내용 없음"
def extract_reviews(self): def extract_reviews(self):
reviews = [] reviews = []
try: try:
@ -81,48 +108,34 @@ class NaverReviewCollector:
) )
lis = self.driver.find_elements(By.XPATH, "//ul[starts-with(@class, 'Review_columns_list')]/li") lis = self.driver.find_elements(By.XPATH, "//ul[starts-with(@class, 'Review_columns_list')]/li")
for li in lis: for li in lis:
if "Review_banner__" in li.get_attribute("class"):
continue
try: try:
if "Review_banner__" in li.get_attribute("class"):
continue
author = li.find_element(By.XPATH, ".//div[1]/a[2]/div/span/span").text.strip() author = li.find_element(By.XPATH, ".//div[1]/a[2]/div/span/span").text.strip()
visit_text = li.find_element(By.XPATH, ".//div[2]/div[1]/span[2]/time").text.strip() visit_text = li.find_element(By.XPATH, ".//div[2]/div[1]/span[2]/time").text.strip()
visit_date = datetime.strptime(visit_text.split("(")[0].replace(". ", "-").replace(".", ""), "%Y-%m-%d").strftime("%Y-%m-%d") visit_date = datetime.strptime(
visit_text.split("(")[0].replace(". ", "-").replace(".", ""), "%Y-%m-%d"
).strftime("%Y-%m-%d")
spans = li.find_elements(By.XPATH, ".//div[2]/div[2]/span") spans = li.find_elements(By.XPATH, ".//div[2]/div[2]/span")
labels = [s.text.strip() for s in spans] written_text = self.extract_written_date(spans, li)
written_text = None
if "작성일" in labels:
idx = labels.index("작성일")
written_text = spans[idx + 1].find_element(By.TAG_NAME, "time").text.strip()
elif "예약자" in labels:
try:
written_text = li.find_element(By.XPATH, ".//div[3]/div[1]/span[2]/time").text.strip()
except:
continue
if not written_text: if not written_text:
continue continue
written_date = datetime.strptime(written_text.split("(")[0].replace(". ", "-").replace(".", ""), "%Y-%m-%d").date() try:
written_date = datetime.strptime(
written_text.split("(")[0].replace(". ", "-").replace(".", ""), "%Y-%m-%d"
).date()
except ValueError:
continue
if not (self.start_date <= written_date <= self.end_date): if not (self.start_date <= written_date <= self.end_date):
continue continue
content_el = None text = self.extract_review_text(li)
for i in range(4, 7): #if not text:
try: # continue
el = li.find_element(By.XPATH, f"./div[{i}]/a")
if el and el.text.strip():
content_el = el
break
except:
continue
if content_el is None:
continue
html = content_el.get_attribute("innerHTML")
text = clean_html_text(html)
reviews.append({ reviews.append({
"작성자": author, "작성자": author,
@ -130,10 +143,9 @@ class NaverReviewCollector:
"작성일": written_date, "작성일": written_date,
"내용": text "내용": text
}) })
except Exception:
except:
continue continue
except: except Exception:
pass pass
return reviews return reviews
@ -163,9 +175,10 @@ class NaverReviewCollector:
lines.append("---") lines.append("---")
message = "\n".join(lines) message = "\n".join(lines)
if not MESSAGE_PLATFORMS: if not MESSAGE_PLATFORMS:
print("[WARN] 메시지 전송 플랫폼이 지정되지 않음. 미전송") print("[WARN] 메시지 전송 플랫폼이 지정되지 않음. 미전송")
print(f"[DEBUG] {message}") debug(message)
return return
sender = MessageSender( sender = MessageSender(
@ -175,38 +188,40 @@ class NaverReviewCollector:
) )
if DEBUG: if DEBUG:
print(f"[DEBUG] message platform : {MESSAGE_PLATFORMS}") debug(f"메시지 플랫폼: {MESSAGE_PLATFORMS}")
print("[DEBUG] 디버그 모드 메시지 전송") debug("디버그 모드: 메시지 전송 생략")
print(f"[DEBUG] {message}") debug(message)
else: else:
sender.send(message, platforms=MESSAGE_PLATFORMS, use_webhook=False) sender.send(message, platforms=MESSAGE_PLATFORMS, use_webhook=False)
def run(self): def run(self):
self.create_driver() while True:
self.driver.get("https://naver.com") self.create_driver()
time.sleep(1) self.driver.get("https://naver.com")
time.sleep(1)
if os.path.exists(COOKIE_FILE): if os.path.exists(COOKIE_FILE):
try: try:
load_cookies(self.driver, COOKIE_FILE) load_cookies(self.driver, COOKIE_FILE)
self.driver.get("https://naver.com") self.driver.get("https://naver.com")
time.sleep(1) time.sleep(1)
except: except Exception:
os.remove(COOKIE_FILE) os.remove(COOKIE_FILE)
self.driver.quit()
self.headless = False
continue
else:
if self.headless:
self.driver.quit()
self.headless = False
continue
if not self.perform_login():
self.driver.quit()
return
self.driver.quit() self.driver.quit()
NaverReviewCollector(headless=False).run() continue
return
else: break # 쿠키 로딩 또는 로그인 성공 시 루프 종료
if self.headless:
self.driver.quit()
NaverReviewCollector(headless=False).run()
return
if not self.perform_login():
self.driver.quit()
return
self.driver.quit()
NaverReviewCollector(headless=self.headless).run()
return
for biz_id in BIZ_ID: for biz_id in BIZ_ID:
place_name = self.access_review_page(biz_id) place_name = self.access_review_page(biz_id)
@ -215,8 +230,8 @@ class NaverReviewCollector:
print("[WARN] 세션 만료 또는 쿠키 무효. 로그인 재진행") print("[WARN] 세션 만료 또는 쿠키 무효. 로그인 재진행")
os.remove(COOKIE_FILE) os.remove(COOKIE_FILE)
self.driver.quit() self.driver.quit()
NaverReviewCollector(headless=False).run() self.headless = False
return return self.run()
try: try:
reviews = self.extract_reviews() reviews = self.extract_reviews()
@ -228,13 +243,14 @@ class NaverReviewCollector:
self.reviews_by_place[place_name] = [] self.reviews_by_place[place_name] = []
self.driver.quit() self.driver.quit()
if not self.reviews_by_place: if not self.reviews_by_place:
sender = MessageSender( sender = MessageSender(
mattermost_url=MATTERMOST_URL, mattermost_url=MATTERMOST_URL,
mattermost_bot_token=MATTERMOST_BOT_TOKEN, mattermost_token=MATTERMOST_BOT_TOKEN,
mattermost_channel_id=MATTERMOST_CHANNEL_ID, mattermost_channel_id=MATTERMOST_CHANNEL_ID,
) )
send_failure_message(sender, MESSAGE_PLATFORMS) send_failure_message(sender, MESSAGE_PLATFORMS)
else: else:
self.send_to_message() self.send_to_message()

View File

@ -1,12 +1,11 @@
# lib/lib.py # lib/lib.py
import os import os, sys
import sys
import time import time
import pickle import pickle
import re import re
from datetime import datetime, timedelta
import undetected_chromedriver as uc import undetected_chromedriver as uc
from datetime import datetime, timedelta
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
# 공통 설정 경로 추가 (필요 시) # 공통 설정 경로 추가 (필요 시)

View File

@ -1,3 +1,4 @@
# naver_review_crawler.py
import os, sys import os, sys
from datetime import datetime from datetime import datetime
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
@ -7,11 +8,11 @@ from selenium.webdriver.support import expected_conditions as EC
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from conf.config import ( from conf.config import (
PLACE_IDS, START_DATE, END_DATE, DEBUG, PLACE_IDS, START_DATE, END_DATE, DEBUG,
MESSAGE_PLATFORMS, MATTERMOST_URL, MATTERMOST_BOT_TOKEN, MATTERMOST_CHANNEL_ID MESSAGE_PLATFORMS, MATTERMOST_URL, MATTERMOST_BOT_TOKEN, MATTERMOST_CHANNEL_ID
) )
from lib.send_message import MessageSender from lib.send_message import MessageSender
from lib.lib import ( from lib.common import (
create_mobile_driver, create_mobile_driver,
get_start_end_dates, get_start_end_dates,
parse_korean_date, parse_korean_date,
@ -21,7 +22,13 @@ from lib.lib import (
send_failure_message send_failure_message
) )
class NaverReviewMapCollector:
def debug(msg):
if DEBUG:
print(f"[DEBUG] {msg}")
class NaverMapReviewCollector:
def __init__(self): def __init__(self):
self.driver = None self.driver = None
self.total_reviews = 0 self.total_reviews = 0
@ -30,40 +37,46 @@ class NaverReviewMapCollector:
def extract_reviews(self): def extract_reviews(self):
reviews = [] reviews = []
WebDriverWait(self.driver, 10).until( try:
EC.presence_of_element_located((By.ID, "_review_list")) WebDriverWait(self.driver, 10).until(
) EC.presence_of_element_located((By.ID, "_review_list"))
ul = self.driver.find_element(By.ID, "_review_list") )
items = ul.find_elements(By.XPATH, './/li[contains(@class, "place_apply_pui")]') ul = self.driver.find_element(By.ID, "_review_list")
for item in items: items = ul.find_elements(By.XPATH, './/li[contains(@class, "place_apply_pui")]')
try:
writer = "익명"
try:
writer = item.find_element(By.XPATH, "./div[1]/a[2]/div/span/span").text.strip()
except:
pass
date_obj = None for item in items:
try: try:
date_text = item.find_element(By.XPATH, "./div[7]/div[2]/div/span[1]/span[2]").text.strip() writer = "익명"
date_obj = parse_korean_date(date_text) try:
except: writer = item.find_element(By.XPATH, "./div[1]/a[2]/div/span/span").text.strip()
continue except Exception:
pass
text = "" try:
try: date_text = item.find_element(By.XPATH, "./div[7]/div[2]/div/span[1]/span[2]").text.strip()
text = item.find_element(By.XPATH, "./div[5]/a").get_attribute("innerHTML") date_obj = parse_korean_date(date_text)
except: except Exception:
continue continue
if not (self.start_date <= date_obj <= self.end_date):
continue
try:
text_html = item.find_element(By.XPATH, "./div[5]/a").get_attribute("innerHTML")
content = clean_html_text(text_html)
except Exception:
continue
if date_obj and (self.start_date <= date_obj <= self.end_date):
reviews.append({ reviews.append({
"작성자": writer, "작성자": writer,
"작성일": date_obj, "작성일": date_obj,
"내용": clean_html_text(text) "내용": content
}) })
except Exception as e:
print(f"[WARN] 리뷰 추출 실패: {e}") except Exception as e:
debug(f"[WARN] 리뷰 항목 처리 중 오류: {e}")
except Exception as e:
debug(f"[ERROR] 리뷰 리스트 접근 실패: {e}")
return reviews return reviews
def send_to_message(self): def send_to_message(self):
@ -91,9 +104,10 @@ class NaverReviewMapCollector:
lines.append("---") lines.append("---")
message = "\n".join(lines) message = "\n".join(lines)
if not MESSAGE_PLATFORMS: if not MESSAGE_PLATFORMS:
print("[WARN] 메시지 전송 플랫폼") print("[WARN] 메시지 전송 플랫폼이 지정되지 않")
print(f"[DEBUG] {message}") debug(message)
return return
sender = MessageSender( sender = MessageSender(
@ -103,8 +117,8 @@ class NaverReviewMapCollector:
) )
if DEBUG: if DEBUG:
print("[DEBUG] 디버그 모드로 메시지 전송") debug("디버그 모드로 메시지 전송 생략")
print(message) debug(message)
else: else:
sender.send(message, platforms=MESSAGE_PLATFORMS, use_webhook=False) sender.send(message, platforms=MESSAGE_PLATFORMS, use_webhook=False)
@ -114,10 +128,15 @@ class NaverReviewMapCollector:
for place_id in PLACE_IDS: for place_id in PLACE_IDS:
url = f"https://m.place.naver.com/place/{place_id}/review/visitor?reviewSort=recent" url = f"https://m.place.naver.com/place/{place_id}/review/visitor?reviewSort=recent"
print(f"[INFO] 접근: {url}") print(f"[INFO] 접근: {url}")
self.driver.get(url) try:
shop_name = extract_shop_name(self.driver) self.driver.get(url)
shop_name = extract_shop_name(self.driver)
except Exception as e:
print(f"[ERROR] {place_id} 매장 접근 오류: {e}")
continue
all_reviews = [] all_reviews = []
seen = set() seen = set() # (작성자, 작성일, 내용) 기준으로 중복 제거
while True: while True:
new_reviews = self.extract_reviews() new_reviews = self.extract_reviews()
@ -135,6 +154,7 @@ class NaverReviewMapCollector:
break break
all_reviews.extend(filtered) all_reviews.extend(filtered)
if not click_more(self.driver): if not click_more(self.driver):
break break
@ -154,6 +174,7 @@ class NaverReviewMapCollector:
else: else:
self.send_to_message() self.send_to_message()
if __name__ == "__main__": if __name__ == "__main__":
collector = NaverReviewMapCollector() collector = NaverMapReviewCollector()
collector.run() collector.run()

View File

@ -1,3 +1,4 @@
# send_message.py
import requests import requests
class MessageSender: class MessageSender:

2
naver_review_bot.bat Normal file
View File

@ -0,0 +1,2 @@
@echo off
python C:\DEV\python\fg-auto\naver_review\run.py

4
requirements.txt Normal file
View File

@ -0,0 +1,4 @@
selenium
requests
undetected_chromedriver
dotenv

43
run.py
View File

@ -1,28 +1,27 @@
import os # run.py
import sys import os, sys
from dotenv import load_dotenv
# 환경 변수 로드
load_dotenv()
# 프로젝트 루트 기준 경로 추가 # 프로젝트 루트 기준 경로 추가
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), 'lib'))) sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), 'lib')))
# 실행 모드 확인 from conf import config
mode = os.getenv("MODE", "").strip().lower()
if mode == "biz": def main():
from lib.biz_crawler import NaverReviewCollector mode = os.getenv("MODE", "").strip().lower()
print("[INFO] 비즈니스 리뷰 수집기 실행")
collector = NaverReviewCollector()
collector.run()
elif mode == "map": if mode == "biz":
from lib.naver_review_crawler import NaverMapReviewCollector from lib.biz_crawler import NaverReviewCollector
print("[INFO] 지도 리뷰 수집기 실행") print("[INFO] 비즈니스 리뷰 수집기 실행")
collector = NaverMapReviewCollector() collector = NaverReviewCollector()
collector.run() collector.run()
else: elif mode == "map":
print("[ERROR] .env 파일에서 MODE 값을 설정해주세요. (biz 또는 map)") from lib.naver_review_crawler import NaverMapReviewCollector
print("[INFO] 지도 리뷰 수집기 실행")
collector = NaverMapReviewCollector()
collector.run()
else:
print(f"[ERROR] .env 파일에서 MODE 값을 설정해주세요. (biz 또는 map) 현재값: '{mode}'")
if __name__ == "__main__":
main()