news 2026/9/3 21:38:18

Python提取PDF表格:主流库对比与实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python提取PDF表格:主流库对比与实战指南

PDF 表格提取,是 Python 技术社区里一个高频出现、但每次做都容易卡壳的需求。财务对账要读银行流水 PDF,数据分析师要整理年报中的财务报表,行政要从扫描版公告里摘录名单,开发者在 CSV 和 Excel 之外遇到这种“半结构化”数据源时,第一反应往往是打开 PDF 手动复制。手动复制带来的问题大家都知道:格式错乱、数字精度丢失、多页表格合并困难,更别提几十个文件批量处理。这篇博客想用一套完整思路帮你解决这类问题,核心判断先放在前面:Python 提取 PDF 表格,没有万能工具,真正的关键是理解表格在 PDF 里的存在形式,然后选择正确的库和参数组合。

我见过不少开发者把精力都花在“找最厉害的库”上,却在第一个示例脚本里就卡在环境依赖、表格线检测和中文编码上。所以这篇文章会从最基础的概念讲起,对比 pdfplumber、camelot、tabula-py 三套主流方案的选型差异,然后给出可以直接运行的完整示例,最后把真实的排错经验整理成清单。无论你是刚接触 Python 的初学者,还是已经在项目中折腾过 PDF 提取的老手,都能从中找到对应阶段的答案。

1. 为什么“提取 PDF 表格”比想象中更难

PDF 本身是一种面向打印和排版的设计格式,而不是面向数据交换的结构化格式。Word 或 Excel 文件在保存时会保留段落、行列、单元格等语义信息,而 PDF 里只有“形状、线条、文字坐标”这些视觉层级的元素。换句话说,PDF 中的表格对人和打印机来说是清晰的,但对程序来说只是一堆文字块和线段的集合,没有直接的“row”“column”概念。

这意味着,Python 提取 PDF 表格的底层逻辑并不是“读取表格”,而是“通过分析文字坐标和线条位置,重新推断出表格结构”。这个过程会受到很多因素干扰:表格有没有完整边框线、文字和线是否精确对齐、单元格内是否换行、表格是否跨页、PDF 本身是文字版还是扫描图片版。很多初学者以为代码写不出来是自己的问题,实际上很可能是选错了工具——用面向“有边框表格”的工具去处理“无边框表格”,结果自然不理想。

手动复制表格的真正成本也常常被低估。单次复制几行数据可能看不出问题,但批量处理几十个 PDF、每个文件包含上百行数据时,人工操作的时间消耗、复制产生的数字格式错误、多页表头无法自动匹配,这些问题累计起来会让整个流程极其脆弱。自动化的价值不只是在“省时间”,更是让处理过程可重复、可审计、可追踪。用 Python 脚本跑一遍,输出结果有日志、有数据文件,出了问题可以追溯,这是任何人工作业都做不到的。

所以,在动手写代码之前,先建立一个认知:提取 PDF 表格的核心难点不是代码语法,而是判断表格在 PDF 中的视觉呈现方式,并选择匹配的解析策略。

2. 主流方案对比:pdfplumber、camelot、tabula-py

Python 生态中处理 PDF 表格的方案很多,但真正被广泛使用的是下面这三个库。它们各自对应的解析原理不同,适用场景也因此有明显的差异。

库名称解析原理优点局限适合场景
pdfplumber基于 pdfminer.six 解析文字坐标,通过线条和文字布局推断表格结构安装简单,API 直观,对文字型 PDF 效果稳定,支持自定义表格线检测策略对无边框表格需要调参,对复杂合并单元格处理不完美大多数常规文字型 PDF,作为首选方案
camelot基于 Ghostscript 将 PDF 页面转换为图像,再通过 OpenCV 识别表格线对有线表格识别能力强,支持 lattice 和 stream 两种模式,能输出表格置信度Windows 环境依赖 Ghostscript,安装相对麻烦,对扫描件仍需 OCR 配合有清晰表格线的报告、论文、财报
tabula-py对 tabula-java 的 Python 封装,底层依赖 Java 环境对线条表格解析效率高,支持批量提取和输出 DataFrame需要安装 Java 运行环境,对无边框表格依赖参数调整已有 Java 环境,需要快速提取有线表格的场景

判断依据其实很简单:如果 PDF 是从 Word、Excel 或 HTML 导出的文字版,表格线完整、文字清晰,pdfplumber 是最稳的选择。如果表格线比较复杂,或者已经出现多级嵌套表头,camelot 的 lattice 模式往往有更好的表现。如果项目本身就是 Java 技术栈,或者你不想引入过多 Python 依赖,tabula-py 值得尝试。

从我个人经验看,在没有特殊原因的情况下,建议优先选择 pdfplumber。原因有三点:第一,它是纯 Python 实现,用 pip 安装即可,不需要额外安装 Java 或 Ghostscript;第二,它的社区活跃度最高,遇到问题基本能在 GitHub issues 中找到答案;第三,它的table_settings参数体系足够灵活,能够应对大部分无边框表格场景。接下来这篇文章的实操部分也以 pdfplumber 为主线演示。

3. 环境准备与依赖安装

为了避免“代码没问题,环境跑不起来”的尴尬,建议先用最小环境把依赖装好,再进入具体功能开发。

环境基本要求:

  • Python 3.8 及以上版本,本文演示使用 Python 3.10,版本以你本机实际环境为准。
  • 建议使用虚拟环境,避免污染全局 Python 环境。
  • 建议使用 pip 安装依赖,本文不涉及 conda 环境的特殊配置。

创建并激活虚拟环境的方式如下:

# Windows python -m venv pdf_env pdf_env\Scripts\activate # macOS / Linux python3 -m venv pdf_env source pdf_env/bin/activate

激活虚拟环境后,安装本文需要的依赖库:

pip install pdfplumber pandas openpyxl

这里说明一下三个依赖的作用:

  • pdfplumber:负责 PDF 页面解析和表格结构识别。
  • pandas:负责处理提取后的二维表格数据,方便后续清洗和导出。
  • openpyxl:pandas 导出 Excel 时的底层引擎,负责把 DataFrame 写入 xlsx 文件。

安装完成后,可以用下面的命令检查 pdfplumber 是否导入正常:

python -c "import pdfplumber; print(pdfplumber.__version__)"

如果安装的是最新稳定版,会正常输出版本号。如果出现ModuleNotFoundError,说明依赖没有安装成功,优先检查 pip 源是否可用,或者换成国内镜像源重试:

pip install pdfplumber pandas openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple

如果你的目标文件是扫描版 PDF,也就是图片而不是文字层,还需要额外安装 OCR 工具。这个场景在后面排错部分单独展开,先不引入额外的复杂度。

4. pdfplumber 核心概念:从页面到表格

pdfplumber 的设计理念非常直接:一个 PDF 文件由多个页面(Page)组成,每个页面包含文字、线条、矩形等元素。提取表格的过程,就是针对某个页面调用extract_table()extract_tables()方法,让库根据页面上的线条和文字位置推断表格结构。

两个方法的区别需要特别注意:

  • extract_table():提取页面中第一个表格,返回一个二维列表。
  • extract_tables():提取页面中所有表格,返回一个三维列表,外层是表格列表,中间是行,内层是单元格。

实际项目中最常见的问题是把这两个方法搞混,导致数据结构解析不一致。比如extract_table()返回的是List[List[str]],而extract_tables()返回的是List[List[List[str]]],两者差了一层嵌套,遍历方式完全不同。

另一个核心概念是table_settings参数。很多人在用 pdfplumber 时把它当黑盒,一旦表格识别不出来就不知道怎么办。实际上,table_settings控制了表格线检测策略、文字对齐策略、单元格合并策略等多个关键逻辑。以vertical_strategyhorizontal_strategy为例,两个最常用的选项:

策略值含义适用场景
lines只使用明确检测到的直线表格线完整清晰
text根据文字坐标推断边界没有表格线、但文字排列整齐
explicit手动指定边界位置页面上有复杂干扰元素

理解这个参数之后再回头看问题:很多“为什么没提取出来”的案例,本质上是策略选择错误。一个没有边框线的表格,用默认的lines策略自然识别不到任何结构。

如果你觉得参数太多记不住,可以先按下面的默认配置跑通,再根据输出结果逐项调整:

table_settings = { "vertical_strategy": "lines", "horizontal_strategy": "lines", "snap_tolerance": 3, }

这组配置的意思很直白:优先按照绘制出来的线条识别表格。适应性虽然一般,但作为理解工具的起点足够了。

5. 实战一:提取单个 PDF 中的完整表格

我先从一个最简单的场景开始:一个文字版的 PDF,包含一张有完整边框线的表格,目标是提取成 DataFrame 并导出 Excel。

完整示例代码如下:

# 文件路径:extract_single.py import pdfplumber import pandas as pd def extract_table_from_pdf(pdf_path, page_number=0): """ 从 PDF 指定页面提取第一个表格 :param pdf_path: PDF 文件路径 :param page_number: 页面索引,从 0 开始 :return: DataFrame """ with pdfplumber.open(pdf_path) as pdf: page = pdf.pages[page_number] table = page.extract_table() if not table: raise ValueError(f"第 {page_number + 1} 页未检测到表格") # 第一行作为表头 header = table[0] rows = table[1:] # 去除单元格中多余空白 header = [str(cell).strip() if cell else "" for cell in header] cleaned_rows = [] for row in rows: cleaned_row = [str(cell).strip() if cell else "" for cell in row] cleaned_rows.append(cleaned_row) df = pd.DataFrame(cleaned_rows, columns=header) return df if __name__ == "__main__": df = extract_table_from_pdf("sample.pdf", page_number=0) print(df.head()) df.to_excel("output.xlsx", index=False) print("提取完成,结果已保存到 output.xlsx")

这段代码包含几个关键设计:

  1. 使用with pdfplumber.open(pdf_path) as pdf确保文件资源正确释放。
  2. 提取到的原始表格很可能包含空白字符,使用strip()统一清洗。
  3. 表头选取逻辑是第一行,这一选择并不总是正确,在使用前先查看 PDF 中是否需要跳行。
  4. 最后用 pandas 导出 Excel,方便后续做数据分析和进一步处理。

运行方式很简单:

python extract_single.py

如果一切正常,会看到 DataFrame 的预览输出,同时生成一个output.xlsx文件。如果输出为None,说明当前页面没有检测到表格,需要优先检查 PDF 是否包含文字层,以及表格是否有完整边框线。

6. 实战二:提取页面中所有表格并分别导出

真实业务中一个页面经常包含多个表格,或者表格被分割在不同区域。例如财务报表中,页面顶部是主要数据表格,底部是附注说明。这种情况下,需要提取页面内所有表格。

代码思路与单个表格类似,区别在于方法和数据结构的处理:

# 文件路径:extract_all_tables.py import pdfplumber import pandas as pd from pathlib import Path def extract_all_tables(pdf_path, output_dir="output"): """ 提取 PDF 所有页面的所有表格,导出到同目录下的 xlsx 文件 """ output_path = Path(output_dir) output_path.mkdir(exist_ok=True) with pdfplumber.open(pdf_path) as pdf: for page_idx, page in enumerate(pdf.pages): tables = page.extract_tables() if not tables: continue for table_idx, table in enumerate(tables): df = pd.DataFrame(table) # 清理单元格空白 df = df.map(lambda x: str(x).strip() if x else "") # 如果第一行是表头,按需自行指定 file_name = f"page{page_idx + 1}_table{table_idx + 1}.xlsx" df.to_excel(output_path / file_name, index=False, header=False) print(f"已保存:{file_name},行数 {len(df)}") if __name__ == "__main__": extract_all_tables("monthly_report.pdf")

这里有一个值得注意的细节:extract_tables()返回的表格中,第一行不一定是表头。因为 PDF 中经常出现“表格上方有一段说明文字”或者“表格标题行有合并单元格”的情况,程序无法自动判断语义上的表头。最稳妥的做法是先用header=False导出原始数据,再通过人工确认或后续逻辑指定表头行。

如果项目对列名有严格要求,可以改用下面的方式手动指定表头:

df = pd.DataFrame(rows) df.columns = ["项目", "金额", "备注"]

但前提是,你已经确认 PDF 中表格的列顺序固定。在处理批量文件时,可以在配置文件里维护列名映射,避免在代码中硬编码。

7. 实战三:复杂场景——无边框表格、合并单元格与跨页表格

基础场景跑通之后,真正的工作才刚刚开始。现实中的 PDF 表格往往不会那么规整,我选三个最高频的复杂场景展开。

7.1 无边框表格

很多从网页或 HTML 导出的 PDF,视觉上看起来有网格线,但实际上是单元格填充色或间距造成的视觉效果,并不存在真正的直线对象。这种场景下,默认的lines策略完全没有用。

解决办法是把策略切换到text

settings_no_lines = { "vertical_strategy": "text", "horizontal_strategy": "text", "snap_tolerance": 5, "join_tolerance": 5, "edge_min_length": 3, "min_words_vertical": 2, "min_words_horizontal": 2, }

其中几个参数的意义:

  • snap_tolerance:相近的 y 坐标允许合并为同一行的容差,单位是点。值太大会导致不同行误合并,值太小会导致同一行文字被拆成多行。
  • join_tolerance:相近的 x 坐标允许连接为同一列的容差。
  • min_words_vertical:形成垂直边界所需的最少文字数量,防止把零散文字误判为列。
  • min_words_horizontal:形成水平边界所需的最少文字数量。

调整参数时,建议先用page.debug_tablefinder(settings)把表格识别结果可视化,逐参数观察边界线的变化。pdfplumber 提供了非常方便的可视化调试工具,生成的结果是一个图片文件,可以直观看到识别的边界和实际表格是否吻合。

7.2 合并单元格

合并单元格在 PDF 中的本质是:一个逻辑单元格跨越多行或多列,但视觉上只是一个矩形区域。pdfplumber 提取后,合并单元格通常会在扩展的位置填充None

举个例子,下面这样的原始表:

部门姓名绩效
技术部 张三 80李四 90王五 85
市场部 赵六 78孙七 92周八 88

提取后可能得到:

[ ["部门", "姓名", "绩效"], ["技术部", "张三", "80", "技术部", "李四", "90", "技术部", "王五", "85"] ]

处理方式是按需填充缺失值,或者按位置重建表格结构。常见做法是使用 pandas 的向前填充:

df = df.ffill()

但要先确认哪些列存在合并单元格。如果用 pandas 的ffill()处理了所有列,可能会把本来应该为空的单元格错误填充。更稳妥的做法是只在已知的合并列上做填充:

df["部门"] = df["部门"].ffill()

7.3 跨页表格

跨页表格分成两类:一类是表头在每页重复出现,另一类是表格中间直接断开,第二页继续。

第一类场景相对好处理:逐页提取后,删除重复表头行,再拼接所有数据。示例:

import pdfplumber import pandas as pd def extract_multi_page_table(pdf_path, header_row_marker="项目名称"): all_rows = [] with pdfplumber.open(pdf_path) as pdf: for page in pdf.pages: tables = page.extract_tables() for table in tables: for row in table: row_text = [cell.strip() if cell else "" for cell in row] # 如果当前行是表头行,跳过 if row_text and row_text[0] == header_row_marker: continue all_rows.append(row_text) df = pd.DataFrame(all_rows) return df

第二类场景更复杂,表格从页面底部断开,表头只在第一页出现。这种处理需要考虑列数的对齐,最直观的做法是设置一个目标列数,把每页提取结果按列数补齐。例如:

target_cols = 5 for row in page_rows: if len(row) < target_cols: row.extend([""] * (target_cols - len(row)))

然后拼接所有页的行数据。如果拼接后仍然出现错位,可能需要在调整table_settings的同时,手动指定表格边界区域,例如只提取页面上半部分的表格:

settings_area = { "vertical_strategy": "lines", "horizontal_strategy": "lines", "snap_tolerance": 3, "explicit_vertical_lines": [50, 300, 545], "explicit_horizontal_lines": [80, 200, 320, 440], }

使用explicit_vertical_linesexplicit_horizontal_lines时,需要先通过调试可视化的方式获取线条的坐标。这个功能虽然操作门槛稍高,但处理复杂版式时非常可靠。

8. 常见问题与排查思路

以下是我从实际使用中整理的高频问题清单,每个问题都配合了排查路径,方便直接对照。

问题现象可能原因排查方式解决方案
extract_table()返回None页面中没有检测到表格线,或表格为无边框样式page.debug_tablefinder()可视化查看识别结果切换vertical_strategyhorizontal_strategytext
提取结果列数错位页面中存在合并单元格或表格线断裂打印原始table列表,观察None位置按需使用 ffill 或手动指定表格边界
中文显示乱码PDF 内嵌字体编码异常查看 PDF 是否包含正常文字层;用pdfplumber提取单行文字测试优先考虑对字符进行 post-process,或换用 OCR 方案
扫描版 PDF 无法提取PDF 本质是图片,没有文字层用 PDF 阅读器搜索关键词,搜索不到说明无文字层引入 OCR(如 PaddleOCR)先识别文字再提取表格
提取结果大量重复表头每页都有重复表头行打印每页首行,确认表头内容拼接时按内容过滤重复表头
tabula-py 报java.lang.Exception本机未安装 Java 或 Java 版本过低命令行执行java -version安装 Java 8 及以上版本
camelot 安装失败,提示 Ghostscript 相关错误Windows 环境缺少 Ghostscript 可执行文件检查 Ghostscript 是否安装下载安装 Ghostscript 并配置系统环境变量
提取速度过慢大文件 PDF、高精度图片解析检查是否误使用了图像模式,统计页面数量仅解析需要的页面;必要时提升硬件性能
导出 Excel 后列宽过窄默认列宽不匹配正常现象,Excel 不会自适应列宽在代码中通过 openpyxl 调整列宽,或手动调整

9. 最佳实践与工程建议

技术实验跑通之后,真正决定项目质量的是工程层面的细节。我总结了下面几条建议,帮你避免在正式交付阶段踩坑。

9.1 先做“探查”再写“主程序”

拿到一个 PDF,不要立刻写完整提取逻辑。先打印页数、每页包含的表格数量、表格的行列结构。用page.debug_tablefinder()输出可视化结果,确认策略和参数是否合适。这个步骤虽然多花 5 分钟,但能省掉后面几个小时的调试时间。

import pdfplumber with pdfplumber.open("sample.pdf") as pdf: print(f"PDF 总页数: {len(pdf.pages)}") for i, page in enumerate(pdf.pages): tables = page.extract_tables() print(f"第 {i + 1} 页检测到 {len(tables)} 个表格") for j, table in enumerate(tables): print(f" 第 {j + 1} 个表格: {len(table)} 行, {len(table[0])} 列")

9.2 统一数据清洗流程

PDF 提取的原始数据几乎总是带有多余空格、换行符、全角半角混用等情况。建议每列定义独立的清洗函数,避免所有列一刀切。

def clean_cell(cell_value): if cell_value is None: return "" # 替换不换行空格和竖线等特殊字符 return " ".join(cell_value.split())

9.3 输出格式选择

表格提取结果常见的输出格式是 CSV、Excel、DataFrame、JSON。如果后续要入数据库,CSV 或 JSON 更通用;如果给业务人员做二次编辑,Excel 更友好。导出 CSV 时要注意编码问题,推荐使用utf-8-sig,避免 Excel 打开中文乱码。

df.to_csv("output.csv", index=False, encoding="utf-8-sig")

9.4 保留原始页面作为审计依据

自动提取无法保证 100% 准确。建议在输出结果中保留一列“来源页码”,并在交付时把原 PDF 与提取结果一起归档,方便出现争议时追溯。

9.5 性能优化方向

处理大量 PDF 时,逐页用pdfplumber解析的速度可能会偏慢。可以考虑用多进程或异步并发处理:

from concurrent.futures import ProcessPoolExecutor def process_single_pdf(pdf_path): # 提取单个 PDF 并返回 DataFrame ... with ProcessPoolExecutor(max_workers=4) as executor: results = list(executor.map(process_single_pdf, pdf_file_list))

如果并发处理时出现重复提取或异常,优先在单进程内定位问题,再拆分到多进程。

9.6 大文件内存管理

pdfplumber.open()在解析时会把页面信息加载到内存。如果一个 PDF 有几万页,逐页打开并释放成本高。可以先使用pdf.pages遍历,并及时清理不再需要的变量。必要时把文件按页拆分:

from PyPDF2 import PdfReader, PdfWriter reader = PdfReader("large.pdf") for i in range(0, len(reader.pages), 100): writer = PdfWriter() for page in reader.pages[i:i + 100]: writer.add_page(page) with open(f"chunk_{i}.pdf", "wb") as f: writer.write(f)

10. 数据处理与后续进阶方向

到这里,你已经能通过 pdfplumber 把 PDF 里的表格结构提取成 DataFrame,再输出为 Excel 或 CSV。但提取只是第一步,真正有价值的往往是后续的数据处理。

常见的数据处理需求包括:字段类型转换。PDF 提取的数字经常是字符串,而且可能存在千分位或币种符号,需要在进入分析流程前做类型转换;重复值筛查和异常值检测。因为 PDF 编写不规范,同一字段可能出现多种写法;多表合并。不同 PDF 文件的表格结构可能不一致,需要在合并前统一列名和数据格式;与数据库对接。提取结果最终可能需要写入 MySQL、PostgreSQL 或其他数据仓库,这时需要设计好主键和数据更新策略。

如果你处理的是扫描版 PDF,或者 PDF 中只有图片没有文字层,那么上面所有方案都会失效。这种情况下需要引入 OCR。常见的组合是 PaddleOCR 或 Tesseract 负责识别文字,再通过 pdfplumber 或自研逻辑恢复表格结构。这套流程的复杂度会明显上升,建议先用小规模样本验证识别准确率,再考虑全量自动化。

关于表格方向,如果遇到 PDF 中表格为横向排版,即页面宽度远大于高度,pdfplumber 也可以处理。只需要在打开 PDF 时确认页面旋转信息,打印page.widthpage.height,必要时用page = pdf.pages[i]配合图像旋转或坐标变换调整方向。

11. 一份可以直接复用的批处理模板

最后,我整理了一份更完整的批处理脚本模板。它做了三件有价值的事:自动遍历目录下所有 PDF;提取所有页面的所有表格;输出带来源信息和错误日志的 Excel 文件。你可以在真实项目中直接改路径和业务逻辑后使用。

# 文件路径:batch_extract_pdf_tables.py import pdfplumber import pandas as pd from pathlib import Path import logging logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") def extract_tables_from_pdf(pdf_path: Path): """ 提取一个 PDF 文件的全部表格数据,返回 DataFrame 列表 """ all_dfs = [] with pdfplumber.open(pdf_path) as pdf: for page_idx, page in enumerate(pdf.pages): tables = page.extract_tables() if not tables: continue for table_idx, table in enumerate(tables): df = pd.DataFrame(table) df = df.map(lambda x: str(x).strip() if x else "") # 增加来源信息 if len(df.columns) >= 1: df["来源页码"] = str(page_idx + 1) all_dfs.append(df) logging.info(f"{pdf_path.name} 第 {page_idx + 1} 页第 {table_idx + 1} 个表格,{len(df)} 行") return all_dfs def batch_process(pdf_dir: str): """ 批量处理目录下所有 PDF """ pdf_dir_path = Path(pdf_dir) pdf_files = list(pdf_dir_path.glob("*.pdf")) if not pdf_files: logging.warning("目录下没有找到 PDF 文件") return all_data = [] error_log = [] for pdf_file in pdf_files: try: dfs = extract_tables_from_pdf(pdf_file) for idx, df in enumerate(dfs): df["来源文件"] = pdf_file.name all_data.append(df) except Exception as e: error_log.append({"文件": pdf_file.name, "错误信息": str(e)}) logging.error(f"{pdf_file.name} 处理失败: {e}") if all_data: result = pd.concat(all_data, ignore_index=True) result.to_excel("batch_output.xlsx", index=False) logging.info(f"已输出 batch_output.xlsx,共 {len(result)} 行") if error_log: error_df = pd.DataFrame(error_log) error_df.to_excel("error_log.xlsx", index=False) logging.warning("存在失败文件,请查看 error_log.xlsx") if __name__ == "__main__": batch_process("./pdf_files")

这个脚本可以处理绝大多数常规 PDF 表格。如果你遇到某些文件提取结果不理想,最有效的调试方式是把该文件单独提取,并在代码中增加打印表格结构和可视化识别的步骤,而不是直接在批处理结果上猜。

关于表格提取后的下一步,建议结合业务需求做数据校验。比如财务数据要验证借贷平衡,人员名单要核对去重,销售报表要验证金额汇总与 PDF 原文一致。只有经过校验的数据,才能真正进入下游分析系统。这也是从“跑通脚本”走向“交付可靠工具”的关键一步。

如果没有明确的校验需求,也建议在文档中记录提取时间和提取工具版本,方便后续复现和排查。

选择 Python 处理 PDF 表格这条路,本身就是选了一条靠逻辑而不是靠点鼠标解决问题的路线。它前期需要花一点时间理解 PDF 的内在结构,构建好参数调整和排错思路,但一旦吃透,后续面对格式更乱的表格文件,你也有足够的工具去应对。希望这篇博客能帮你少走弯路,更从容地处理手头的 PDF 数据。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 19:29:31

Czkawka 磁盘清理完整指南:从重复文件扫描到相似图片分组

Czkawka 磁盘清理完整指南&#xff1a;从重复文件扫描到相似图片分组 【免费下载链接】czkawka Multi functional app to find duplicates, empty folders, similar images etc. 项目地址: https://gitcode.com/GitHub_Trending/cz/czkawka 如果你的磁盘里散落着好几份同…

作者头像 李华
网站建设 2026/9/2 11:52:46

Grok Bot强制命名是优点:从身份标识到实例管理的工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 21:38:35

Python GUI开发:从事件驱动原理到Gradio与Streamlit实战应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 11:51:22

本地部署DeepSeek Harness,打造会说话的AI角色“爱莉”

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 11:51:11

求生之路2三方图浪潮狂疫:安装、联机与高难度团队生存指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 11:50:02

2026年AI论文写作工具怎么选?3款横评差异大

论文写到凌晨两点&#xff0c;查重报告弹出来那一刻&#xff0c;整个人是懵的。重复率超标、AI检测标红、导师留言"结构再调调"——这些场景每个写过论文的人都经历过。市面上的AI论文写作工具越来越多&#xff0c;功能描述看着都差不多&#xff0c;真上手才发现差距…

作者头像 李华