分享

Python 竟能解析 PDF 表格?

 heii2 2018-08-19

需求

公司的PDF年报中有各种各样的表格,需要对其中的某些具体的小标题下的表格解析出来,也就是所谓的数据结构化。

解决方案

通过看别人写的博客,发现python里面有关PDF解析的通常有以下四种:

  • pdfminer,擅长仅仅是文字的解析,本小白试过了,是把表格解析成普通的文本,还经常会伴随一些莫名奇妙的不认识的符号。这个方案pass

  • pdf2html,看例是把pdf解析成html,但是html的标签并没有规律,解析一个还行,但是本小白是许多的pdf文档下小标题的表格,这个方案直接pass

  • tabula,这个是我看过的前辈写的博客中使用最多的,本人用过了。对于简单的表格,也就是单元格中没有换行的,表头表尾形式不复杂的,这个方案的值得推荐。电脑需要有Java的环境

  • pdfplumber,这个是看了知乎上的一个大佬的发现,并且自己安装成功之后,发现最小众,但是最符合我的需求的解决方案。前提是是需要安装ImageMagick的


实施解决

本人一共使用了两种方案解决了我的需求,分别是tabula和pdfplumber

先做前期的工作

1,将PDF文件转化为JPG格式,进行搜索关键字,查看想要的表格的页码比如下图中的风险管理状况的得分表:

代码如下:(有宝宝的百度AIP密钥哦!)

#pdf 拆分为jpg
from pdf2image import convert_from_path,convert_from_bytes
import tempfile
import pdf2image
def pdf2image(I_path,O_path):
   with tempfile.TemporaryDirectory() as path:
       images_from_path = convert_from_path(I_path,output_folder=O_path,fmt='jpg')
I_path='/Users/gaohua/Desktop/33.PDF'
O_path='/Users/gaohua/Desktop/33'
pdf2image(I_path,O_path)

#文档重命名
import os
path='/Users/gaohua/Desktop/33'
def rename_file(path):
   for file in os.listdir(path):
       os.rename(os.path.join(path,file),os.path.join(path,file[-5:]))
rename_file(path)

#使用百度ocr进行识别
from aip import AipOcr
def baidu_aip(APP_ID,API_KEY,SECRET_KEY):
   client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
   return(client)
APP_ID = '11659928'
API_KEY = 'Ogkg6buRucGnKtfeoamjg7rT'
SECRET_KEY = 'OlCLKVhaYMyqYwzvlaQ5uVgfUxzOlkcr'
client=baidu_aip(APP_ID,API_KEY,SECRET_KEY)

def get_file_content(path):
   with open(path,'rb') as fp:
       return fp.read()

def find_page(path,key_words):
   for file in os.listdir(path)[1:-1]:
       result = client.basicGeneral(get_file_content(os.path.join(path,file)))
       for item in result['words_result']:
#             print(item['words'])#输出解析的pdf文字
           if key_words in item['words']:
               return (file.strip('.jpg'))

上面的模块安装起来应该问题不大,有问题的话可以留言哦。

调用函数的输出如下

key_words='风险管理状况'
page=find_page(path,key_words)
print(page)

会输出相应的页码(无耻的骄傲一下下,看看宝宝的jupyter好看不?)

在拿到页码的情况下,我们就可以为所欲为啦!

首先就是第一种方法:tabula

具体的操作方法如下:

import tabula
# Read pdf into DataFrame
df = tabula.read_pdf('/Users/gaohua/Desktop/33.pdf',pages=str(page))
df

这个直接返回的是一个数据帧,所以就直接是结构化的数据啦!

输出结果是这样哒:

这样的话,我们就已经完成了我们的需求啦!后续的关于写入的Excel中中的话,在下就部多言啦!可以移步熊猫或者为pywin32哦!

虽然塔布拉是很方便,但是它的输出是真的不方便,而且还需要装的的的java的环境,JAVA的环境变量搞的本宝宝肾亏...

有时候还会输出乱七八糟的东西,比如有时候会输出繁体的中文,我就遇到过...

所以保险起见

这里再给出第二个解决方案:

再次就是二个解决方案pdfplumber

import pdfplumber
pdf = pdfplumber.open('/Users/gaohua/Desktop/33.pdf')
p0 = pdf.pages[int(page)-1]#注意此处的pages是一个列表,索引是从0开始的
table = p0.extract_table()
import pandas as pd
df = pd.DataFrame(table[1:], columns=table[0])
df

嘻嘻嘻输出如下:



虽然为了展示对比的方便,这里都是用了同样的一个表格,但是方案2的解决真的要比1好

别问我为啥知道2比1好,你试试用1去解析一些带有文字格式的表格,带有复杂的表头的表格,你就知道啦!我在这里并没有在瞎说,而且还得装的的java的,后者只装一个的的ImageMagick的就行,而且ImageMagick的的的很有用哒,嘻嘻嘻

总结

本次一共总和运用了百度OCR的接口,百度AIP这个东西嘛!这简直就是男人的宝库!自己去看看就知道啦!

还有就是使用了PDF格式的解析的包


但是还是有不足的哦,就是这两个解决方案都是针对于比较乖巧的表格的,就是横线和竖线都比较完整的表格的,像下面的这种表格:

方案一的识别输出是心有余而肾不足,输出为无

方案二的识别输出是行百步者半九十,输出为一个不太像样的表格,还需要手工的调整....

 

好啦本次分享就到这里啦,一并感谢借鉴过的如来神掌武功秘籍的大佬们的博客!


(完)


看完本文有收获?请转发分享给更多人

关注「Python那些事」,做全栈开发工程师

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多