테스트 사이트 - 개발 중인 베타 버전입니다

그누보드 자동 글 작성 + 멀티 파일 업로드 스크립트 (Python)

냑 회원님들 안녕하세요? ^-^

 

이번 주말에는 비가 많이 오네요~ 

 

다들 비 피해 없으시기를 기원할게요! :)

 

 

저번에 작성했던 'Python으로 구현한 그누보드 자동 글쓰기 함수'( https://sir.kr/g5_tip/15678 )를 보완하여

 

멀티 파일 업로드까지 가능하도록 업데이트 하였습니다 ^^

 

그누보드 PHP 내장함수를 사용할 수 없기 때문에 해당 함수를 파이썬으로 변환하여 적절히 처리했구요~

 

다만 replace_filename() 함수에서 SHA1 방식 암호화를 하는 부분 중에 사용자 IP는 제외했습니다.

 

참고로 pymysql과 ftputil을 제외하면 Anaconda에 포함된 기본 모듈만 사용했어요 :)

 

 

아래 스크립트는 외부에서 그누보드 DB 및 FTP에 접속하는 것을 전제로 구현되었기 때문에

 

호스팅 또는 VPS에서 DB와 FTP에 외부접속할 수 있도록 설정하셔야 정상적으로 작동합니다.

 

 

[code]

import pymysql, ftputil, hashlib, os, sys

from datetime import datetime

from PIL import Image


 

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를 이용하여 파일을 업로드하는 함수입니다.

    with ftputil.FTPHost('URL을입력하세요', 'FTP계정명을입력하세요', 'FTP비번을입력하세요') as fh:

        fh.chdir('업로드할디렉토리를입력하세요ex./web/data/file/board')

        fh.upload(filename, bf_file, callback = None)

    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, file_list = None):

    # MySQL connection 및 cursor 생성

    conn = pymysql.connect(host = '연결할URL을입력하세요', 

                           user = 'MySQL유저명을입력하세요', 

                           password = 'MySQL비번을입력하세요',

                           db = 'MySQL디비명을입력하세요', 

                           charset = 'utf8')

    curs = conn.cursor()

 

    # 작성글 INSERT

    sql = f"select wr_num from g5_write_{board}"

    curs.execute(sql)

    wr_num = str(int(curs.fetchone()[0]) - 1)

    print(wr_num)

    now = datetime.today().strftime('%Y-%m-%d %H:%M:%S') # 그누보드의 날짜 형식 준수 (ex: 2021-04-05 23:45:15)

    sql = f"insert into g5_write_{board} set wr_num = {wr_num}, \

          wr_reply = '', wr_comment = 0, 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_1 = '', wr_2 = '', wr_3 = '', wr_4 = '', wr_5 = '', \

          wr_6 = '', wr_7 = '', wr_8 = '', wr_9 = '', wr_10 = '', \

          wr_comment_reply = '', wr_facebook_user = '', wr_twitter_user = '', \

          as_re_name = '', as_tag = '', as_map = '', as_icon = '', as_thumb = '', as_video = ''"

    curs.execute(sql)

 

    # 부모 아이디에 UPDATE

    sql = f"select wr_id from g5_write_{board}"

    curs.execute(sql)

    wr_id = str(curs.fetchall()[-1][0])

    print(f"wr_id : {wr_id}")

    sql = f"update g5_write_{board} set wr_parent = {wr_id} where wr_id = {wr_id}"

    curs.execute(sql)

 

    # 새글 INSERT

    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}' )"

    curs.execute(sql)

 

    # 게시글 1 증가

    sql = f"select bo_count_write from g5_board where bo_table = '{board}'"

    curs.execute(sql)

    bo_count_write = str(int(curs.fetchone()[0]))

    print(curs.fetchall())

    print(bo_count_write)

    sql = f"update g5_board set bo_count_write = {bo_count_write} + 1 where bo_table = '{board}'"

    curs.execute(sql)

 

    # 파일 업로드 및 관련 정보를 테이블에 저장

    if not file_list or file_list == [''] or file_list == []: # 첨부파일이 없는 경우에는 스크립트를 중단합니다.

        conn.close()

        sys.exit()

 

    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)

        if type != '0': # 이미지 파일의 경우 가로 및 세로를 구하고, 그 외의 경우에는 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 = '{file}', bf_file = '{bf_file}', \

              bf_content = '', bf_download = 0, bf_filesize = '{size}', \

              bf_width = '{width}', bf_height = '{height}', bf_type = '{type}', bf_datetime = '{now}'"

        curs.execute(sql)

    

    # 파일의 개수를 게시물에 업데이트

    sql = f"update g5_write_board set wr_file = '{file_count}' where wr_id = '{wr_id}'"

    curs.execute(sql)

 

    # MySQL connection 닫기

    conn.close()

    return


 

def main():

    board = '게시판명을입력하세요'

    subject = '제목을입력하세요'

    content = '내용을입력하세요HTML태그도가능합니다'

    mb_id = '아이디를입력하세요'

    nickname = '닉네임을입력하세요'

    file_list = ['업로드할파일명을입력하세요', '업로드할파일명을입력하세요']

    board_write(board, subject, content, mb_id, nickname, file_list)


 

if __name__ == "__main__":

    main()

[/code]

 

 

위 스크립트를 활용하여 3개의 파일(PNG, GIF, PY)을 업로드한 결과는 다음과 같습니다 ^^

 

영문이나 숫자가 아닌 한글로 된 파일명도 정상적으로 업로드되는 것을 확인했어요~

 

아미나에서 테스트하였지만 그누보드 5.4에서도 대동소이할 것으로 생각되네요 :)

 

 

3666978703_1621123092.7271.png

(냥냥펀치!)

 

 

테스트해보니 작성자명을 계정의 실제 닉네임과 달리 적용한 경우에

 

위 함수로 글을 올린 후 로그인하여 글을 수정하면 해당 계정의 실제 닉네임으로 변경되는 점을 주의하셔야 됩니다!

 

 

crontab에 넣고 장기적으로 실사용하시려면 다음과 같은 부분을 보완하시는 것을 권장합니다 ^^

 

1. 오류 처리

 

파일 업로드 실패 등의 경우에 글과 첨부파일을 삭제하고 sys.exit() 하도록 처리하면 좋을 것 같네요.

 

 

2. 보안

 

사이트 운영자가 직접 글 내용과 이미지를 선별하여 사용할 것이라면 별다른 보안 이슈는 없겠지만,

 

명랑폐인 님께서 올려주신 '게시판 파싱후 글등록 처리 함수'을 참고하여 조금 더 보완하시면 도움이 될듯요~

 

https://sir.kr/g5_tip/6977

 

만약 타 사이트에서 파싱한 결과물을 위 함수를 이용하여 그대로 올리는 목적으로 사용하시려면

 

SQL injection, steganography 등 기법에도 대응할 수 있도록 보완해야 안전할 것 같습니다 ㅎㄷㄷ

 

 

이상 허접한 스크립트인데 읽어주셔서 감사합니다!

 

다음에는 위 함수를 활용하여 브라우저에 접속하지 않은 상태에서

 

곧바로 글 작성 및 첨부파일 업로드를 할 수 있는 GUI 프로그램을 작성해볼게요~ 

 

그럼 냑 회원님들 다들 좋은 주말 되시고, 내일까지 비가 온다니 아침에 우산 꼭 챙기세요 ^-^

 

감사합니다!!

댓글 작성

댓글을 작성하시려면 로그인이 필요합니다.

로그인하기

댓글 11개

그누보드 자동 글 작성 + 멀티 파일 업로드 스크립트 (Python)
@sahara 옙 조금이나마 도움이 되셨으면 좋겠네요 ^-^
그럼 이번주도 좋은 한 주 되세요~! :)
이것을 사용하고 싶은데 어떻게 사용하는지요? 초보라 생각하고 가르쳐주시기 바랍니다
저는 한 서버에 그누2개를 사용하는데 1번 그누 게시글을 자동으로 2번 게시판에 어미지를 포함해서 올라가게 하려면 이것을 사용하면 될것 같은데 어떻게 사용하면 되는지요?

물론 디비에서 다운받아서 올리면 되는데 이게 훨씬 편할 것 같습니다
제가 잘못 이해를 했는지 모르지만요?

감사합니다
@풍운 안녕하세요? ^^
말씀하신 내용이 그누보드를 이용한 A 사이트와 B 사이트를 운영 중이신데,
A 사이트의 게시판에 누군가 글을 작성하면
자동으로 B 사이트에도 글이 작성되도록 하려는 용도이신거죠? :)

그러한 용도라면...
(1) crontab 등을 활용하여 적절한 시간 간격으로 A 사이트 게시판을 크롤링한 후에,
(2) B 사이트 게시판에 위 스크립트를 활용하여 올리시면 됩니다.

그런데 (1)에 해당하는 부분을 별도로 구현하셔야 되기 때문에,
아쉽게도 위 스크립트만으로는 원하시는 결과물을 얻어낼 수는 없습니다 ㅠㅠ

충분한 설명이 되셨는지요? :)
그럼 좋은 휴일 보내시길 기원합니다!
@Innisfree 아 그렇군요...감사드립니다
@풍운 옙 원하시는 결과를 구현하는 방법이 여러 가지가 있을 것 같습니다 ^-^
SIR에는 저보다 고수님들이 많이 계시니 해당 내용을 질문 게시판에 올리시면
최선의 방법을 찾으실 수 있을 것 같네요 :)
일회적으로 크롤링하는 것과, 장기적으로 꾸준히 크롤링하는 것은 상당히 다릅니다.
저는 파이썬이 편해서 파이썬을 많이 활용하는 편이지만,
아마도 다른 분들께서는 굳이 파이썬을 사용하여 크롤링으로 해결하기보다는 다른 더 좋은 방법을 권하실 것 같습니다.
그럼 문의하신 내용도 잘 해결되시고, 가정에 건강이 늘 함께 하시기를 기원합니다!
@Innisfree 좋은조언 감사드립니다. 정리해서 한번 질문해보겠습니다
편한 휴일되세요
티스토리 글이랑, 첨부 긁어올수 있나요?

제 블로그가 티스토리에 글이 몇개 있는데
그누보드로 마이그레이션 하고 싶거든요
@더SUN 옙 티스토리 API를 이용하거나 곧바로 크롤링하는 방식으로 구현하면 가능합니다!
좋은 주말 되세요 ^^

유용한 자료 감사합니다.

게시판 목록

그누보드5 팁자료실

글쓰기
🐛 버그신고