Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

파이썬(Python)으로 MS Word(.docx) 문서 읽는 방법 완전 정리

들어가며

데이터 엔지니어로 일하다 보면 테스트 결과물을 마이크로소프트 워드(Word) 문서로 받는 경우가 허다합니다. 스크린샷, 링크, 그리고 아주 길고 긴 문단까지 온갖 정보가 하나의 워드 문서에 뒤섞여 들어 있죠. 워드는 본래 간단한 텍스트 문서여야 할 내용을 열 때마다 느리고 무거운 거대 파일로 만들어 버리고, 컴퓨터를 옮기면 서식이 어긋나는 고질적인 문제도 안고 있습니다.

하지만 나에게 불편한 도구가 다른 사람에게는 꼭 필요한 도구일 수 있다는 점도 인정해야 합니다.

본론으로 돌아가면, 파이썬의 워드 문서 지원은 생각보다 빈약합니다. 대표적인 python-docx 라이브러리조차 문서 생성과 파일 크기·제목 같은 기본 메타데이터 읽기 정도만 지원할 뿐, 문서의 실제 내용을 자유롭게 다루기는 어렵습니다. 결국 테스트 결과를 프로그램으로 처리하려면 직접 코드를 작성해야 했습니다.

이번 글에서는 인터넷에 공개된 샘플 워드 문서를 가져와 실제 내부 구조를 살펴보겠습니다. 사용할 샘플 파일의 주소는 다음과 같습니다.
https://file-examples-com.github.io/uploads/2017/02/file-sample_100kB.docx

구현 방법

1단계: 필요한 모듈 임포트

먼저 압축 해제와 네트워크 요청, 바이트 스트림 처리에 필요한 모듈을 임포트합니다.

from zipfile import ZipFile
from urllib.request import urlopen
from io import BytesIO

2단계: 원격 워드 문서를 열어 XML 내용 확인하기

이제 원격지의 워드 문서를 바이너리 파일 객체로 읽어옵니다. 이후 zipfile 라이브러리로 압축을 해제하고, 그 안에 들어 있는 XML 파일을 읽어 화면에 출력합니다.

file_url = 'https://file-examples-com.github.io/uploads/2017/02/file-sample_100kB.docx'

# 워드 문서 읽기
wordDocx = urlopen(file_url).read()
wordDocx = BytesIO(wordDocx)
document = ZipFile(wordDocx)

# XML 콘텐츠 가져오기
xml_content = document.read('word/document.xml')

# XML 콘텐츠 출력
print(xml_content.decode('utf-8'))

3단계: 실행 결과 분석

코드를 실행하면 word/document.xml 파일의 내용이 그대로 출력됩니다. 여기서 중요한 사실 하나를 짚고 넘어갑시다. .docx 파일은 사실 ZIP 형식의 압축 파일이며, 그 안에는 문서의 실제 내용이 담긴 여러 개의 XML 파일이 들어 있습니다. 출력 결과의 일부는 다음과 같습니다.

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<w:document xmlns:o='urn:schemas-microsoft-com:office:office'
xmlns:w='https://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:body>
<w:p>
<w:pPr><w:pStyle w:val='Title'/></w:pPr>
<w:r><w:t xml:space='preserve'>Lorem ipsum </w:t></w:r>
</w:p>
<w:p>
<w:pPr><w:pStyle w:val='Heading1'/></w:pPr>
<w:r><w:t>Lorem ipsum dolor sit amet...</w:t></w:r>
</w:p>
...
</w:body>
</w:document>

XML 구조를 보면 각 문단은 <w:p> 태그로, 실제 텍스트는 <w:t> 태그로 감싸져 있는 것을 알 수 있습니다. 굵게, 기울임, 밑줄 같은 서식 정보도 <w:rPr> 속성에 함께 기록됩니다.

응용: 본문 텍스트만 깔끔하게 추출하기

XML 전체가 아니라 순수한 텍스트만 필요하다면 정규표현식으로 <w:t> 태그의 내용만 골라낼 수 있습니다.

import re

text_list = re.findall(r'<w:t[^>]*>([^<]*)</w:t>', xml_content.decode('utf-8'))
print('\n'.join(text_list))

더 견고한 처리가 필요하다면 lxml이나 BeautifulSoup 같은 XML 파서를 사용해 네임스페이스를 고려해 파싱하는 것이 좋습니다.

핵심 정리

1. .docx 파일은 ZIP 압축 파일이므로 zipfile 모듈로 바로 열 수 있습니다.
2. 문서의 본문 내용은 내부의 word/document.xml에 저장되어 있습니다.
3. 실제 텍스트는 <w:t> 태그 안에 들어 있으므로, 이 태그만 추출하면 원하는 본문을 얻을 수 있습니다.
4. python-docx만으로 부족한 상황에서도 표준 라이브러리만으로 워드 문서를 충분히 읽어낼 수 있습니다.