在本文中将应用 Python 演示如何解析文档 (如 pdf) 并提取文本,图形,表格等信息。
文档解析波及查看文档中的数据并提取有用的信息。它能够通过自动化缩小了大量的手工工作。一种风行的解析策略是将文档转换为图像并应用计算机视觉进行辨认。而文档图像剖析 (Document Image Analysis) 是指从文档的图像的像素数据中获取信息的技术,在某些状况下,预期后果应该是什么样的没有明确的答案(文本、图像、图表、数字、表格、公式……)。
OCR (Optical Character Recognition,光学字符识别)是通过计算机视觉对图像中的文本进行检测和提取的过程。它是在第一次世界大战期间创造的,过后以色列科学家伊曼纽尔·戈德堡 (Emanuel Goldberg) 创造了一台能读取字符并将其转换为电报代码的机器。到了当初该畛域曾经达到了一个非常复杂的程度,混合图像处理、文本定位、字符宰割和字符识别。基本上是一种针对文本的对象检测技术。
在本文中我将展现如何应用 OCR 进行文档解析。我将展现一些有用的 Python 代码,这些代码能够很容易地用于其余相似的状况(只需复制、粘贴、运行),并提供残缺的源代码下载。
这里将以一家上市公司的 PDF 格局的财务报表为例(链接如下)。
https://s2.q4cdn.com/47000403…(As-Filed).pdf
检测和提取该 PDF 中的 文本、图形和表格
环境设置
文档解析令人烦恼的局部是,有太多的工具用于不同类型的数据(文本、图形、表格),但没有一个可能完满地工作。上面是一些最风行办法和软件包:
- 以文本形式解决文档: 用 PyPDF2 提取文本,用 Camelot 或 TabulaPy 提取表,用 PyMuPDF 提取图形。
- 将文档转换为图像(OCR): 应用 pdf2image 进行转换,应用 PyTesseract 以及许多其余的库提取数据,或者只应用 LayoutParser。
兴许你会问:“为什么不间接解决 PDF 文件,而要把页面转换成图像呢?”你能够这么做。这种策略的次要毛病是编码问题: 文档能够采纳多种编码(即 UTF-8、ASCII、Unicode),因而转换为文本可能会导致数据失落。因而为了防止产生该问题,我将应用 OCR,并用 pdf2image 将页面转换为图像,须要留神的是 PDF 渲染库 Poppler 是必须的。
# with pip
pip install python-poppler
# with conda
conda install -c conda-forge poppler
你能够很容易地读取文件:
# READ AS IMAGE
import pdf2imagedoc = pdf2image.convert_from_path("doc_apple.pdf")
len(doc) #<-- check num pages
doc[0] #<-- visualize a page
跟咱们的截图截然不同,如果想将页面图像保留在本地,能够应用以下代码:
# Save imgs
import osfolder = "doc"
if folder not in os.listdir():
os.makedirs(folder)p = 1
for page in doc:
image_name = "page_"+str(p)+".jpg"
page.save(os.path.join(folder, image_name), "JPEG")
p = p+1
最初,咱们须要设置将要应用的 CV 引擎。LayoutParser 仿佛是第一个基于深度学习的 OCR 通用包。它应用了两个驰名的模型来实现工作:
Detection: Facebook 最先进的指标检测库(这里将应用第二个版本 Detectron2)。
pip install layoutparser torchvision && pip install "git+https://github.com/facebookresearch/detectron2.git@v0.5#egg=detectron2"
Tesseract:最驰名的 OCR 零碎,由惠普公司在 1985 年创立,目前由谷歌开发。
pip install "layoutparser[ocr]"
当初曾经筹备好开始 OCR 程序进行信息检测和提取了。
import layoutparser as lp
import cv2
import numpy as np
import io
import pandas as pd
import matplotlib.pyplot as plt
检测
(指标)检测是在图片中找到信息片段,而后用矩形边框将其突围的过程。对于文档解析,这些信息是题目、文本、图形、表……
让咱们来看一个简单的页面,它蕴含了一些货色:
这个页面以一个题目开始,有一个文本块,而后是一个图和一个表,因而咱们须要一个经过训练的模型来辨认这些对象。侥幸的是,Detectron 可能实现这项工作,咱们只需从这里抉择一个模型,并在代码中指定它的门路。
我将要应用的模型只能检测 4 个对象(文本、题目、列表、表格、图形)。因而,如果你须要辨认其余货色(如方程),你就必须应用其余模型。
## load pre-trained model
model = lp.Detectron2LayoutModel(
"lp://PubLayNet/mask_rcnn_X_101_32x8d_FPN_3x/config",
extra_config=["MODEL.ROI_HEADS.SCORE_THRESH_TEST", 0.8],
label_map={0:"Text", 1:"Title", 2:"List", 3:"Table", 4:"Figure"})
## turn img into array
i = 21
img = np.asarray(doc[i])
## predict
detected = model.detect(img)
## plot
lp.draw_box(img, detected, box_width=5, box_alpha=0.2,
show_element_type=True)
后果蕴含每个检测到的布局的细节,例如边界框的坐标。依据页面上显示的程序对输入进行排序是很有用的:
## sort
new_detected = detected.sort(key=lambda x: x.coordinates[1])
## assign ids
detected = lp.Layout([block.set(id=idx) for idx,block in
enumerate(new_detected)])## check
for block in detected:
print("---", str(block.id)+":", block.type, "---")
print(block, end='\n\n')
实现 OCR 的下一步是正确提取检测到内容中的有用信息。
提取
咱们曾经对图像实现了宰割,而后就须要应用另外一个模型解决分段的图像,并将提取的输入保留到字典中。
因为有不同类型的输入(文本,题目,图形,表格),所以这里筹备了一个函数用来显示后果。
'''{'0-Title':'...','1-Text':'...','2-Figure': array([[ [0,0,0], ...]]),'3-Table': pd.DataFrame,
}
'''
def parse_doc(dic):
for k,v in dic.items():
if "Title" in k:
print('\x1b[1;31m'+ v +'\x1b[0m')
elif "Figure" in k:
plt.figure(figsize=(10,5))
plt.imshow(v)
plt.show()
else:
print(v)
print(" ")
首先看看文字:
# load model
model = lp.TesseractAgent(languages='eng')
dic_predicted = {}
for block in [block for block in detected if block.type in ["Title","Text"]]:
## segmentation
segmented = block.pad(left=15, right=15, top=5,
bottom=5).crop_image(img)
## extraction
extracted = model.detect(segmented)
## save
dic_predicted[str(block.id)+"-"+block.type] =
extracted.replace('\n',' ').strip()
# check
parse_doc(dic_predicted)
再看看图形报表
for block in [block for block in detected if block.type == "Figure"]:
## segmentation
segmented = block.pad(left=15, right=15, top=5,
bottom=5).crop_image(img)
## save
dic_predicted[str(block.id)+"-"+block.type] = segmented
# check
parse_doc(dic_predicted)
下面两个看着很不错,那是因为这两种类型绝对简略,然而表格就要简单得多。尤其是咱们上看看到的的这个,因为它的行和列都是进行了合并后产生的。
for block in [block for block in detected if block.type == "Table"]:
## segmentation
segmented = block.pad(left=15, right=15, top=5,
bottom=5).crop_image(img)
## extraction
extracted = model.detect(segmented)
## save
dic_predicted[str(block.id)+"-"+block.type] = pd.read_csv(io.StringIO(extracted) )
# check
parse_doc(dic_predicted)
正如咱们的意料提取的表格不是很好。好在 Python 有专门解决表格的包,咱们能够间接解决而不将其转换为图像。这里应用TabulaPy 包:
import tabula
tables = tabula.read_pdf("doc_apple.pdf", pages=i+1)
tables[0]
后果要好一些,然而名称依然错了,然而成果要比间接 OCR 好的多
总结
本文是一个简略教程,演示了如何应用 OCR 进行文档解析。应用 Layoutpars 软件包进行了整个检测和提取过程。并展现了如何解决 PDF 文档中的文本,数字和表格。
本文的源代码:
https://avoid.overfit.cn/post/2a9b8de5583b46f8bedf7387cf8f8693
作者:Mauro Di Pietro