PDF 解析实例 - 基于位置的 PDF 文本

在某个客户的具体案例里面,客户提供的一个不规则的表格要求解析,具体界面如图:
PDF 解析实例 - 基于位置的 PDF 文本

我们首先导入pdfplumber
然后我们测试了一下提取表格和提取 text:

tables = page0.extract_tables() #从page0里面取出多个tables 
texts = page0.extract_text() #从page0里面取出所有文本

我们可以发现:那些表头是图片,下面那些比较清晰的印刷体是字符,其实大家用拖动选中试试就能看出哪些是字符了,由于他不是对齐的表格,提取表格也取不到任何数据,怎么办呢?
其实这个表格是固定位置的,他的任何一个打印数据应该都不会越界,我们简单的试了一下 pdfplumber 的另外一个功能,extract_words:

page0.extract_words(x_tolerance=5, y_tolerance=0) 

可以看到,我们指定有 5 个单位以上的间隔,就认定是两个词了,我们得到了很多有用的信息:

{'x0': Decimal('44.884'), 'x1': Decimal('71.281'), 'top': Decimal('28.387'), 'bottom': Decimal('36.253'), 'text': '03031'}, 
{'x0': Decimal('87.120'), 'x1': Decimal('124.076'), 'top': Decimal('28.387'), 'bottom': Decimal('36.253'), 'text': '0012345'}

我们看到这里面是 03031 和 0012345 两个词列表,实际结果中非常多,这里不一一例举了,这里结果都返回了位置,这里面有 x0,x1,top,bottom,他们的含义是:
PDF 解析实例 - 基于位置的 PDF 文本
在程序编写中,我们配置了一个表格,用于提取我们需要的字段:
PDF 解析实例 - 基于位置的 PDF 文本
这样我们要提取更多字段,只要配置这个表格就行了
我们通过如下程序来提取这个配置:

# coding=utf-8
import pdfplumber as pp
import xlwings as xw
import pandas as pd

config_file = 'path/to/file/field_config.xlsx'
pdf_file = 'path/to/file/Payslip_Sample_IT_2.pdf'
result_file = 'path/to/file/result.xlsx'

def get_field(page, position):
    rect = page.crop(position)
    return rect.extract_text()

if __name__ == "__main__":
    pdf = pp.open(pdf_file)
    config_df = pd.read_excel(config_file)
    result_df = pd.DataFrame()
    for p in pdf.pages:
        columns = []
        data = []
        for index, row in config_df.iterrows():
            columns.append(row['field'])
            text = get_field(p, (row['x0'], row['top'], row['x1'], row['bottom']))
            data.append(text)
        try:
            df = pd.DataFrame([data], columns=columns)
            result_df = result_df.append(df)
        except Exception as e:
            print('error:====', data, columns)
            print(e)
    result_df = result_df.reset_index(drop=True)
    wb = xw.Book(result_file)
    sht = wb.sheets[0]
    sht.clear()
    sht.range('A1').value = result_df
    wb.save()

最终得到了如下结果:
PDF 解析实例 - 基于位置的 PDF 文本

在实际操作过程中,可能会出现这种情况:
PDF 解析实例 - 基于位置的 PDF 文本

我们通过 extract_words 得到的位置是蓝色框的位置,但是实际用户需要使用的是红色框的位置,那么就需要手动调位置坐标了,所以我们需要准确理解 x0,x1,top,bottom 的含义。
如果大家有空,可以试试 pdfplumber 中的这几个函数,来准确定位:

im = p0.to_image()
rect = page.crop(position)
im.draw_rect(bbox_or_obj, fill={color}, stroke={color}

具体大家可以参考pdfplumber文档
这个由于我有个画图插件没装好,暂时还没试验成功,有心学习的可以试验一下,这里借 pdfplumber 官方的一张图来看一下效果:
PDF 解析实例 - 基于位置的 PDF 文本

注意,他用了 extract_words 结果直接画框,我们应该逐步增大我们配置文件中框体,直到取到合适的宽度,如果大家有新的实验效果,可以跟帖在后面或者另外写一个经验