본문 바로가기
아래아한글 자동화/python+hwp 중급

[QnA]각각의 페이지를 한 개의 hwp파일로 저장하고, 제목은 표 안에서 추출하는 코드를 작성/컴파일해서 실행파일 보내주세요.

by 일코 2021. 5. 19.
선생님!! 안녕하세요~~
오늘 유튜브 영상보구 문의드리는 구독자(오늘 구독 시작^^)입니다.
우선 바쁘실텐데 이렇게 도움을 주셔서 감사합니다.
말씀드린 것처럼.. 다음주 정도 정리하고 있는 한글파일을 기준으로
각 페이지별로 나누어 파일 따로 저장해야 하는 일을 해야 합니다.
한글 내에서의 기능으로 처리한다면 결국 페이지만큼 수작업(노가다)를 해야하는 상황이라
유튜브를 검색하던 중 딱 선생님의 처리 방법이 유일한 해결책일거라는 생각이 들더라구요~~
단... 파이썬? 이런 코딩작업은 한번도 해본적이 없고...  제가 배워서 하기에는 기약도 없을것 같아..우선 
프로그램이 없더라도 코딩된 어떤 실행파일을 실행하면 원하는 결과만 얻도록 도움을 부탁드립니다^^
제가 작업중인 샘플 한글 파일을 첨부와 같이 송부드리고.. 저장방식은
1. 원본 한글파일과 동일한 폴더를 생성하고
2. 각 페이지별 개별 파일명은...가능하다면.. 각페이지의 증빙자료 자료명 으로 저장
  만약 불가능하면 1페이지- 증빙_1, 2페이지- 증빙_2.....이런 방식으로 개별저장 으로 부탁드립니다.

감사합니다.

문의자료_페이지별 개별저장.hwp
0.10MB

직접 실행해 보고 싶은 분들은 위의 파일을 다운받으시면 됩니다.

 

페이지별로 나누어 hwp파일을 따로 저장하는 방식은, 2018버전을 기점으로 엄청나게 간편해졌습니다. 바로 "쪽 복사" 기능 덕분인데요. 한컴네오 버전까지는 쪽을 완벽하게 복사하기 위해 여백과 배경을 체크하는 등 번거로운 작업을 하거나, 혹은 문서 전체를 복사한 후에 해당 쪽만 남기고 모두 지우는 등의 작업을 거쳐야만 메타정보가 오염(?)되지 않을 수 있었습니다.

하지만 지금은 쪽 관련 명령어 "CopyPage", "DeletePage", "PastePage" 가 생긴 덕분에... 이 부분을 훨씬 수월하게 작업할 수 있게 되었습니다. 예를 들면, 아래의 코드는 현재 페이지를 새 탭에 복사 후 "다른이름으로 저장"하고, 원래 문서에서는 페이지를 삭제하는 방식으로, 모든 페이지를 각각 개별의 hwp파일로 저장하는 코드의 일부입니다.

for i in range(hwp.PageCount):  # 페이지 수만큼 반복
    제목 = 제목문자열_추출(hwp)
    hwp.Run("CopyPage")  # 현재쪽 복사
    hwp.Run("DeletePage")  # 현재쪽 삭제
    hwp.XHwpDocuments.Add(isTab=True)  # 새 탭으로 빈 문서 열기
    hwp.Run("PastePage")  # 새 탭에 붙여넣기
    hwp.Run("MoveTopLevelBegin")  # 문서최상단으로 이동 == hwp.MovePos(2)
    hwp.Run("DeletePage")  # 현재쪽(빈 페이지) 삭제
    hwp.SaveAs(os.path.join(filepath, 제목 + ".hwp"))  # 기존 파일명+_n.hwp 로 저장
    hwp.XHwpDocuments.Item(0).Close(isDirty=False)  # 탭 닫기
    sleep(0.2)  # 0.1초 쉬어줌(꼭 필요)

"복사" 이외의 다른 부분, 이를테면 페이지별 용지/여백정보를 모두 추출하는 코드도 이제는 필요없게 되었습니다. 다른 부분을 신경쓰지 않아도 되어 자동화 코드가 훨씬 간편해진 느낌입니다. 참고로 아래의 코드는 문서의 페이지별 여백을 리스트 안에 사전으로 담는 함수입니다.

def 페이지별_여백추출(hwp):
    """
    모든 페이지의 여백정보를 저장한 페이지별 dict의 list를 반환하는 함수.
    "PageSetup", "PageDef" 및 "PaperWidth" 등의 문자열은 API문서에서 검색가능
    :param hwp: 한/글 오브젝트
    :return: 2중dict.
    """
    margin_dict = {}  # 빈 사전 생성
    hwp.MovePos(2)  # 문서의 시작으로 이동
    for page in range(hwp.PageCount):  # 모든 페이지번호마다 반복하면서
        Act = hwp.CreateAction("PageSetup")  # 페이지설정 정보를 열고
        Set = Act.CreateSet()  # 빈 파라미터셋(그릇?) 생성
        Act.GetDefault(Set)  # 현재 쪽의 여백값을 파라미터셋에 채음
        margin_dict[page] = {
            "PaperWidth": Set.Item("PageDef").Item("PaperWidth"),  # 용지너비 추출
            "PaperHeight": Set.Item("PageDef").Item("PaperHeight"),  # 용지높이 추출
            "LeftMargin": Set.Item("PageDef").Item("LeftMargin"),  # 왼쪽여백
            "RightMargin": Set.Item("PageDef").Item("RightMargin"),  # 오른쪽여백
            "TopMargin": Set.Item("PageDef").Item("TopMargin"),  # 오른쪽여백
            "BottomMargin": Set.Item("PageDef").Item("BottomMargin"),  # 오른쪽여백
            "HeaderLen": Set.Item("PageDef").Item("HeaderLen"),  # 오른쪽여백
            "FooterLen": Set.Item("PageDef").Item("FooterLen"),  # 오른쪽여백
            "GutterLen": Set.Item("PageDef").Item("GutterLen"),  # 제본길이
            "GutterType": Set.Item("PageDef").Item("GutterType"),  # 제본타입
            "Landscape": Set.Item("PageDef").Item("Landscape")  # 종횡
        }
        hwp.Run("MovePageDown")  # 다음 페이지로 이동
    return margin_dict

 

 

한컴네오 이하의 버전이라면 페이지 복사를 위해 이런 방식으로 여백정보를 얻어와야겠죠. 저장한 정보를 적용하는 함수는 아래와 같습니다.

def 새_여백구역_추가(hwp, margin_dict, ApplyTo=4):
    """
    문서 하단에 새 여백구역을 추가하는 함수
    :param hwp: hwp오브젝트
    :param margin_dict: 여백과 종횡, 용지설정이 들어있는 사전객체. 하단의 "페이지별_여백추출"의 원소
    :param ApplyTo: 4는 새 구역으로 여백설정 추가(기본), 3은 문서전체의 여백을 수정하도록 함
    :return: 반환값 없음
    """
    hwp.HAction.GetDefault("PageSetup", hwp.HParameterSet.HSecDef.HSet)
    hwp.HParameterSet.HSecDef.PageDef.PaperWidth = margin_dict["PaperWidth"]  # 용지너비
    hwp.HParameterSet.HSecDef.PageDef.PaperHeight = margin_dict["PaperHeight"]  # 용지높이
    hwp.HParameterSet.HSecDef.PageDef.LeftMargin = margin_dict["LeftMargin"]  # 왼쪽여백
    hwp.HParameterSet.HSecDef.PageDef.RightMargin = margin_dict["RightMargin"]  # 오른쪽여백
    hwp.HParameterSet.HSecDef.PageDef.TopMargin = margin_dict["TopMargin"]  # 오른쪽여백
    hwp.HParameterSet.HSecDef.PageDef.BottomMargin = margin_dict["BottomMargin"]  # 오른쪽여백
    hwp.HParameterSet.HSecDef.PageDef.HeaderLen = margin_dict["HeaderLen"]  # 오른쪽여백
    hwp.HParameterSet.HSecDef.PageDef.FooterLen = margin_dict["FooterLen"]  # 오른쪽여백
    hwp.HParameterSet.HSecDef.PageDef.GutterLen = margin_dict["GutterLen"]  # 제본길이
    hwp.HParameterSet.HSecDef.PageDef.GutterType = margin_dict["GutterType"]  # 제본타입
    hwp.HParameterSet.HSecDef.PageDef.Landscape = margin_dict["Landscape"]  # 종횡
    hwp.HParameterSet.HSecDef.HSet.SetItem("ApplyClass", 24)
    hwp.HParameterSet.HSecDef.HSet.SetItem("ApplyTo", ApplyTo)  # 4는 새 구역으로, 3은 문서전체
    hwp.HAction.Execute("PageSetup", hwp.HParameterSet.HSecDef.HSet)

사족이 너무 길었네요. 하여튼 2018, 2020에서는 페이지 관련 작업시 코드가 훨씬 간편해집니다.

아래는 완성한 코드입니다. 문서의 모든 페이지를 각각 다른 이름의 hwp파일로 저장합니다. 저장 파일명은 페이지 상단 표의 특정 셀 범위의 문자열입니다.

# 아래아한글 파일을 열어서 각각의 페이지를 한 개의 한글파일로 저장하는 프로그램입니다.
# 분할된 파일은 해당 한글파일 경로에 result 폴더를 생성한 후 저장합니다.

import os  # 파일과 폴더이름을 다루기 편한 모듈
from tkinter import Tk  # 내장 GUI, 실행이 간편함
from tkinter.filedialog import askopenfilename  # 1개의 파일 선택창
from time import sleep  # 잠시 쉬어주기 위한 함수
import win32com.client as win32  # 한/글을 열기 위한 모듈
import pyperclip as cb


def 제목문자열_추출(hwp):
    hwp.InitScan()  # 문서 탐색 시작
    del_num = 0
    while True:
        result = hwp.GetText()  # 문단별로 텍스트와 상태코드 얻기
        if result[0] == 1:  # 상태코드1 == 문서 끝에 도달하면
            break  # while문 종료
        elif result[0] == 4 and result[1].startswith("증빙자료 번호"):  # 상태코드3:표 내부, 4:표 안으로 진입,
            hwp.MovePos(201)  # 탐색된 위치로 캐럿 이동
            hwp.HAction.Run("TableCellBlock")
            hwp.HAction.Run("TableLowerCell")
            hwp.HAction.Run("Copy")
            number = cb.paste().strip().replace(")", "_")
            hwp.HAction.Run("TableRightCell")
            hwp.HAction.Run("Copy")
            hwp.HAction.Run("Cancel")
            title = cb.paste().strip()
            break
        else:  # 그 외에는
            pass  # 그냥 넘어감
    return (number+title).strip()


if __name__ == '__main__':
    root = Tk()  # GUI 실행하고
    # 소스 한/글파일 선택 -> source_hwp에 전체경로 지정
    source_hwp = askopenfilename(title="아래아한글 파일을 선택해주세요.",
                                 initialdir=os.getcwd(),
                                 filetypes=[("아래아한글파일", "*.hwp *.hwpx")])
    root.destroy()  # GUI 종료

    filename = os.path.basename(source_hwp)  # hwp파일의 전체경로 중 파일이름만 추출
    filepath = os.path.join(os.path.dirname(source_hwp))  # hwp파일의 전체경로 중 경로만 추출
    os.chdir(filepath)  # 해당경로로 이동
    try:
        os.mkdir(filename.rsplit(".", maxsplit=1)[0])  # result 폴더 생성
    except FileExistsError:  # 같은 이름의 폴더가 이미 존재하면
        pass  # 패스
    os.chdir(filename.rsplit(".", maxsplit=1)[0])  # result 폴더로 이동
    filepath = os.getcwd()  # result 폴더의 경로를 filepath 변수로 지정

    hwp = win32.gencache.EnsureDispatch("HWPFrame.HwpObject")  # 한/글 프로그램 실행
    hwp.RegisterModule("FilePathCheckDLL", "FilePathCheckerModule")  # 보안승인모듈 활성화
    hwp.Open(source_hwp)  # 파일 열기
    hwp.XHwpWindows.Item(0).Visible = False  # 백그라운드작업, True로 바꾸면 숨김해제됨
    hwp.MovePos(2)  # 문서 처음으로 이동
    page_num = hwp.PageCount  # 전체 페이지 수를 page_num에 저장

    for i in range(page_num):  # 페이지 수만큼 반복
        제목 = 제목문자열_추출(hwp)
        hwp.Run("CopyPage")  # 현재쪽 복사
        hwp.Run("DeletePage")  # 현재쪽 삭제
        hwp.XHwpDocuments.Add(isTab=True)  # 새 탭 열기
        hwp.Run("PastePage")  # 붙여넣기
        hwp.Run("MoveTopLevelBegin")  # 문서최상단으로 이동 == hwp.MovePos(2)
        hwp.Run("DeletePage")  # 현재쪽 삭제
        hwp.SaveAs(os.path.join(filepath, 제목 + ".hwp"))  # 기존 파일명+_n.hwp 로 저장
        hwp.XHwpDocuments.Item(0).Close(isDirty=False)  # 탭 닫기
        sleep(0.2)  # 0.1초 쉬어줌(꼭 필요)

    # 완료시 팝업 하나 띄워주기
    msgbox = hwp.XHwpMessageBox
    msgbox.string = f"총 {page_num}개의 파일로 \r\n분할작업이 완료되었습니다."
    msgbox.DoModal()

    # 한/글 닫기
    hwp.XHwpDocuments.Item(0).Close(isDirty=False)  # 원래 문서도 저장하지 않고 닫기
    hwp.Quit()  # 한/글 프로그램 종료

여백과 주석 포함 80줄 정도의 짧은 코드입니다.


이 코드를 exe파일로 컴파일하는 방법 중 가장 간편한 방법은 파이인스톨러(pyinstaller)를 사용하는 것입니다.

커맨드프롬프트에서 "pip install pyinstaller"로 파이인스톨러를 설치하시면 됩니다.

pyinstaller 설치화면

 실행방법은 파이썬파일과 아이콘파일(필요시)이 들어있는 폴더로 이동해서

"pyinstaller 파일명 -F -w --icon=face.ico" 방식으로 실행하시면 됩니다.

파라미터를 간단히 설명드리면, -F는 1개의 파일로 컴파일, -w 는 콘솔창이 나타나지 않게, --icon으로 아이콘을 넣어줍니다.

실행화면은,

현재폴더 하위에 build와 dist폴더가 생성되었고, dist 안에 실행파일이 있습니다.

컴파일도 이렇게 간단하답니다.

내친김에 실행까지 해볼까요?

페이지별로 각각의 인덱스와 제목을 붙여 저장중

이번 포스팅은 여기서 마칩니다.

보다 많은 분들께 도움이 되었으면 하는 바람입니다.

행복한 하루 되세요!

 


국내 유일의 파이썬+한컴오피스 업무자동화 입문강의

 

움짤로 빠르게 배우는 파이썬-아래아한글 자동화 레시피 - 인프런 | 강의

파이썬으로 아래아한글을 다루는 짧은 예제코드들을 소개하고, 중간중간의 결과를 GIF로 보여드립니다. 동영상 강의가 아니지만 오히려 빠르게 배울 수 있고, 따라하기도 쉽습니다., - 강의 소개

www.inflearn.com

 

댓글