Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f61eb5e23 | |||
| fe5a8c8b1c | |||
| f79ffcec63 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ config.py
|
||||
naver_review/build/
|
||||
*.spec
|
||||
data/weather_capture_*.png
|
||||
.vscode/
|
||||
|
||||
@ -21,25 +21,62 @@ import ftputil
|
||||
|
||||
from config import DB_CONFIG, FTP_CONFIG, MAIN
|
||||
from weather import get_precipitation_summary
|
||||
from send_message import MessageSender # MessageSender 클래스 임포트
|
||||
|
||||
|
||||
# ---------------------------
|
||||
# 이미지 캡처 함수
|
||||
# ---------------------------
|
||||
def capture_image(script_path, output_path, max_attempts=5):
|
||||
def capture_image(script_path, output_path, max_attempts=5, msg_sender=None):
|
||||
"""
|
||||
이미지 캡처 시도
|
||||
|
||||
Returns:
|
||||
tuple: (성공여부, 에러메시지)
|
||||
"""
|
||||
for attempt in range(max_attempts):
|
||||
print(f"[{datetime.now().strftime('%H:%M:%S')}] 이미지 캡처 시도 {attempt + 1}/{max_attempts}")
|
||||
try:
|
||||
subprocess.run([sys.executable, script_path], check=True)
|
||||
result = subprocess.run(
|
||||
[sys.executable, script_path],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=60 # 60초 타임아웃 설정
|
||||
)
|
||||
|
||||
if os.path.isfile(output_path):
|
||||
print(f"[성공] 이미지가 정상적으로 캡처되었습니다: {output_path}")
|
||||
return True, None
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
error_msg = f"캡처 스크립트 실행 타임아웃 (시도 {attempt + 1}/{max_attempts})"
|
||||
print(f"[오류] {error_msg}")
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"[오류] weather_capture.py 실행 실패: {e}")
|
||||
if os.path.isfile(output_path):
|
||||
print(f"[성공] 이미지가 정상적으로 캡처되었습니다: {output_path}")
|
||||
return True
|
||||
error_msg = f"weather_capture.py 실행 실패:\n{e.stderr if e.stderr else str(e)}"
|
||||
print(f"[오류] {error_msg}")
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"예상치 못한 오류: {type(e).__name__}: {e}"
|
||||
print(f"[오류] {error_msg}")
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
# 모든 시도 실패
|
||||
final_error = f"❌ **날씨 이미지 캡처 실패**\n\n"\
|
||||
f"📅 날짜: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"\
|
||||
f"🔄 시도 횟수: {max_attempts}회\n"\
|
||||
f"📁 출력 경로: `{output_path}`\n"\
|
||||
f"⚠️ 파일이 생성되지 않았습니다."
|
||||
|
||||
print(f"[실패] {max_attempts}회 시도 후에도 이미지가 생성되지 않았습니다.")
|
||||
return False
|
||||
|
||||
|
||||
# Mattermost 알림 전송
|
||||
if msg_sender:
|
||||
msg_sender.send(final_error, platforms=['mattermost'])
|
||||
|
||||
return False, final_error
|
||||
|
||||
# ---------------------------
|
||||
# 파일 관련 유틸 함수
|
||||
@ -70,11 +107,17 @@ def file_upload(filename, bf_file):
|
||||
print(f"[FTP 오류] {type(e).__name__}: {e}")
|
||||
return False
|
||||
|
||||
|
||||
# ---------------------------
|
||||
# 게시글 작성 함수
|
||||
# ---------------------------
|
||||
def write_board(board, subject, content, mb_id, nickname, ca_name=None, file_list=None):
|
||||
def write_board(board, subject, content, mb_id, nickname, ca_name=None, file_list=None, msg_sender=None):
|
||||
"""
|
||||
게시글 작성
|
||||
|
||||
Returns:
|
||||
tuple: (성공여부, 에러메시지)
|
||||
"""
|
||||
conn = None
|
||||
try:
|
||||
conn = pymysql.connect(
|
||||
host=DB_CONFIG['HOST'],
|
||||
@ -135,27 +178,48 @@ def write_board(board, subject, content, mb_id, nickname, ca_name=None, file_lis
|
||||
size, width, height, img_type, now))
|
||||
file_count += 1
|
||||
else:
|
||||
raise Exception(f"[FTP 오류] 파일 업로드 실패: {file}")
|
||||
raise Exception(f"파일 업로드 실패: {file}")
|
||||
|
||||
curs.execute(f"UPDATE g5_write_{board} SET wr_file = %s WHERE wr_id = %s", (file_count, wr_id))
|
||||
conn.commit()
|
||||
print("[성공] 게시글과 첨부파일 등록 완료")
|
||||
return True, None
|
||||
|
||||
except Exception as e:
|
||||
conn.rollback()
|
||||
if "[FTP 오류]" in str(e):
|
||||
if conn:
|
||||
conn.rollback()
|
||||
|
||||
# 에러 메시지 생성
|
||||
error_detail = traceback.format_exc()
|
||||
error_msg = f"❌ **게시글 등록 실패**\n\n"\
|
||||
f"📅 날짜: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"\
|
||||
f"📋 게시판: `{board}`\n"\
|
||||
f"📝 제목: {subject}\n"\
|
||||
f"⚠️ 오류 유형: `{type(e).__name__}`\n"\
|
||||
f"💬 오류 메시지: {str(e)}\n"\
|
||||
f"```\n{error_detail}\n```"
|
||||
|
||||
if "FTP" in str(e) or "파일 업로드" in str(e):
|
||||
print(f"[FTP 오류] {e}")
|
||||
else:
|
||||
print(f"[DB 오류] {type(e).__name__}: {e}")
|
||||
raise
|
||||
|
||||
# Mattermost 알림 전송
|
||||
if msg_sender:
|
||||
msg_sender.send(error_msg, platforms=['mattermost'])
|
||||
|
||||
return False, error_msg
|
||||
|
||||
finally:
|
||||
conn.close()
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
|
||||
# ---------------------------
|
||||
# 메인 실행 함수
|
||||
# ---------------------------
|
||||
def main():
|
||||
|
||||
# 기상청 API로 얻어오는 데이터와 캡처의 데이터가 다르므로 내용에 대해 업데이트 하지 않음.
|
||||
# 날씨 정보 문자열 얻기
|
||||
#weather_content = get_precipitation_summary()
|
||||
@ -167,6 +231,8 @@ def main():
|
||||
MAIN["content"] = """
|
||||
<p>Rainy Day 이벤트 적용안내</p>
|
||||
<p><b>10:00 ~ 22:00까지의 예보를 합산하며, ~1mm인 경우 0.5mm로 계산합니다.</b></p>
|
||||
<p>레이니데이 이벤트 정보 확인</p>
|
||||
<p><a href="https://firstgarden.co.kr/news/60">이벤트 정보 보기</a></p>
|
||||
"""
|
||||
|
||||
today = datetime.today().strftime('%Y%m%d')
|
||||
|
||||
@ -61,7 +61,7 @@ try:
|
||||
|
||||
# 캡처 대상 요소 대기 후 찾기
|
||||
target_element = wait.until(EC.presence_of_element_located(
|
||||
(By.XPATH, '/html/body/div[2]/section/div/div[2]')
|
||||
(By.XPATH, '/html/body/div[1]/main/div[2]/div[1]')
|
||||
))
|
||||
|
||||
# 저장 경로 설정
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 128 KiB |
Reference in New Issue
Block a user