基于tabula对pdf中的excel进行识别并转换成word(三)

        上一节中是基于PaddleOCR对图片中的excel进行识别并转换成word优化,本节改变思路,直接从pdf中读取表格的信息,具体思路如下所述。

        PDF中的表格数据如下截图所示:

        一、基于tabula从PDF中提取表格

df_list = tabula.read_pdf("excel.pdf", pages="all", multiple_tables=True, stream=True)

        二、获取表格中的数据

for table_index, table in enumerate(df_list):# 获取行数和列数rows, cols = table.shapeprint(f"表格 {table_index + 1} 的行数: {rows}, 列数: {cols}")heading_cells = []for col_num, column_name in enumerate(table.columns):heading_cells.append(column_name)table_data.append(heading_cells)for row_index, row in table.iterrows():table_data.append(row.tolist())

table_data数据格式:

 [['订单号', '商品名称', '单价', '总价', '购买日期', '收货地址'], [nan, nan, '(元)', '(元)', nan, nan], ['20250423A', '月之暗面笔记本', '50', '100', '2025-04-23', '北京市海淀区'], ['XXXXXX323', nan, nan, nan, nan, '中关村大街 1 号'], [nan, nan, nan, nan, nan, 'XXXXXXXX121RWW'], ['20250423B', '月之暗面 T 恤', '80', '80', '2025-04-23', '上海市浦东新区'], ['YYYY987', nan, nan, nan, nan, '陆家嘴金融区'], [nan, nan, nan, nan, nan, '112DSDCWE2DFDWEWE']]
table_data: [['订单号', '商品名称', '单价(元)', '总价(元)', '购买日期', '收货地址'], ['20250423AXXXXXX323', '月之暗面笔记本', '50', '100', '2025-04-23', '北京市海淀区中关村大街 1 号XXXXXXXX121RWW'], ['20250423BYYYY987', '月之暗面 T 恤', '80', '80', '2025-04-23', '上海市浦东新区陆家嘴金融区112DSDCWE2DFDWEWE']]

        三、根据表格中的必填项内容去判断是否为nan,去合并单元格

        具体思路:比如订单编号和商品名称不能为空,那么从最后一行开始向上遍历列表,检查每一行的第一列和第二列是否为空(即是否为   NaN  )。如果为空,则将该行的数据合并到上一行对应的单元格中,并删除当前行。

def handle_table(table_data):for i in range(len(table_data) - 1, 0, -1):if table_data[i][0] in [None, np.nan, ""] or table_data[i][1] in [None,np.nan,"",]:for j in range(len(table_data[i])):if table_data[i][j] not in [None,np.nan,"",]:  # 只有当单元格不为空时才合并table_data[i - 1][j] = f"{table_data[i - 1][j]}{table_data[i][j]}".strip()# 删除当前行del table_data[i]

        四、生成word

def create_table_and_fill_data(data, output_file):"""在 Word 文档中插入表格并填充数据:param data: 表格数据:param output_file: 输出文件路径"""# 创建一个新的 Word 文档doc = Document()# 添加一个标题sssdoc.add_heading("测试XX信息表", level=1)# 创建表格table = doc.add_table(rows=len(data), cols=len(data[0]))# 填充表格数据for row_index, row_data in enumerate(data):for col_index, cell_text in enumerate(row_data):cell = table.cell(row_index, col_index)cell.text = str(cell_text)set_cell_borders(cell, border_color="FF0000", row_height=300)# 设置表格边框颜色# 保存 Word 文档doc.save(output_file)

补充画表格边框函数set_cell_borders

def set_cell_borders(cell, border_color="000000", row_height=None):"""设置单元格的边框颜色:param cell: 单元格对象:param border_color: 边框颜色,默认为黑色"""tc = cell._elementtcPr = tc.get_or_add_tcPr()tcBorders = OxmlElement("w:tcBorders")for border_name in ("top", "left", "bottom", "right"):border = OxmlElement(f"w:{border_name}")border.set(qn("w:val"), "single")border.set(qn("w:sz"), "4")  # 边框大小border.set(qn("w:space"), "0")border.set(qn("w:color"), border_color)tcBorders.append(border)tcPr.append(tcBorders)# 设置内容居中显示for paragraph in cell.paragraphs:for run in paragraph.runs:run.font.size = paragraph.style.font.size  # 保持字体大小一致paragraph.alignment = 1  # 1 表示居中对齐# 设置行高if row_height is not None:tr = cell._element.getparent()  # 获取行元素trPr = tr.get_or_add_trPr()trHeight = OxmlElement("w:trHeight")trHeight.set(qn("w:val"), str(row_height))trPr.append(trHeight)

        5、效果展示

6、完整代码

import tabula
import numpy as np
from docx import Document
from docx.oxml.ns import qn
from docx.oxml import OxmlElementdef get_table_data(df_list):# 遍历每个表格for table_index, table in enumerate(df_list):# 获取行数和列数rows, cols = table.shapeprint(f"表格 {table_index + 1} 的行数: {rows}, 列数: {cols}")heading_cells = []for col_num, column_name in enumerate(table.columns):heading_cells.append(column_name)table_data.append(heading_cells)for row_index, row in table.iterrows():table_data.append(row.tolist())def handle_table(table_data):for i in range(len(table_data) - 1, 0, -1):if table_data[i][0] in [None, np.nan, ""] or table_data[i][1] in [None,np.nan,"",]:for j in range(len(table_data[i])):if table_data[i][j] not in [None,np.nan,"",]:  # 只有当单元格不为空时才合并table_data[i - 1][j] = f"{table_data[i - 1][j]}{table_data[i][j]}".strip()# 删除当前行del table_data[i]def set_cell_borders(cell, border_color="000000", row_height=None):"""设置单元格的边框颜色:param cell: 单元格对象:param border_color: 边框颜色,默认为黑色"""tc = cell._elementtcPr = tc.get_or_add_tcPr()tcBorders = OxmlElement("w:tcBorders")for border_name in ("top", "left", "bottom", "right"):border = OxmlElement(f"w:{border_name}")border.set(qn("w:val"), "single")border.set(qn("w:sz"), "4")  # 边框大小border.set(qn("w:space"), "0")border.set(qn("w:color"), border_color)tcBorders.append(border)tcPr.append(tcBorders)# 设置内容居中显示for paragraph in cell.paragraphs:for run in paragraph.runs:run.font.size = paragraph.style.font.size  # 保持字体大小一致paragraph.alignment = 1  # 1 表示居中对齐# 设置行高if row_height is not None:tr = cell._element.getparent()  # 获取行元素trPr = tr.get_or_add_trPr()trHeight = OxmlElement("w:trHeight")trHeight.set(qn("w:val"), str(row_height))trPr.append(trHeight)def create_table_and_fill_data(data, output_file):"""在 Word 文档中插入表格并填充数据:param data: 表格数据:param output_file: 输出文件路径"""# 创建一个新的 Word 文档doc = Document()# 添加一个标题sssdoc.add_heading("测试XX信息表", level=1)# 创建表格table = doc.add_table(rows=len(data), cols=len(data[0]))# 填充表格数据for row_index, row_data in enumerate(data):for col_index, cell_text in enumerate(row_data):cell = table.cell(row_index, col_index)cell.text = str(cell_text)set_cell_borders(cell, border_color="FF0000", row_height=300)# 设置表格边框颜色# 保存 Word 文档doc.save(output_file)pdf_file = "excelv2.pdf"
output_file = "order0429.docx"  # 输出的 Word 文件路径
table_data = []
# 使用tabula从PDF中提取表格
df_list = tabula.read_pdf(pdf_file, pages="all", multiple_tables=True, stream=True)
get_table_data(df_list)
handle_table(table_data)
create_table_and_fill_data(table_data, output_file)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java中的接口和抽象类

Java 抽象类与接口:区别、应用与选择 在 Java 编程的世界里,抽象类和接口是两个极为重要的概念,它们在实现代码抽象、提高代码复用性和可维护性方面发挥着关键作用。然而,很多开发者在使用时容易混淆这两个概念。本文将深入探讨 …

Java读Excel:解析阿里云easyExcel导入文件的行号

文章目录 引言I 解析阿里云easyExcel导入文件的行号声明解析对象的基类判断Excel解析对象类型是否包含继承某个类 isAssignableFromJava 转换list类型并设置下标到元素对象属性II 封装excel 文件读取excel 文件读取用法文件导入上下文III 参数校验工具类校验参数是否合法 (jaka…

mmap核心原理和用途及其与内存映射段的关系

mmap 是 Linux/Unix 系统中的一个关键系统调用,全称是 Memory Map(内存映射)。它的核心功能是将 文件、设备或匿名内存 直接映射到进程的虚拟地址空间,从而实现高效的内存访问和操作。以下是其核心原理和用途的详细说明&#xff1…

数据库概论速成期中版

文章目录 引论数据库用户Casual usersNaive usersApplication programmersDatabase administrators 关系模型CAP数据库两种描述关系数据库的方式简单总结 第一范式规则第二范式规则举个例子符合第二规则的操作不符合第二规则的操作 第三范式规则key,superkey,null values,主键&…

解决调用Claude 3.7接口 403 Request not allowed问题

1. 遇到问题 Python 基于 Langchain 对接 Claude 3.7 大模型接口进行问答时,由于国内不在Claude支持的国家和地区,所以一直调不通,错误 anthropic.PermissionDeniedError: Error code: 403 - {error: {type: forbidden, message: Request…

Vue2+Vue3学习笔记

Vue基础介绍 下载并安装vue.js v2 https://v2.cn.vuejs.org/https://v2.cn.vuejs.org/ v3 https://v3.cn.vuejs.org/ 会重定向到Vue.js - 渐进式 JavaScript 框架 | Vue.jsVue.js - 渐进式的 JavaScript 框架https://cn.vuejs.org/ 从v2过渡到v3 在F盘创建v2v3学习笔记 并…

2025年KBS新算法 SCI1区TOP:长颖燕麦优化算法AOO,深度解析+性能实测

目录 1.摘要2.算法原理3.结果展示4.参考文献5.文章&代码获取 1.摘要 本文提出了一种新颖的元启发式算法——长颖燕麦优化算法(AOO),该算法灵感来自动画燕麦在环境中的自然行为。AOO模拟了长颖燕麦的三种独特行为:(i) 通过自然…

CentosLinux系统crontab发现执行删除命令失效解决方法

权限或安全策略限制 ​​可能场景​​: ​​### ​​目录权限冲突​​: 你的目录权限为 drwxr-xr-x(属主 mssql),但 cron 任务以 root 执行。 ​​风险点​​:若目录内文件属主为 mssql 且权限为 700&…

后验概率最大化(MAP)估计算法原理以及相具体的应用实例附C++代码示例

1. MAP估计基本原理 MAP(Maximum A Posteriori,最大后验概率估计)是贝叶斯推断中的重要概念,它的目标是: 给定观测数据,找到使得后验概率最大的参数值。 公式化表示: [ θ MAP arg ⁡ max ⁡…

16、路由守卫:设置魔法结界——React 19 React Router

一、魔法结界的本质 "路由守卫是霍格沃茨城堡的隐身斗篷,在时空裂隙中精准控制维度跃迁!" 魔法部交通司官员挥舞魔杖,React Router 的嵌套路由在空中交织成星轨矩阵。 ——基于《国际魔法联合会》第7号时空协议,路由守…

从车道检测项目入门open cv

从车道检测项目入门open cv 前提声明:非常感谢b站up主 嘉然今天吃带变,感谢其视频的帮助。同时希望各位大佬积积极提出宝贵的意见。😊😊😊(❁◡❁)(●’◡’●)╰(▽)╯ github地址:https://github.com/liz…

【行业特化篇3】制造业简历优化指南:技术参数与标准化流程的关键词植入艺术

写在最前 作为一个中古程序猿,我有很多自己想做的事情,比如埋头苦干手搓一个低代码数据库设计平台(目前只针对写java的朋友),比如很喜欢帮身边的朋友看看简历,讲讲面试技巧,毕竟工作这么多年,也做到过高管,有很多面人经历,意见还算有用,大家基本都能拿到想要的offe…

如何在本地部署小智服务器:从源码到全模块运行的详细步骤

小智聊天机器人本地后台服务器源码全模块部署 作者:林甲酸 -不是小女子也不是女汉子 是大女子 更新日期:2025年4月29日 🎯 前言:为什么要写这篇教程? 上周按照虾哥小智服务器的教程去部署本地后台,我用的是…

github开源项目添加开源协议,使用很简单

直接在 GitHub 网页上创建 进入你的 GitHub 仓库 打开你的项目仓库页面(如 https://github.com/用户名/仓库名)。 点击 "Add file" → "Create new file" 在仓库主页,点击右上角的 "Add file" 按钮&#xff…

8.idea创建maven项目(使用Log4j日志记录框架+Log4j 介绍)

8.idea创建maven项目(使用Log4j日志记录框架Log4j 介绍) 在 IntelliJ IDEA 的 Maven 项目中引入了 Log4j,并配置了日志同时输出到控制台和文件。 Log4j 提供了灵活的日志配置选项,可以根据项目需求调整日志级别、输出目标和格式。 1. 创建 Maven 项目 …

【和春笋一起学C++】函数——C++的编程模块

目录 1. 原型句法 2. 函数分类 3. 函数参数之按值传递 4. 数组作为函数参数 在C中,要使用函数,必须要有这三个方面: 函数原型,函数原型描述了函数到编译器的接口,函数原型一般放在include文件中。函数原型告诉编译…

深挖Java基础之:认识Java(创立空间/先导:Java认识)

今天我要介绍的是在Java中对Java的一些基本语法的认识与他们的运用,以及拟举例子说明和运用场景,优势和劣势, 注:本篇文章是对Java的一些基本的,简单的代码块的一些内容,后续会讲解在Java中的变量类型&…

Python+Selenium+Pytest+Allure PO模式UI自动化框架

一、框架结构 allure-report:测试报告base:定位元素封装data:数据log:日志文件page:页面封装文件夹report:缓存报告testcases:测试用例层utils:工具类run.py:执行文件 二…

博物馆除湿控湿保卫战:M-5J1R 电解除湿科技如何重塑文物守护的未来

在卢浮宫幽深的长廊里,达芬奇的《蒙娜丽莎》正经历着一场看不见的战争——不是来自时间的侵蚀,而是空气中无形的水分子。每一件文物都在与湿度进行着无声的抗争,这场抗争关乎人类文明的延续。湿度,这个看不见的文物杀手&#xff0…

【嘉立创EDA】如何找到曲线和直线的交点,或找到弧线和直线的交点

文章路标👉 :one: 文章解决问题:two: 主题内容:three: 参考方法be end..1️⃣ 文章解决问题 操作环境:嘉立创EDA专业版 V2.2.38 本文使用嘉立创EDA,描述如何快速找到曲线和直线交点的方法,这里的曲线包括了弧线等。本文将此过程记录,以供有需要的读者参考。 2️⃣ 主题…