성능 향상
This commit is contained in:
@ -1,180 +1,234 @@
|
||||
import pymysql, ftputil, hashlib, os, sys
|
||||
# -*- 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 subprocess
|
||||
import time
|
||||
import os
|
||||
import pymysql
|
||||
import ftputil
|
||||
|
||||
from config import DB_CONFIG, FTP_CONFIG, MAIN
|
||||
|
||||
# 오늘 날짜 기반으로 파일명 생성
|
||||
today_str = datetime.today().strftime('%Y%m%d')
|
||||
base_dir = os.path.dirname(os.path.abspath(__file__)) # 현재 파이썬 파일의 경로
|
||||
capture_script = os.path.join(base_dir, 'weather_capture.py')
|
||||
weather_filename = f'weather_capture_{today_str}.png'
|
||||
weather_file = os.path.join(base_dir, weather_filename)
|
||||
|
||||
# 파일 존재 확인 및 생성 루프
|
||||
while not os.path.isfile(weather_file):
|
||||
print(f"[{datetime.now().strftime('%H:%M:%S')}] {weather_file} 파일이 없습니다. {capture_script} 실행 중...")
|
||||
subprocess.call(['python3', capture_script])
|
||||
#time.sleep(1)
|
||||
|
||||
print(f"[{datetime.now().strftime('%H:%M:%S')}] {weather_file} 파일을 확인했습니다. 계속 진행합니다.")
|
||||
|
||||
# 파일 업로드 경로 설정
|
||||
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
|
||||
# ---------------------------
|
||||
# 이미지 캡처 관련 함수
|
||||
# ---------------------------
|
||||
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 file_type(x): # 그누보드의 bf_type 값을 반환하는 함수입니다. (디폴트 : 0)
|
||||
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(x.lower(), '0')
|
||||
|
||||
def file_upload(filename, bf_file): # FTP를 이용하여 파일을 업로드하는 함수입니다.
|
||||
|
||||
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, callback = None)
|
||||
print(f"[업로드 완료] {filename}")
|
||||
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
|
||||
|
||||
return
|
||||
|
||||
def get_filename(filename): # 파일명을 변환하는 함수입니다.
|
||||
ms = datetime.now().microsecond
|
||||
encoded_name = filename.encode('utf-8')
|
||||
result = f'{ms}_{hashlib.sha1(encoded_name).hexdigest()}'
|
||||
return result
|
||||
|
||||
def board_write(board, subject, content, mb_id, nickname, ca_name=None, file_list=None):
|
||||
conn = pymysql.connect(host=DB_CONFIG['HOST'],
|
||||
user=DB_CONFIG['USER'],
|
||||
db=DB_CONFIG['DBNAME'],
|
||||
password=DB_CONFIG['PASS'],
|
||||
charset='utf8')
|
||||
curs = conn.cursor()
|
||||
# ---------------------------
|
||||
# 게시글 작성 함수
|
||||
# ---------------------------
|
||||
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')
|
||||
|
||||
sql = f"SELECT wr_num FROM g5_write_{board}"
|
||||
print(f"[쿼리 실행] {sql}")
|
||||
curs.execute(sql)
|
||||
conn.commit()
|
||||
wr_num = str(int(curs.fetchone()[0]) - 1)
|
||||
print(f"[결과] wr_num: {wr_num}")
|
||||
# 게시글 번호(wr_num) 계산
|
||||
curs.execute(f"SELECT wr_num FROM g5_write_{board}")
|
||||
wr_num = str(int(curs.fetchone()[0]) - 1)
|
||||
|
||||
now = datetime.today().strftime('%Y-%m-%d %H:%M:%S')
|
||||
# 게시글 삽입
|
||||
curs.execute(f"""INSERT INTO g5_write_{board} SET wr_num = {wr_num},
|
||||
wr_reply = '', wr_comment = 0, 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))
|
||||
|
||||
sql = f"""INSERT INTO g5_write_{board} SET wr_num = {wr_num},
|
||||
wr_reply = '', wr_comment = 0, ca_name = '{ca_name}', wr_option = 'html1', wr_subject = '{subject}',
|
||||
wr_content = '{content}', wr_link1 = '', wr_link2 = '',
|
||||
wr_link1_hit = 0, wr_link2_hit = 0, wr_hit = 1, wr_good = 0, wr_nogood = 0,
|
||||
mb_id = '{mb_id}', wr_password = '', wr_name = '{nickname}', wr_email = '', wr_homepage = '',
|
||||
wr_datetime = '{now}', wr_last = '{now}', wr_ip = '111.111.111.111',
|
||||
wr_comment_reply = '', wr_facebook_user = '', wr_twitter_user = '',
|
||||
wr_1 = '', wr_2 = '', wr_3 = '', wr_4 = '', wr_5 = '', wr_6 = '', wr_7 = '', wr_8 = '', wr_9 = '', wr_10 = ''
|
||||
"""
|
||||
print(f"[쿼리 실행] {sql}")
|
||||
curs.execute(sql)
|
||||
conn.commit()
|
||||
print("[결과] 게시글 INSERT 완료")
|
||||
# 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])
|
||||
|
||||
sql = f"SELECT wr_id FROM g5_write_{board}"
|
||||
print(f"[쿼리 실행] {sql}")
|
||||
curs.execute(sql)
|
||||
wr_id = str(curs.fetchall()[-1][0])
|
||||
conn.commit()
|
||||
print(f"[결과] wr_id: {wr_id}")
|
||||
# wr_parent 업데이트
|
||||
curs.execute(f"UPDATE g5_write_{board} SET wr_parent = {wr_id} WHERE wr_id = {wr_id}")
|
||||
|
||||
sql = f"UPDATE g5_write_{board} SET wr_parent = {wr_id} WHERE wr_id = {wr_id}"
|
||||
print(f"[쿼리 실행] {sql}")
|
||||
curs.execute(sql)
|
||||
conn.commit()
|
||||
print("[결과] wr_parent 업데이트 완료")
|
||||
# 새글 테이블 등록
|
||||
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))
|
||||
|
||||
sql = f"""INSERT INTO g5_board_new (bo_table, wr_id, wr_parent, bn_datetime, mb_id)
|
||||
VALUES ('{board}', '{wr_id}', '{wr_id}', '{now}', '{mb_id}')"""
|
||||
print(f"[쿼리 실행] {sql}")
|
||||
curs.execute(sql)
|
||||
conn.commit()
|
||||
print("[결과] 새글 INSERT 완료")
|
||||
# 게시글 수 증가
|
||||
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))
|
||||
|
||||
sql = f"SELECT bo_count_write FROM g5_board WHERE bo_table = '{board}'"
|
||||
print(f"[쿼리 실행] {sql}")
|
||||
curs.execute(sql)
|
||||
bo_count_write = str(int(curs.fetchone()[0]))
|
||||
conn.commit()
|
||||
print(f"[결과] 현재 게시글 수: {bo_count_write}")
|
||||
# 파일 업로드 처리
|
||||
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}"
|
||||
|
||||
sql = f"UPDATE g5_board SET bo_count_write = {bo_count_write} + 1 WHERE bo_table = '{board}'"
|
||||
print(f"[쿼리 실행] {sql}")
|
||||
curs.execute(sql)
|
||||
conn.commit()
|
||||
print("[결과] 게시글 수 증가 완료")
|
||||
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
|
||||
|
||||
if not file_list:
|
||||
print("[종료] 첨부파일 없음. 연결 종료.")
|
||||
conn.close()
|
||||
sys.exit()
|
||||
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}")
|
||||
|
||||
file_count = len(file_list)
|
||||
for cnt, file in enumerate(file_list):
|
||||
ext = os.path.splitext(file)[1].lstrip('.')
|
||||
bf_file = f'{get_filename(file)}.{ext}'
|
||||
file_upload(file, bf_file)
|
||||
type = file_type(ext)
|
||||
# 첨부파일 수 업데이트
|
||||
curs.execute(f"UPDATE g5_write_{board} SET wr_file = %s WHERE wr_id = %s", (file_count, wr_id))
|
||||
|
||||
if type != '0':
|
||||
im = Image.open(file)
|
||||
width, height = im.size
|
||||
else:
|
||||
width, height = 0, 0
|
||||
|
||||
size = os.path.getsize(file)
|
||||
sql = f"""INSERT INTO g5_board_file SET bo_table = '{board}', wr_id = '{wr_id}',
|
||||
bf_no = '{cnt}', bf_source = '{weather_filename}', bf_file = '{bf_file}',
|
||||
bf_content = '', bf_download = 0, bf_filesize = '{size}',
|
||||
bf_width = '{width}', bf_height = '{height}', bf_type = '{type}', bf_datetime = '{now}'"""
|
||||
print(f"[쿼리 실행] {sql}")
|
||||
curs.execute(sql)
|
||||
# 트랜잭션 커밋 (단 1회)
|
||||
conn.commit()
|
||||
print(f"[결과] 파일({file}) 업로드 정보 INSERT 완료")
|
||||
print("[완료] 게시글 작성 및 파일 업로드 완료")
|
||||
|
||||
sql = f"UPDATE g5_write_{board} SET wr_file = '{file_count}' WHERE wr_id = '{wr_id}'"
|
||||
print(f"[쿼리 실행] {sql}")
|
||||
curs.execute(sql)
|
||||
conn.commit()
|
||||
print(f"[결과] 첨부파일 수 wr_file = {file_count} 업데이트 완료")
|
||||
except Exception as e:
|
||||
# 예외 발생 시 롤백
|
||||
conn.rollback()
|
||||
print(f"[DB 오류] {type(e).__name__}: {e}")
|
||||
finally:
|
||||
# 연결 종료
|
||||
conn.close()
|
||||
|
||||
conn.close()
|
||||
print("[종료] MySQL 연결 종료")
|
||||
|
||||
|
||||
|
||||
# ---------------------------
|
||||
# 메인 실행 함수
|
||||
# ---------------------------
|
||||
def main():
|
||||
board = MAIN['board']
|
||||
ca_name = MAIN['ca_name']
|
||||
subject = MAIN['subject']
|
||||
content = MAIN['content']
|
||||
mb_id = MAIN['mb_id']
|
||||
nickname = MAIN['nickname']
|
||||
file_list = [MAIN['file1'], MAIN['file2']]
|
||||
# file_list = [MAIN['file1']]
|
||||
board_write(board, subject, content, mb_id, nickname, ca_name, file_list)
|
||||
# 파일 경로 및 이름 설정
|
||||
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()
|
||||
|
||||
# main() 완료 후 이미지 파일 삭제
|
||||
if os.path.isfile(weather_file):
|
||||
try:
|
||||
os.remove(weather_file)
|
||||
print(f"[삭제 완료] {weather_file} 파일을 삭제했습니다.")
|
||||
except Exception as e:
|
||||
print(f"[삭제 오류] {type(e).__name__}: {e}")
|
||||
else:
|
||||
print(f"[파일 없음] {weather_file} 파일을 찾을 수 없습니다.")
|
||||
|
||||
Reference in New Issue
Block a user