python pdfplumber优化表格提取

样例pdf

直接使用文本提取效果:

使用表格提取

 

根据提取的文本信息是没办法获取到表格数据的,太乱了。尤其是 3 4列。

解决:

自行画线,根据画线进行提取。

效果:

思路:

1.根据表头进行画竖线

2.根据行坐标画横线

3.根据坐标放入单元格的list中

4.拼接单元格文字。

问题:

根据表头画竖线,可能内容超出表头左右坐标。

解决办法:根据内容进行特殊匹配。

#!/usr/bin/python
# -*- coding: utf-8 -*-
import re
import pdfplumber
import logging as log


class PDF(object):
    file_path = None
    config = {}
    bill_date_begin = None
    bill_date_end = None
    parse_data = []
    unit = None
    trans_during = None

    def __new__(cls, *args, **kwargs):
        return super().__new__(cls)

    def parse(self):
        try:

            with pdfplumber.open(self.file_path) as pdf:
                page_ind = 1
                log.info(" 发现总页数:{}".format(str(page_ind)))

                for index, page in enumerate(pdf.pages):
                    print(" 第 " + str(page_ind) + " 页: ")
                    page_ind += 1

                    explicit_vertical_lines = []
                    explicit_horizontal_lines = []

                    explicit_horizontal_lines_y_line = []
                    explicit_horizontal_lines_h_line = []
                    explicit_horizontal_lines_keys = []
                    lines_dict = {}
                    table_begin = False

                    ts_y_list = {"jyzy": {"y": [-1, -1]}}
                    table_top = None
                    for ind, char in enumerate(page.chars):
                        next3Text = ""
                        if ind <= (len(page.chars) - 3):
                            next3Text = page.chars[ind]["text"] + page.chars[ind + 1]["text"] + page.chars[ind + 2]["text"]
                            if next3Text.find("交易日") > -1:
                                table_begin = True

                        if table_begin is False:
                            continue

                        if ind >= 2:
                            text = page.chars[ind - 2]["text"] + page.chars[ind - 1]["text"] + page.chars[ind]["text"]
                            if text.find("易日期") > -1 or text.find("出金额") > -1 or text.find("入金额") > -1 or text.find("户余额") > -1 or text.find("账标识") > -1 or text.find("户序号") > -1:
                                # print(text)
                                lines_dict = char
                                explicit_vertical_lines.append({
                                    "x0": lines_dict["x1"] + 2,
                                    "x1": lines_dict["x1"] + 2,
                                    "y0": lines_dict["y0"],
                                    "top": lines_dict["top"] - 5,
                                    "bottom": lines_dict["bottom"] + 700,
                                    "height": lines_dict["height"],
                                    "orientation": "v",
                                    "object_type": "line",
                                    "page_number": index
                                })
                                table_top = lines_dict["top"] - 5
                                explicit_horizontal_lines_h_line.append(lines_dict["x1"] + 2)

                            elif text.find("交易日") > -1:
                                # print(text)
                                lines_dict = page.chars[ind - 2]
                                put_dic = {
                                    "x0": lines_dict["x0"] - 8,
                                    "x1": lines_dict["x0"] - 8,
                                    "y0": lines_dict["y0"],
                                    "top": lines_dict["top"] - 5,
                                    "bottom": lines_dict["bottom"] + 700,
                                    "height": lines_dict["height"],
                                    "orientation": "v",
                                    "object_type": "line",
                                    "page_number": index
                                }

                                explicit_vertical_lines.append(put_dic)
                                explicit_horizontal_lines_h_line.append(lines_dict["x0"] - 8)
                            elif text.find("被冲账") > -1:
                                # print(text)
                                lines_dict = page.chars[ind - 2]
                                explicit_vertical_lines.append({
                                    "x0": lines_dict["x0"] - 1,
                                    "x1": lines_dict["x0"] - 1,
                                    "y0": lines_dict["y0"],
                                    "top": lines_dict["top"] - 5,
                                    "bottom": lines_dict["bottom"] + 700,
                                    "height": lines_dict["height"],
                                    "orientation": "v",
                                    "object_type": "line",
                                    "page_number": index
                                })
                                explicit_horizontal_lines_h_line.append(lines_dict["x0"] - 8)

                            # 竖线修复
                            if text.find("易摘要") > -1 or text.find("对方户") > -1:
                                if text.find("易摘要") > -1:
                                    ts_y_list["jyzy"]["y"][0] = char["x1"] + 2
                                    # ts_y_list["jyzy"]["y"][0] = char["x1"] + char["x1"] - char["x0"]
                                elif text.find("对方户") > -1:
                                    ts_y_list["jyzy"]["y"][1] = page.chars[ind-2]["x0"] - 1
                                    ts_y_list["jyzy"]["mid"] = page.chars[ind-2]

                            # 判断是否添加过该横线
                            if char["y0"] not in explicit_horizontal_lines_keys:
                                text = page.chars[ind - 2]["text"] + page.chars[ind - 1]["text"] + page.chars[ind]["text"]
                                if text.find("标识T") > -1 or text.find("leA") > -1:
                                    explicit_horizontal_lines_keys.append(char["y0"])
                                    continue

                                # 特殊竖线,根据表头坐标和内容坐标对比,取最左的那一个作为竖线的坐标
                                if ts_y_list["jyzy"]["y"][0] != -1 and ts_y_list["jyzy"]["y"][1] != -1 and char["x0"] > ts_y_list["jyzy"]["y"][0] and char["x1"] < ts_y_list["jyzy"]["y"][1]:
                                    if "mid" in ts_y_list["jyzy"].keys():
                                        if ts_y_list["jyzy"]["mid"]["x0"] > char["x0"]:
                                            ts_y_list["jyzy"]["mid"] = char
                                    else:
                                        ts_y_list["jyzy"]["mid"] = char

                                lines_dict_h = char

                                if text.find("ag2") > -1:
                                    explicit_horizontal_lines.append({
                                        "x0": 579,
                                        "x1": lines_dict_h["x1"] - 15,
                                        "y0": lines_dict_h["y0"],
                                        "y1": lines_dict_h["y1"],
                                        "top": lines_dict_h["bottom"] + 5,
                                        "bottom": lines_dict_h["bottom"] + 5,
                                        "height": lines_dict_h["height"],
                                        "width": lines_dict_h["width"],
                                        "orientation": "h",
                                        "object_type": "line",
                                        "page_number": index
                                    })
                                    explicit_horizontal_lines_y_line.append(lines_dict_h["bottom"] + 5)
                                elif next3Text.find("交易日") > -1 or (text.find("交易日") > -1 and index > 0):
                                    explicit_horizontal_lines.append({
                                        "x0": 579,
                                        "x1": lines_dict_h["x1"] - 15,
                                        "y0": lines_dict_h["y0"] if index == 0 else (lines_dict_h["y0"] - 5),
                                        "y1": lines_dict_h["y1"],
                                        "top": lines_dict_h["top"] - 5,
                                        "bottom": lines_dict_h["top"] - 5,
                                        "height": lines_dict_h["height"],
                                        "width": lines_dict_h["width"],
                                        "orientation": "h",
                                        "object_type": "line",
                                        "page_number": index
                                    })
                                    explicit_horizontal_lines_y_line.append(lines_dict_h["top"] + 5)
                                else:

                                    if lines_dict_h["x1"] > 200:
                                        continue

                                    # 正常行数据添加横线
                                    explicit_horizontal_lines.append({
                                        "x0": 579, # 横线长度
                                        "x1": lines_dict_h["x1"] - 12,
                                        "y0": lines_dict_h["y0"],
                                        "y1": lines_dict_h["y1"],
                                        "top": lines_dict_h["bottom"] + 5,
                                        "bottom": lines_dict_h["bottom"] + 5,
                                        "height": lines_dict_h["height"],
                                        "width": lines_dict_h["width"],
                                        "orientation": "h",
                                        "object_type": "line",
                                        "page_number": index
                                    })
                                    explicit_horizontal_lines_y_line.append(lines_dict_h["bottom"] + 5)

                                explicit_horizontal_lines_keys.append(char["y0"])

                    for k, v in ts_y_list.items():
                        if "mid" in v.keys() and v["mid"]["x0"] != -1:
                            lines_dict = v["mid"]
                            explicit_vertical_lines.append({
                                "x0": lines_dict["x0"] -8,
                                "x1": lines_dict["x0"] -8,
                                "y0": lines_dict["y0"],
                                "top": table_top,
                                "bottom": lines_dict["bottom"] + 700,
                                "height": lines_dict["height"],
                                "orientation": "v",
                                "object_type": "line",
                                "page_number": index
                            })
                            explicit_horizontal_lines_h_line.append(lines_dict["x0"] - 1)

                    page.curves.clear()
                    page.lines.clear()
                    # 赋值画线
                    page.objects['line'] = explicit_vertical_lines + explicit_horizontal_lines

                    explicit_horizontal_lines_h_line.sort()

                    line_text = []
                    # 根据横线坐标 & 纵线坐标 ,判断单元格
                    for ind, y in enumerate(explicit_horizontal_lines_y_line):
                        if (ind + 1) == len(explicit_horizontal_lines_y_line):
                            continue

                        # 单元格内容组装
                        def get_this_cell_text(y, next_y):
                            this_y_line = []
                            for char in page.chars:
                                if char["bottom"] > y and char["bottom"] < next_y:
                                    this_y_line.append(char)

                            cell_list = []
                            for ind_h, h in enumerate(explicit_horizontal_lines_h_line):
                                if (ind_h + 1) == len(explicit_horizontal_lines_h_line):
                                    continue

                                next_h = explicit_horizontal_lines_h_line[ind_h+1]
                                cell_text = ""
                                for char in this_y_line:
                                    if char["x0"] > h and char["x0"] < next_h:
                                        cell_text += char["text"]

                                cell_list.append(cell_text)
                            return cell_list

                        next_y = explicit_horizontal_lines_y_line[ind + 1]
                        this_cell_text = get_this_cell_text(y, next_y=next_y)
                        line_text.append(this_cell_text)

                    # im = page.to_image()
                    # im.draw_rects(page.extract_words())
                    # im.draw_vline(location, stroke={color}, stroke_width=1)
                    # im.save("aa.png')

                    # 合并解析的数据
                    self.parse_data = self.parse_data + line_text

            # 开始进行数据格式化
            data_list = []
            head_index = {'交易日期': -1, '账户序号': -1, '收入金额': -1, '支出金额': -1, '账户余额': -1, '交易摘要': -1, '对方户名': -1,
                          '被冲账标识': -1}
            isTableRow = True
            for ind, line in enumerate(self.parse_data):

                if ind == 0:
                    for ind_c, cell in enumerate(line):
                        for k, v in head_index.items():
                            if cell.find(k) > -1:
                                head_index[k] = ind_c

                    continue

                if "".join(s for s in line).find("第") > -1 and "".join(s for s in line).find("页") > -1:
                    continue
                if "".join(s for s in line).find("交易日期Transactiodate") > -1 and "".join(s for s in line).find("账户序号nAccountSeqNo") > -1:
                    continue

                if line[0] == "":
                    continue

                if "".join(s for s in line).find("声明:") > -1:
                    isTableRow = False

                if isTableRow is False:
                    continue

                value_dict = {}
                for k, v in head_index.items():
                    value_dict[k] = line[head_index[k]]
                # print(value_dict)

                currency = ""
                amount = value_dict["收入金额"].replace(" ", "") if value_dict["收入金额"] != "" else value_dict["支出金额"].replace(" ", "")
                balance_v = value_dict["账户余额"].replace(" ", "")

                if balance_v is not None and len(balance_v) > 0:
                    balance_v = balance_v.replace(currency, "")

                amount = amount.replace(currency, "")

                data_one = {"trans_remark": value_dict["交易摘要"],
                            "currency": self.unit,
                            "trans_date":value_dict["交易日期"],
                            "trans_amount": amount,
                            "balance": balance_v,
                            "trans_place": '',
                            "opponent_mess": value_dict["对方户名"]}

                data_list.append(data_one)

            import json
            print(json.dumps(data_list, ensure_ascii=False))
            self.parse_data = data_list
        except FileNotFoundError:
            raise FileNotFoundError
        except:
            raise Exception


PDF(None, "3.pdf", "123432", {}).parse()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/767754.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

thinksboard 网络请求方式

html模块 deleteImage点击事件 <div class"tb-images tb-absolute-fill" [ngClass]"{tb-dialog-mode: dialogMode, mat-padding: !dialogMode}"><div fxFlex fxLayout"column" class"tb-images-content" [ngClass]"{t…

elementPlus自定义el-select下拉样式

如何在f12元素选择器上找到下拉div呢&#xff1f; 给el-select添加 :popper-append-to-body"false" 即可&#xff0c;这样就可以将下拉框添加到body元素中去&#xff0c;否则当我们失去焦点&#xff0c;下拉就消失了&#xff0c;在元素中找不到el-select。剩下就可以…

Amos结构方程模型---探索性分析

初级 第5讲 探索性分析_哔哩哔哩_bilibili amos中基本操作&#xff1a; 椭圆潜变量&#xff0c;不可预测 数据导入 改变形状 判定系数 方差估计和假设检验&#xff1a; 探索性分析&#xff1a; ses&#xff08;潜变量&#xff09;社会经济指数 从考虑最大的MI开始&#xff0c;卡…

模拟 ADC 的前端

ADC 的 SPICE 模拟 反复试验的方法将信号发送到 ADC 非常耗时&#xff0c;而且可能有效也可能无效。如果转换器捕获电压信息的关键时刻模拟输入引脚不稳定&#xff0c;则无法获得正确的输出数据。SPICE 模型允许您执行的步是验证所有模拟输入是否稳定&#xff0c;以便没有错误…

全网最详细金融APP测试功能点-测试用例,详细整理(全)

2024软件测试面试刷题&#xff0c;这个小程序&#xff08;永久刷题&#xff09;&#xff0c;靠它快速找到工作了&#xff01;&#xff08;刷题APP的天花板&#xff09;-CSDN博客跳槽涨薪的朋友们有福了&#xff0c;今天给大家推荐一个软件测试面试的刷题小程序。https://blog.c…

mov文件怎么转换成mp4格式?这四种转换方法超级好用!

mov文件怎么转换成mp4格式&#xff1f;在数字娱乐的世界中&#xff0c;你是否曾遇到过MOV格式的视频&#xff1f;也许&#xff0c;对于许多人来说&#xff0c;这并不是一个常见的格式&#xff0c;但这并非偶然&#xff0c;首先&#xff0c;我们来谈谈MOV的兼容性问题&#xff0…

「漏洞复现」时空智友ERP系统updater.uploadStudioFile 任意文件上传漏洞

0x01 免责声明 请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;作者不为此承担任何责任。工具来自网络&#xff0c;安全性自测&#xff0c;如有侵权请联系删…

Python处理异常用操作介绍

Python中的异常处理主要用于捕获和处理程序运行过程中出现的错误。 在编写Python程序时&#xff0c;我们经常会遇到各种错误&#xff0c;如语法错误、运行时错误等。为了确保程序的稳定性和健壮性&#xff0c;我们需要对可能出现的错误进行捕获和处理。本文将介绍Python中常用的…

Python入门 2024/7/3

目录 for循环的基础语法 遍历字符串 练习&#xff1a;数一数有几个a range语句 三个语法 语法1 语法2 语法3 练习&#xff1a;有几个偶数 变量作用域 for循环的嵌套使用 打印九九乘法表 发工资案例 continue和break语句 函数的基础定义语法 函数声明 函数调用 …

MLLM QLoRA微调实战:基于最新的袖珍Mini-InternVL模型

引言 大型语言模型&#xff08;LLM&#xff09;的世界正在不断发展&#xff0c;新的进步正在迅速出现。一个令人兴奋的领域是多模态LLM&#xff08;MLLMs&#xff09;的发展&#xff0c;这种模型既能够理解文本又能够理解图像&#xff0c;并与之进行交互。因此&#xff0c;这种…

ICCV2023鲁棒性相关论文速览

Paper1 Towards Better Robustness against Common Corruptions for Unsupervised Domain Adaptation 摘要原文: Recent studies have investigated how to achieve robustness for unsupervised domain adaptation (UDA). While most efforts focus on adversarial robustnes…

udp发送数据如果超过1个mtu时,抓包所遇到的问题记录说明

最近在测试Syslog udp发送相关功能&#xff0c;测试环境是centos udp头部的数据长度是2个字节&#xff0c;最大传输长度理论上是65535&#xff0c;除去头部这些字节&#xff0c;可以大概的说是64k。 写了一个超过64k的数据(随便用了一个7w字节的buffer)发送demo&#xff0c;打…

Geotools系列说明之LineString仿高德航路截取说明

需求分析 我们在做webgl的时候经常会遇到这样的需求&#xff0c;计算给定航路的拥堵情况&#xff0c;不同的拥堵显示不同的颜色&#xff0c;航路截取计算等等。基于这类问题统一都可以使用LineString进行处理 实现思路 如上图所示&#xff0c;航路是几个关键的点然后练成线&a…

MySql Innodb 索引有哪些与详解

概述 对于MYSQL的INNODB存储引擎的索引&#xff0c;大家是不陌生的&#xff0c;都能想到是 B树结构&#xff0c;可以加速SQL查询。但对于B树索引&#xff0c;它到底“长”得什么样子&#xff0c;它具体如何由一个个字节构成的&#xff0c;这些的基础知识鲜有人深究。本篇文章从…

2本Top,4本纯正刊,25天即录!7月刊源表已更新!

本周投稿推荐 SCI • 能源技术类&#xff0c;1.5-2.0&#xff08;来稿即录25天&#xff09; • 计算机类&#xff0c;2.0-3.0&#xff08;纯正刊29天录用&#xff09; EI • 各领域沾边均可&#xff08;2天录用&#xff09; CNKI • 7天录用-检索&#xff08;急录友好&a…

【微信小程序开发实战项目】——如何制作一个属于自己的花店微信小程序(2)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

Python基于决策树回归模型、多元线性回归模型、随机森林回归模型和LightGBM回归模型实现波士顿房价预测项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 城市住房市场的稳定与健康发展是衡量一个地区经济活力和社会福祉的重要指标之一。波士顿&#xff0c;作…

Three-pass authentication

7.2.3 Mechanism MUT.CR — Three-pass authentication # 参考符号 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/7aed1610e49e48729933f8160e5228af.png)

研发驱动 再谱新篇丨美格智能南通研发中心正式成立

近日&#xff0c;美格智能全资设立的众格智能技术&#xff08;南通&#xff09;有限公司&#xff0c;正式在江苏省南通市紫琅科技城揭牌成立&#xff0c;此举也标志着继上海、西安、深圳之后&#xff0c;美格智能研发力量布局再谱新篇&#xff1a;美格智能南通研发中心正式成立…

工商业光伏项目如何快速开发?

一、前期调研与规划 1、屋顶资源评估&#xff1a;详细测量屋顶面积、承重能力及朝向&#xff0c;利用光伏业务管理软件进行日照分析和发电量预测&#xff0c;确保项目可行性。 2、政策与补贴研究&#xff1a;深入了解当地政府对工商业光伏项目的政策支持和补贴情况&#xff0…