在本文中将应用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 pippip install python-poppler# with condaconda install -c conda-forge poppler

你能够很容易地读取文件:

# READ AS IMAGEimport pdf2imagedoc = pdf2image.convert_from_path("doc_apple.pdf")len(doc) #<-- check num pagesdoc[0]   #<-- visualize a page

跟咱们的截图截然不同,如果想将页面图像保留在本地,能够应用以下代码:

# Save imgsimport osfolder = "doc"if folder not in os.listdir():    os.makedirs(folder)p = 1for 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 lpimport cv2import numpy as npimport ioimport pandas as pdimport matplotlib.pyplot as plt

检测

(指标)检测是在图片中找到信息片段,而后用矩形边框将其突围的过程。对于文档解析,这些信息是题目、文本、图形、表……

让咱们来看一个简单的页面,它蕴含了一些货色:

这个页面以一个题目开始,有一个文本块,而后是一个图和一个表,因而咱们须要一个经过训练的模型来辨认这些对象。侥幸的是,Detectron可能实现这项工作,咱们只需从这里抉择一个模型,并在代码中指定它的门路。

我将要应用的模型只能检测4个对象(文本、题目、列表、表格、图形)。因而,如果你须要辨认其余货色(如方程),你就必须应用其余模型。

## load pre-trained modelmodel = 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 arrayi = 21img = np.asarray(doc[i])## predictdetected = model.detect(img)## plotlp.draw_box(img, detected, box_width=5, box_alpha=0.2,             show_element_type=True)

后果蕴含每个检测到的布局的细节,例如边界框的坐标。依据页面上显示的程序对输入进行排序是很有用的:

## sortnew_detected = detected.sort(key=lambda x: x.coordinates[1])## assign idsdetected = lp.Layout([block.set(id=idx) for idx,block in                       enumerate(new_detected)])## checkfor 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 modelmodel = 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()# checkparse_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# checkparse_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) ) # checkparse_doc(dic_predicted)

正如咱们的意料提取的表格不是很好。好在Python有专门解决表格的包,咱们能够间接解决而不将其转换为图像。这里应用TabulaPy 包:

import tabulatables = tabula.read_pdf("doc_apple.pdf", pages=i+1)tables[0]

后果要好一些,然而名称依然错了,然而成果要比间接OCR好的多

总结

本文是一个简略教程,演示了如何应用OCR进行文档解析。应用Layoutpars软件包进行了整个检测和提取过程。并展现了如何解决PDF文档中的文本,数字和表格。

本文的源代码:
https://avoid.overfit.cn/post/2a9b8de5583b46f8bedf7387cf8f8693

作者:Mauro Di Pietro