Files
fg-auto/data/gnu_autoupload.py

235 lines
8.1 KiB
Python

# -*- coding: utf-8 -*-
"""
gnu_autoupload.py
기능:
1. Selenium을 이용해 날씨 정보를 캡처 (weather_capture.py 호출)
2. FTP를 이용해 이미지 업로드
3. 그누보드 DB에 게시글 및 첨부파일 정보 자동 등록
"""
import os
import sys
import time
import subprocess
import tempfile
import hashlib
from datetime import datetime
from PIL import Image
import pymysql
import ftputil
from config import DB_CONFIG, FTP_CONFIG, MAIN
# ---------------------------
# 이미지 캡처 관련 함수
# ---------------------------
def capture_image(script_path, output_path, max_attempts=5):
"""
weather_capture.py를 실행해 이미지 파일을 생성
:param script_path: 캡처 스크립트 경로
:param output_path: 기대되는 이미지 파일 경로
:param max_attempts: 최대 재시도 횟수
:return: 성공 여부 (True/False)
"""
for attempt in range(max_attempts):
print(f"[{datetime.now().strftime('%H:%M:%S')}] 캡처 시도 {attempt + 1}/{max_attempts}")
try:
subprocess.run(['python3', script_path], check=True)
except subprocess.CalledProcessError as e:
print(f"[오류] weather_capture.py 실행 실패: {e}")
if os.path.isfile(output_path):
print(f"[성공] 이미지 캡처 완료: {output_path}")
return True
time.sleep(2)
print(f"[실패] {max_attempts}회 시도 후에도 이미지가 생성되지 않았습니다.")
return False
# ---------------------------
# 파일 업로드 및 처리 관련
# ---------------------------
def file_type(ext):
"""
파일 확장자를 기반으로 그누보드용 파일 유형 코드 반환
"""
return {
'gif': '1', 'jpeg': '2', 'jpg': '2', 'png': '3', 'swf': '4',
'psd': '5', 'bmp': '6', 'tif': '7', 'tiff': '7', 'jpc': '9',
'jp2': '10', 'jpx': '11', 'jb2': '12', 'swc': '13', 'iff': '14',
'wbmp': '15', 'xbm': '16'
}.get(ext.lower(), '0')
def get_filename(filename):
"""
원본 파일명을 기반으로 해시된 파일명을 생성
"""
ms = datetime.now().microsecond
encoded_name = filename.encode('utf-8')
return f'{ms}_{hashlib.sha1(encoded_name).hexdigest()}'
def file_upload(filename, bf_file):
"""
FTP 서버에 파일 업로드
:param filename: 로컬 경로
:param bf_file: 서버에 저장될 파일명
"""
try:
with ftputil.FTPHost(FTP_CONFIG['HOST'], FTP_CONFIG['USER'], FTP_CONFIG['PASS']) as fh:
fh.chdir(FTP_CONFIG['UPLOAD_DIR'])
fh.upload(filename, bf_file)
print(f"[업로드 완료] {filename}{bf_file}")
return True
except Exception as e:
print(f"[FTP 오류] {type(e).__name__}: {e}")
return False
# ---------------------------
# 게시글 작성 함수
# ---------------------------
def write_board(board, subject, content, mb_id, nickname, ca_name=None, file_list=None):
"""
그누보드 DB에 게시글과 파일을 한 트랜잭션으로 삽입
:param board: 게시판 ID
:param subject: 제목
:param content: 내용
:param mb_id: 회원 ID
:param nickname: 작성자 이름
:param ca_name: 카테고리명
:param file_list: 첨부파일 경로 리스트
"""
try:
# 데이터베이스 연결
conn = pymysql.connect(
host=DB_CONFIG['HOST'],
user=DB_CONFIG['USER'],
db=DB_CONFIG['DBNAME'],
password=DB_CONFIG['PASS'],
charset='utf8'
)
curs = conn.cursor()
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# 게시글 번호(wr_num) 계산
curs.execute(f"SELECT wr_num FROM g5_write_{board}")
wr_num = str(int(curs.fetchone()[0]) - 1)
# 게시글 삽입
curs.execute(f"""INSERT INTO g5_write_{board} SET wr_num = {wr_num},
wr_reply = '', wr_comment = 0, wr_comment_reply = '', ca_name = %s, wr_option = 'html1', wr_subject = %s,
wr_content = %s, wr_link1 = '', wr_link2 = '', wr_link1_hit = 0, wr_link2_hit = 0,
wr_hit = 1, wr_good = 0, wr_nogood = 0, mb_id = %s, wr_password = '',
wr_name = %s, wr_email = '', wr_homepage = '', wr_datetime = %s, wr_last = %s,
wr_ip = '127.0.0.1'""",
(ca_name, subject, content, mb_id, nickname, now, now))
# wr_id 조회
curs.execute(f"SELECT wr_id FROM g5_write_{board} ORDER BY wr_id DESC LIMIT 1")
wr_id = str(curs.fetchone()[0])
# wr_parent 업데이트
curs.execute(f"UPDATE g5_write_{board} SET wr_parent = {wr_id} WHERE wr_id = {wr_id}")
# 새글 테이블 등록
curs.execute(f"""INSERT INTO g5_board_new (bo_table, wr_id, wr_parent, bn_datetime, mb_id)
VALUES (%s, %s, %s, %s, %s)""", (board, wr_id, wr_id, now, mb_id))
# 게시글 수 증가
curs.execute(f"SELECT bo_count_write FROM g5_board WHERE bo_table = %s", (board,))
bo_count_write = int(curs.fetchone()[0])
curs.execute(f"UPDATE g5_board SET bo_count_write = %s WHERE bo_table = %s",
(bo_count_write + 1, board))
# 파일 업로드 처리
file_count = 0
if file_list:
for idx, file in enumerate(file_list):
ext = os.path.splitext(file)[1].lstrip('.')
bf_file = f"{get_filename(file)}.{ext}"
if file_upload(file, bf_file):
img_type = file_type(ext)
width, height = (0, 0)
if img_type != '0':
with Image.open(file) as img:
width, height = img.size
size = os.path.getsize(file)
curs.execute(f"""INSERT INTO g5_board_file SET bo_table = %s, wr_id = %s, bf_no = %s,
bf_source = %s, bf_file = %s, bf_content = '', bf_download = 0,
bf_filesize = %s, bf_width = %s, bf_height = %s, bf_type = %s, bf_datetime = %s""",
(board, wr_id, idx, os.path.basename(file), bf_file,
size, width, height, img_type, now))
file_count += 1
else:
print(f"[경고] 파일 업로드 실패: {file}")
# 첨부파일 수 업데이트
curs.execute(f"UPDATE g5_write_{board} SET wr_file = %s WHERE wr_id = %s", (file_count, wr_id))
# 트랜잭션 커밋 (단 1회)
conn.commit()
print("[완료] 게시글 작성 및 파일 업로드 완료")
except Exception as e:
# 예외 발생 시 롤백
conn.rollback()
print(f"[DB 오류] {type(e).__name__}: {e}")
finally:
# 연결 종료
conn.close()
# ---------------------------
# 메인 실행 함수
# ---------------------------
def main():
# 파일 경로 및 이름 설정
today = datetime.today().strftime('%Y%m%d')
script_dir = os.path.dirname(os.path.abspath(__file__))
capture_script = os.path.join(script_dir, 'weather_capture.py')
weather_filename = f'weather_capture_{today}.png'
weather_file = os.path.join(script_dir, weather_filename)
# 이미지 생성 시도
if not capture_image(capture_script, weather_file):
return
# 설정값 동적 갱신
FTP_CONFIG['UPLOAD_DIR'] = f"/www/data/file/{MAIN['board']}/"
MAIN['subject'] = f"[{datetime.now().strftime('%Y-%m-%d')}] 날씨 정보"
MAIN['file1'] = MAIN['file2'] = weather_file
file_list = [MAIN['file1']]
# 게시글 작성
write_board(
board=MAIN['board'],
subject=MAIN['subject'],
content=MAIN['content'],
mb_id=MAIN['mb_id'],
nickname=MAIN['nickname'],
ca_name=MAIN['ca_name'],
file_list=file_list
)
# 캡처 파일 삭제
try:
if os.path.isfile(weather_file):
os.remove(weather_file)
print(f"[삭제 완료] {weather_file}")
except Exception as e:
print(f"[삭제 오류] {type(e).__name__}: {e}")
# ---------------------------
# 스크립트 실행 진입점
# ---------------------------
if __name__ == "__main__":
main()