본문 바로가기
업무자동화 with Python

[업무자동화 with Python] PDF문서내용 추출(PDFPlumber 활용) (3) (표 추출)

by CodeCrafter 2024. 10. 21.
반응형

 

이번에는 지난 시간에 이어서 pdf plumber를 활용해 표 내용을 추출하는 방법에 대해서 알아보겠습니다.

 

지난 시간에는 표 내용을 추출하는 기본적인 방법에 대해서 알아보았다면,

 

이번에는 병합된 셀 부분들로 인해 행 또는 열 간 구분이 잘 안되는 상황에 대해, 보다 세분화해서 표를 추출하는 방법에 대해서 알아보겠습니다.

 

[업무자동화 with Python] PDF문서내용 추출(PDFPlumber 활용) (2) (표 추출)

 

 

 

* 재현의 용이성을 위해 코드는 구글 코랩 무료버전에서 실행하였습니다.

 

 

1. PDFPlumber를 활용한 표 추출

- 이번 실습간에 활용할 데이터는 background-checks 이며, 아래 링크에서 다운로드 받으실 수 있습니다.

https://github.com/jsvine/pdfplumber/blob/stable/examples/pdfs/background-checks.pdf

 

pdfplumber/examples/pdfs/background-checks.pdf at stable · jsvine/pdfplumber

Plumb a PDF for detailed information about each char, rectangle, line, et cetera — and easily extract text and tables. - jsvine/pdfplumber

github.com

 

 

(위 pdf 파일을 다운로드 받아서 드라이브에 저장해주시면 되겠습니다)

 

- 먼저, 코랩의 드라이브를 임포트 해줍니다.

from google.colab import drive
drive.mount('/content/drive')

 

- 다음으로, pdfplumber를 설치해줍니다.

!pip install pdfplumber

 

 

- 이제 pdfplumber 라이브러리를 import 해줍니다.

import pdfplumber
pdf = pdfplumber.open("/content/drive/MyDrive/background-checks.pdf")

 

 

- 잘 import 되었는지 해당 pdf의 첫번째 페이지를 불러와봅니다.

p0 = pdf.pages[0]
im = p0.to_image()
im

 

* 이상없이 잘 불러와졌습니다.

 

반응형

 

 

- 데이터를 추출하기 전에 현재 상태의 pdf 파일에서 어떤 단위로 pdfplumber가 해당 표를 인식하고 있는지 debug_tablefinder를 통해서 알아보겠습니다.

 

im.reset().debug_tablefinder()

 

* 열 단위로는 세부적으로 잘 된 것 같지만, 행 단위로는  5개 단위로 행을 구분하는 선이 표시되어 있다보니, pdfplumber도 5개 단위를 하나의 행으로 인식하고 있음을 알 수 있습니다.

 

* 이렇게 한 뒤 데이터 처리 부분에서 후처리해도 되겠지만, 가급적이면 처음부터 1개의 행 단위로 잘 추출할 수 있게 하면 좋을 것 같습니다.

 

 

- 이를 위해 표(table)를 인식하는 setting을  수정해보겠습니다.

 

table_settings = {
    "vertical_strategy": "lines",
    "horizontal_strategy": "text",
    "snap_y_tolerance": 5,
    "intersection_x_tolerance": 15,
}

 

*vertical_strategy 는 열을 구분하는 기준을 제시하는 것으로 pdf에 표시된  선(line) 을 기준으로 나누어준다고 설정해줍니다.

*horizontal_strategy는 행을 구분하는 기준을 제시하는 것입니다. line으로 했을때 5개 행을 하나의 행으로 인식했기때문에 이를 개선하기 위해 문자(text)를 단위로 해준다면 각 문자 단위의 행으로 구분이 될 것입니다.

*snap_y_tolerance :  상단에서 서로 정확히 맞닿지 않는 몇 개의 가로선을 같은 세로 정렬로 스냅하는 기능을 말합니다. 즉, 조금 떨어진 가로선들이 같은 위치에 있는 것처럼 처리되도록 허용 범위를 설정하는 것입니다. 이를 통해 가로 선들이 약간 어긋 나있어도 같은 행에 속하게 해줍니다. 이번 실습에서는 5 pixel로 해보겠습니다.

*intersection_tolerance : 텍스트의 좌우 끝이 세로선과 완벽하게 맞닿지않는 문제를 해결하기 위한 설정으로, 위와 유사한 개념입니다. 이번 실습에서는 15 pixel로 해보겠습니다.

 

이제 위 설정을 바탕으로 debug_tablefinder를 실행해보겠습니다.

im.reset().debug_tablefinder(table_settings)

*결과는 예상했던 것처럼 text 단위의 행 간 구분이 가능해짐을 확인할 수 있습니다.

 

 

- 그러면 위 설정을 바탕으로 표 정보를 추출해보겠습니다. 확인을 위해 5개 행까지의 정보를 출력해보겠습니다.

 

table = p0.extract_table(table_settings)
for row in table[:5]:
    print(row)

 

* 잘 추출됨을 확인할 수 있습니다.

* 그렇지만 원치않는 header와 footer 또한 포함됨을 알 수 있습니다. 이 부분을 제거해보겠습니다.

 

 

 

- 표 정보가 포함된 행 정보부터 필요한 마지막 행까지를 core_table로 지정합니다.

core_table = table[4:4+56]

 

 

 

- 구분자 역할을 하는 점을 넣어서 core_table의 첫번째 그리고 마지막 행의 정보를 확인해봅니다. 구분자를 넣어서 확인해보면 비어있는 셀에 대한 정보까지 확인할 수 있어서 더 정확하게 검산할 수 있습니다.

" • ".join(core_table[0])

 

 

이상없게 잘 되었음을 확인할 수 있습니다.

반응형

댓글