본문 바로가기

세미나

Python의 win32com 으로 윈도우 프로그램 제어하기

728x90

프로젝트를 진행하던 도중 서버에서 hwp 파일을 저장한 후 다른 사용자에게 해당 파일을 보여줘야 하는 기능이 필요했습니다.

그런데 다른 사용자들이 한글이 없으면 열람하지 못하는 상황이 발생하기 때문에 hwp 파일을 pdf 파일로 변환하기로 했습니다.

 

하지만 자바에는 hwp 를 다루는 라이브러리가 존재하지 않았고, 결국 한번도 해보지 않은 Python으로 개발하게 되었습니다.

 

win32com 으로 한글 파일 다루기

Python에는 hwp 파일을 다루는 방법이 존재 했습니다.

win32com 은 윈도우 프로그램을 파이썬 언어를 매개체로 제어할 수 있도록 만들어진 api로

이를 통해 한글파일을 열고 pdf 파일로 save as(다른이름으로 저장) 작업을 수행할 수 있었습니다.

 

hwp to pdf

def hwptopdf(filename, path):
  hwp = win32.gencache.EnsureDispatch('HWPFrame.HwpObject', pythoncom.CoInitialize())
  hwp.RegisterModule('FilePathCheckDLL', 'SecurityModule')
  
  pattern = re.compile('.*[.]hwp', re.IGNORECASE)
  if pattern.match(filename):

    t = threading.Thread(target=pressD)
    t.daemon = True
    t.start()
    hwp.Open(os.path.join(path, filename))

    pre, ext = os.path.splitext(filename)
    hwp.HAction.GetDefault("FileSaveAs_S", hwp.HParameterSet.HFileOpenSave.HSet)
    hwp.HParameterSet.HFileOpenSave.filename = os.path.join(path, pre + ".pdf")
    hwp.HParameterSet.HFileOpenSave.Format = "PDF"
    hwp.HAction.Execute("FileSaveAs_S", hwp.HParameterSet.HFileOpenSave.HSet)

  hwp.Quit()

 

hwp 파일을 연 후 pdf 로 저장을 하는데 보안 모듈 승인창이 실행되어 승인 버튼을 따로 눌러줘야 하는 상황이 발생했습니다.

저는 이를 키보드를 제어하는 라이브러리를 이용해 다른 스레드 에서 모두허용(alt + a) 버튼을 누르도록 처리했습니다.

 

파일 업로드 endpoint

@app.route('/hwptopdf', methods = ['POST'])
def upload_file():
  # form 전송된 file을 받아옴
  f = request.files['file']
  # form 전송된 url을 받아오고, 저장될 경로로 만듬
  filename = secure_filename(f.filename)
  pattern = re.compile('.*[.]hwp', re.IGNORECASE)
  if pattern.match(filename):
    url =  request.url_root + "pdf" + originPath + "/"
    f.save(os.path.join(path, filename))
    # queue에 데이터 추가
    global fileQueue
    fileQueue.put((filename, path, noticeId, url))
  response = app.response_class(status=200)
  return response

 

서버 프레임워크는 Flask를 사용했습니다. 워낙 간단하게 작성할수 있다고 잘 알려진 터라 이 작업에 딱 맞다고 생각했습니다.

 

파일을 받는 endpoint로 파일 데이터가 들어오면 이를 저장하고, 해당 파일의 이름으로 이미 변환된 pdf 파일이 없다면 queue에 파일 정보를 넣어 추후에 변환하도록 처리했습니다.

 

무한루프로 파일 변환하는 메소드

def convert():
  global isRunning
  while True:
    if (not fileQueue.empty()) and (not isRunning):
      isRunning = True
      data = fileQueue.get()
      filename, path, noticeId, url = data[0], data[1], data[2], data[3]
      #받아온 파일이 한글파일일 경우에만 작동
      pattern = re.compile('.*[.]hwp', re.IGNORECASE)
          hwptopdf(filename, path)
        if os.path.isfile(result_file):
          response = requests.patch(url, data=datas, headers=headers)
      isRunning = False
      
if __name__ == '__main__':
  convertThread = threading.Thread(target=convert, args=[])
  convertThread.daemon = True
  convertThread.start()
  app.run(debug=False)

 

파일을 변환하는 메소드를 개별스레드에 무한루프로 실행시켜 둡니다.

queue에 들어있는 파일들을 변환하는 함수는 서버가 시작될때 다른 스레드에 실행시킵니다.

 

문제점

기능은 정상적으로 작동 되었지만 몇가지 문제점이 걸렸습니다.

 

1. 파일을 queue 로 관리하는 부분을 직접 구현함.

2. 변환하는 메소드가 무한으로 실행됨.

3. 스레드로 구현한 코드가 보기에 깔끔하지 않음.

 

이러한 문제점들을 해결하기 위해서 async await 을 이용한 비동기로 처리를 하게되었습니다.

 

Flask -> Quart

Flask에서 async await을 사용하기 위해서 고군분투 했지만 제대로 실행되지 않고, Flask서버를 강제 종료 시키면 그제서야 비동기 함수들이 실행되는 등 문제가 발생했습니다.

 

asyncio를 제대로 사용하지 못한줄 알고 이에 대해서만 검색했는데, 결국 문제는 Flask에 있었고 async를 사용할 수 있게 개선된 Quart를 사용하여 문제를 해결하게 되었습니다.

 

@app.route('/hwptopdf', methods = ['POST'])
async def upload_file():
  f = (await request.files)['file']
  asyncio.ensure_future(convert(data))

핵심 메소드들의 기능은 그대로 유지하고, 각 메소드들에 async await 처리를 해줬습니다.

 

기존 queue에 파일을 저장하는 코드에 ensure_future 라는 메소드를 사용했습니다.

이 메소드는 메소드의 대상을 queue에 저장한 후 비동기 처리를 하게 해줍니다. 이를 통해 코드를 간결하게 처리할 수 있게 되었습니다.

 

 

후기

파이썬으로 무언가를 개발하는게 처음이었는데 조금 어색한 문법과 코드가 있었지만 개발하는데 정말 쉽고 직관적이었습니다.

특히 Flask 로 웹 서버를 생성하고 실행시키는게 너무 가볍고 편했습니다.

 

해당 기능 외에도 SQLite를 이용해 정상적으로 변환되지 않은 파일들을 저장하는 메소드도 구현했는데 이 또한 구현하는데 쉽고 간결했습니다.

 

얕고 좁게 파이썬을 사용했지만 파이썬을 사용하는 이유를 좀 알게된 계기가 되었던것 같습니다.

 

 

 

출처 : https://bebutae.tistory.com/255

 

파이썬으로 여러개의 한글 파일을 PDF 파일로 변환하기(hwp to pdf)

안녕하세요. 오늘은 파이썬을 이용해 한글 파일을 PDF 파일로 변환해보겠습니다. 파이썬을 활용해서 사무작업을 자동화 하는것은 직장인들에겐 정말 매력적인 소재일 것입니다. 저 역시 15개 가

bebutae.tistory.com

 


박준호 / 선임연구원

Junho Park / 서비스R&D팀

 

 

junho@userinsight.co.kr

728x90