Python:解析PDF文本及表格——pdfminer、tabula、pdfplumber 的用法及对比

PDF 是个异常坑爹的东西,有不少处理 PDF 的库,可是没有完美的。java

1、pdfminer3k

pdfminer3kpdfminerpython3 版本,主要用于读取 PDF 中的文本。python

网上有不少 pdfminer3k 的代码示例,看过之后,只想吐槽一下,太复杂了,有违 python 的简洁。数组

from pdfminer.pdfparser import PDFParser, PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTTextBox
from pdfminer.pdfinterp import PDFTextExtractionNotAllowed

path = "test.pdf"

# 用文件对象来建立一个pdf文档分析器
praser = PDFParser(open(path, 'rb'))
# 建立一个PDF文档
doc = PDFDocument()
# 链接分析器 与文档对象
praser.set_document(doc)
doc.set_parser(praser)

# 提供初始化密码
# 若是没有密码 就建立一个空的字符串
doc.initialize()

# 检测文档是否提供txt转换,不提供就忽略
if not doc.is_extractable:
    raise PDFTextExtractionNotAllowed
else:
    # 建立PDf 资源管理器 来管理共享资源
    rsrcmgr = PDFResourceManager()
    # 建立一个PDF设备对象
    laparams = LAParams()
    device = PDFPageAggregator(rsrcmgr, laparams=laparams)
    # 建立一个PDF解释器对象
    interpreter = PDFPageInterpreter(rsrcmgr, device)

    # 循环遍历列表,每次处理一个page的内容
    for page in doc.get_pages():
        interpreter.process_page(page)                        
        # 接受该页面的LTPage对象
        layout = device.get_result()
        # 这里layout是一个LTPage对象,里面存放着这个 page 解析出的各类对象
        # 包括 LTTextBox, LTFigure, LTImage, LTTextBoxHorizontal 等 
        for x in layout:
            if isinstance(x, LTTextBox):
                print(x.get_text().strip())
复制代码

pdfminer 对于表格的处理很是的不友好,能提取出文字,可是没有格式:app

PDF 表格截图:工具

代码运行结果:spa

想把这个结果还原成表格可不容易,加的规则太多必然致使通用性的降低。code

2、tabula-py

tabula 是专门用来提取 PDF 表格数据的,同时支持 PDF 导出为 CSV、Excel 格式,可是这工具是用 java 写的,依赖 java7/8。tabula-py 就是对它作了一层 Python 的封装,因此也依赖 java7/8。cdn

代码很简单:对象

import tabula

path = 'test.pdf'

df = tabula.read_pdf(path, encoding='gbk', pages='all')
for indexs in df.index:
    print(df.loc[indexs].values)

# tabula.convert_into(path, os.path.splitext(path)[0]+'.csv', pages='all')
复制代码

虽然号称是专业处理 PDF 中的表格的,但实际效果也不咋地。仍是 pdfminer 中使用的 PDF,运行结果以下:blog

这结果然的很尴尬啊,表头识别就错了,还有 PDF 中有两张表,我没发现怎么区分表。

3、pdfplumber

pdfplumber 是按页来处理 PDF 的,能够得到页面的全部文字,而且提供的单独的方法用于提取表格。

import pdfplumber

path = 'test.pdf'
pdf = pdfplumber.open(path)

for page in pdf.pages:
    # 获取当前页面的所有文本信息,包括表格中的文字
    # print(page.extract_text()) 

    for table in page.extract_tables():
        # print(table)
        for row in table:
            print(row)
        print('---------- 分割线 ----------')

pdf.close()
复制代码

获得的 table 是个 string 类型的二维数组,这里为了跟 tabula 比较,按行输出显示。

能够看到,跟 tabula 相比,首先是能够区分表格,其次,准确率也提升了不少,表头的识别彻底正确。对于表格中有换行的,识别还不是很正确,但至少列的划分没问题,因此仍是能处理的。

import pdfplumber
import re

path = 'test1.pdf'
pdf = pdfplumber.open(path)

for page in pdf.pages:
    print(page.extract_text())
    for pdf_table in page.extract_tables():
        table = []
        cells = []
        for row in pdf_table:
            if not any(row):
                # 若是一行全为空,则视为一条记录结束
                if any(cells):
                    table.append(cells)
                    cells = []
            elif all(row):
                # 若是一行全不为空,则本条为新行,上一条结束
                if any(cells):
                    table.append(cells)
                    cells = []
                table.append(row)
            else:
                if len(cells) == 0:
                    cells = row
                else:
                    for i in range(len(row)):
                        if row[i] is not None:
                            cells[i] = row[i] if cells[i] is None else cells[i] + row[i]
        for row in table:
            print([re.sub('\s+', '', cell) if cell is not None else None for cell in row])
        print('---------- 分割线 ----------')

pdf.close()
复制代码

通过处理后,运行获得结果:

image

这结果已经彻底正确了,而用 tabula,即使是通过处理也是没法获得这样的结果的。固然对于不一样的 PDF,可能须要不一样的处理,实际状况仍是要本身分析。

pdfplumber 也有处理不许确的时候,主要表如今缺列:

我找了另外一个 PDF,表格部分截图以下:

解析结果以下:

4 列变成了 2 列,另外,若是表格有合并单元格的状况,也会有这种问题,我挑这个表格展现是由于比较特殊,没有合并单元格也缺列了。这应该跟 PDF 生成的时候有关。

但其实数据是获取完整的,并无丢,只是被认为是非表格了。输出 page.extract_text() 以下:

而后,我又用 tabula 试了下,结果以下:

列是齐了,可是,表头呢???

pdfplumber 还提供了图形 Debug 功能,能够得到 PDF 页面的截图,而且用方框框起识别到的文字或表格,帮助判断PDF的识别状况,而且进行配置的调整。要使用这个功能,还须要安装 ImageMagick。由于没有用到,因此暂时没有去细究。

4、后记

咱们在作爬虫的时候,不免会遇到 PDF 须要解析,主要仍是针对文本和表格的数据提取。而 python 处理 PDF 的库实在是太多太多了,好比还有 pypdf2,网上资料也比较多,可是我试了,读出来是乱码,没有仔细的读源码因此这个问题也没有解决。

而我对比较经常使用的 3 个库比较后以为,仍是 pdfplumber 比较好用,对表格的支持最好。


扫码关注个人我的公众号
相关文章
相关标签/搜索