table extraction은 문서로부터 표를 양식 그대로 추출하는 기술에 대해 연구하는 분야이다.
이 기술은 주로 데이터 과학자들이나 연구자들에게 유용한데, 문헌이나 문서들로부터 표 형식의 데이터를 추출해서 가공 가능한 포맷 (예를 들면 csv나 dataframe) 등으로 변환하는 기술은 데이터로부터 다양한 인사이트를 얻는데 도움이 되기 때문이다.
파이썬을 사용해서 표를 추출하는 방법으로는 크게 3가지 툴이 추천되곤한다.
- pdfplumber
- camelot
- tabula-py
개인적으로 이들 중에는 pdfplumber가 가장 높은 성능을 보였으며, 그 다음으로는 tabula-py가 좋았고, camelot이 가장 추출률이 좋지 않았었다.
이제 예제 코드와 함께 각 툴들에 대해서 소개를 해보고자 한다.
(참고로 해당 툴들은 모두 텍스트 추출 기반으로 작동하기 때문에 스캔된 문서와 같이 이미지로 구성된 문서들은 작동하지 않는다)
1. pdfplumber
설치방법:
pip install pdfplumber
pdfplumber는 기본적으로 Anssi Nurminen의 석사 논문을 기반으로 구현된 라이브러리이다.
참고로 해당 논문은 table extraction 분야에서 현재까지도 가장 널리 인용되고 있는 논문이니, 관심이 있으면 꼭 정독하기를 추천한다.
아래는 pdf 문서 내에 있는 모든 "표 (table)"라고 인식되어지는 데이터들을 출력하는 코드이다. 또한, 디버깅을 위해 각 페이지마다 텍스트를 추출해서 각 텍스트 별로 bounding box를 추가해서 이미지 파일로 저장하는 기능 역시 구현하였다.
import pdfplumber
import json
TABLE_SETTINGS = {
"vertical_strategy": "lines",
"horizontal_strategy": "lines",
"explicit_vertical_lines": [],
"explicit_horizontal_lines": [],
"snap_tolerance": 3,
"snap_x_tolerance": 2,
"snap_y_tolerance": 2,
"join_tolerance": 3,
"join_x_tolerance": 3,
"join_y_tolerance": 3,
"edge_min_length": 3,
"min_words_vertical": 3,
"min_words_horizontal": 1,
"intersection_tolerance": 3,
"intersection_x_tolerance": 3,
"intersection_y_tolerance": 3,
"text_tolerance": 3,
"text_x_tolerance": 3,
"text_y_tolerance": 3,
}
def extract_data_from_pdf(pdf_path):
with pdfplumber.open(pdf_path) as pdf:
pages = pdf.pages
index = 1
for page in pages:
# 해당 페이지 내의 모든 텍스트를 찾아서 bounding box 추가 후 이미지로 저장
im = page.to_image(resolution=150)
im.draw_rects(page.extract_words())
im.save(f"output_{i}.png", format="PNG")
i += 1
# 페이지 내의 테이블들을 모두 찾기
tables = page.find_tables(table_settings=TABLE_SETTINGS)
# 추출된 표들을 하나씩 출력하기
for table in tables:
print(table)
if __name__ == '__main__':
extract_data_from_pdf('test.pdf')
pdfplumber는 기본적으로 높은 수준의 정확도를 보여서 다른 라이브러리들로는 추출이 안되는 표들 역시 적절히 추출하는 높은 성능을 보인다. 추출이 잘 안되는 경우가 2가지 있는데 "셀 병합이 많은 표"나 "여러 페이지에 걸쳐져 있는 표" 등에 대해서는 잘 작동하지 못하는 모습을 보인다. 그러나 이러한 항목들은 다른 라이브러리에서도 잘 해결하지 못하는 항목들이다.
"여러 페이지에 걸쳐져 있는 표"의 경우에는 추가적인 알고리즘을 코딩해서 문제를 해결해야 한다. 이 "알고리즘"은 기본적으로 pdf 문서마다 특성이 조금씩 다르기 때문에 일반화시키기는 조금 어려움이 있다. 보통은 추출된 표의 셀들의 좌표에 대한 메타데이터를 비교 분석하는 코드를 구현해서 문제를 해결하는 접근법이 가장 많이 사용된다고 한다.
2. camelot
설치방법:
pip install "camelot-py[base]"
camelot의 최대 장점은 "controllable"한 특성이라고 할 수 있다.
테이블 추출 시, 각 테이블의 추출 정확도를 함께 표현해줘서 accuracy threshold 기반의 필터링이 가능하며, 추출된 테이블에 대해 Lattice 방법을 통한 셀 병합 탐지 등의 기능을 제공한다.
아쉬운 점이라면, pdfplumber에 비해 추출을 못하는 경우가 다소 있다는 점일 것이다. (pdf 내의 표를 찾지 못해서 데이터를 추출하지 못하는 경우가 pdfplumber보다 많음)
아래는 camelot을 통한 테이블 추출 예제 코드이다.
import camelot
def camelot_extract(pdf_path):
tables = camelot.read_pdf(pdf_path, pages="all")
print(tables)
for i, table in enumerate(tables):
print(f"Table {i + 1}:")
print(table.df)
print("\n")
if __name__ == '__main__':
camelot_extract('test.pdf')
3. tabula-py
설치 방법:
# tabula-py는 tabula-java를 기반으로 포팅된 라이브러리이다.
# 따라서, Java 8 이상 버전의 자바가 설치되어 있어야 한다.
# jpype는 jvm 라이브러리를 파이썬에서 호출할 수 있게 도와주는 기능을 제공. (함께 설치해야 정상 작동)
pip install "tabula-py[jpype]"
tabula-py는 tabula-java의 파이썬 포팅 버전으로, pdf에서 인식된 표들을 dataframe으로 변환해주는 기능을 제공한다.
tabula-java라는 JVM 기반 라이브러리를 사용하기 때문에 준수한 성능을 보장한다는 특징을 가진다.
개인적인 실험 결과로는 camelot보다는 높은 성능을 보이나 pdfplumber보다는 낮은 성능을 보인다는 점이 아쉬웠다.
아래는 pdf에서 표들을 추출해서 출력하는 예제 코드이다.
import tabula
def tabula_extract_to(pdf_path, output_path):
"""표를 추출한 뒤, 각각 csv 파일로 저장"""
tabula.convert_into(pdf_path, output_path, output_format="csv", pages='all', lattice=True)
def tabula_extract(pdf_path):
"""표를 추출한 뒤, 각각 print"""
dfs = tabula.read_pdf(pdf_path, pages='all', lattice=True)
for i, df in enumerate(dfs):
print(f"Table {i + 1}:")
print(df)
print("\n")
위의 예제에서 "lattice=True" 옵션을 사용하면 하나의 셀이 여러 줄로 이루어져 있는 경우 등을 적절히 처리할 수 있다.
'Python' 카테고리의 다른 글
파이썬에서 더 빠른 JSON serialization 사용하기 (0) | 2024.01.22 |
---|---|
python psutil을 사용해서 간단한 모니터링 스크립트 구축하기 (0) | 2024.01.02 |
Python gc 튜닝을 통한 성능 개선 (Flask 기반 예시 코드) (0) | 2023.10.14 |
pip-audit과 GitHub Actions를 활용한 취약 라이브러리 탐지 파이프라인 구축하기 (0) | 2023.10.09 |
소스코드 레벨에서 비교하는 Python List와 Set의 차이 (2) | 2023.10.09 |