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

한/글 없이 hwpx 파일의 표를 pd.DataFrame으로 추출하는 방법

by 일코 2022. 2. 2.

안녕하세요?

일상의 코딩, 일코입니다.

 

hwpx 포맷이 만들어진지 벌써 10년도 훌쩍 넘었습니다.

한컴오피스에서는, 데이터 추출이 번거로운 기존의 hwp 포맷 대신 

machine-readable한 hwpx 포맷을 사용해줄 것을 정부 및 기관에 요청한 바 있었는데요.

 

실제로 hwpx 포맷이 어떻게 쓰이는지 한 번 간단히 알아보고,

한/글 프로그램 없이도

한/글 문서의 표를 판다스 데이터프레임으로 추출하는

간단한 예제를

여러분께 소개하려고 합니다.

 

우선 추출하고자 하는 한/글 문서는 아래와 같습니다.

df.hwpx 문서

예제로 사용할 hwpx문서(표) 안에 들어 있는 데이터는

seaborn으로 데이터 시각화 연습하실 때

한 번쯤은 사용해보셨을 법한,

seaborn_tips_dataset입니다.

 

데이터 출처 : seaborn_tips_dataset | Kaggle

 

seaborn_tips_dataset

 

www.kaggle.com

예제를 간편하게 따라해 보고 싶으신 분들은

아래의 한/글 문서를 다운로드한 후 따라와주시기 바랍니다.

df.hwpx
0.10MB


 

우선 hwpx가 왜 machine-readable 한 건지

한 번 알아보겠습니다.

 

df.hwpx 문서를 다운로드하셨으면

하나 복사하신 후에

확장자인 hwpx를 zip으로 바꾼 후

압축을 해제해 보시기 바랍니다.

hwpx 파일의 정체는 ZIP과 XML !?

압축을 풀면 대략 아래와 같은 구조입니다.

이미지를 제외하면, 모두 메모장으로 읽을 수 있는 포맷입니다.

 

우리가 추출할 텍스트 데이터는

Contents/section0.xml 파일 안에 들어 있습니다.

71번 라인에 첫 번째 셀의 값인 "total_bill"이 보이네요. (리포맷 상태)

 

저도 XML 문서를 파싱하는 게 익숙하지는 않아서

표의 데이터를 추출해서 df로 변환하는 예제만 간단히 보여드리겠습니다.

 


 

① 임포트할 모듈은 딱 다섯 개입니다. os, shutil, xml, zipfile, pandas

 

② hwpx 파일 경로를 파이썬에 입력합니다.

 

③ hwpx 파일의 압축을 해제합니다.

 

④ 생성된 폴더 안의 Contents/Section0.xml 파일을 xml.etree.ElementTree로 열어줍니다.

 

⑤ 문서 안의 표 태그를 가져옵니다. (현재 문서에는 총 1개입니다.)

 

⑥ 표의 열 갯수와 행 갯수 정보를 가져옵니다. (pd.reshape시 활용)

 

⑦ 표의 데이터를 1차원 리스트로 쭉 빼옵니다.

 

⑧ 데이터프레임으로 변환, reshape 후 dtype 설정

 

⑨ (마지막으로) 압축해제된 폴더 삭제

끝.

 

한 번 플롯은 그려보고 마칠까요?

바이올린플롯을 그려보았습니다.

"금요일만 되면 남자들이 크게 쏘는" 씁쓸한 경향을 보이는 플롯이네요.

직접 한 번 해 보시기 바랍니다...

 

위에서 작성한 코드입니다. 참고하시기 바랍니다.

#1
import os
import shutil
import xml.etree.ElementTree as ET
import zipfile

import pandas as pd


#2
hwpx_file = r"C:\Users\smj02\Desktop\df.hwpx"
os.chdir(os.path.dirname(hwpx_file))
path = os.path.join(os.getcwd(), "hwpx")


#3
with zipfile.ZipFile(hwpx_file, 'r') as zf:
    zf.extractall(path=path)


#4
tree = ET.parse(os.path.join(os.getcwd(), "hwpx", "Contents", "section0.xml"))
root = tree.getroot()


#5
tbl_list = []
for child in root.iter():
    if child.tag.endswith("}tbl"):
        tbl_list.append(child)


#6
tbl = tbl_list[0]
tbl_cols = int(tbl.attrib["colCnt"])
tbl_rows = int(tbl.attrib["rowCnt"])


#7
data = []
for i in tbl.iter():
    if i.tag.endswith("}t"):
        data.append(i.text)


#8
df = pd.DataFrame(data)
df = pd.DataFrame(data=df.iloc[tbl_cols:, :].values.reshape(-1, tbl_cols), columns=df.iloc[:tbl_cols, 0].values)
df = df.astype({"total_bill": "float", "tip": "float", "size": "int"})


#9
shutil.rmtree(path)

# 끝.



### 플로팅
df.describe()

import seaborn as sns
import matplotlib.pyplot as plt

plt.style.use('ggplot')
sns.catplot(x="day", y="total_bill", hue="sex", kind="violin", data=df)

 

 


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

 

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

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

www.inflearn.com

 

댓글