一、Camelot库核心概述
Camelot是一款专为从PDF文件中精确提取表格数据而生的Python库,它能将PDF里的表格转换为Pandas DataFrame或CSV、JSON等格式,极大降低了PDF表格数据处理的门槛。其工作原理是通过两种核心算法(Lattice和Stream)识别表格:Lattice适用于有清晰边框线的表格,通过检测线条来定位单元格;Stream适用于无边框表格,依靠文本的位置和间距来划分单元格。

该库的优点十分突出:提取精度高、支持自定义配置、输出格式灵活、完全免费开源;缺点则是对扫描版PDF(图片型PDF)无效,仅支持文本型PDF,且对复杂嵌套表格的处理能力有限。Camelot采用MIT License开源协议,允许开发者自由使用、修改和分发,无商业使用限制。
二、Camelot库安装步骤
Camelot的安装分为基础安装和依赖补充两个部分,因为它依赖于Ghostscript等第三方工具,不同操作系统的安装流程略有差异,以下是详细的安装指南。
2.1 安装Ghostscript依赖
Ghostscript是Camelot识别PDF表格的核心依赖,必须优先安装。
- Windows系统
访问Ghostscript官方下载地址(https://www.ghostscript.com/releases/gsdnld.html),下载对应版本的安装包,按照安装向导完成安装。安装完成后,需要将Ghostscript的可执行文件路径添加到系统环境变量中,例如默认路径为C:\Program Files\gs\gs10.02.1\bin。 - macOS系统
使用Homebrew包管理器执行以下命令安装:bash brew install ghostscript - Linux系统(Ubuntu/Debian)
执行apt-get命令安装:bash sudo apt-get install ghostscript
2.2 安装Camelot库
完成Ghostscript安装后,通过pip命令即可安装Camelot库,建议使用Python3.6及以上版本:
pip install camelot-py[cv]这里的[cv]表示安装包含OpenCV依赖的完整版,OpenCV有助于提升表格识别的准确率。安装完成后,可以在Python环境中执行以下代码验证是否安装成功:
import camelot
print(camelot.__version__)如果代码能正常输出Camelot的版本号,说明安装成功。
三、Camelot库核心用法与代码实例
Camelot的核心操作流程是读取PDF文件→配置提取参数→提取表格→导出/处理数据,下面将详细讲解两种核心提取算法的使用方法,并结合代码实例进行演示。
3.1 核心概念:Lattice与Stream算法
在使用Camelot提取表格前,需要先明确PDF表格的类型,从而选择对应的算法:
- Lattice算法:默认算法,适用于有明确边框线的表格,例如Excel导出的PDF表格、财务报表等。该算法通过检测表格的竖线和横线来确定单元格的边界,提取精度极高。
- Stream算法:适用于无边框线的表格,例如纯文本排版的表格、网页导出的无框PDF表格等。该算法通过分析文本块的位置、间距和对齐方式,来推断表格的结构。
3.2 基础用法:提取单页PDF表格
首先准备一个测试用的PDF文件(例如test_table.pdf),该文件的第1页包含一个有边框的表格。下面的代码将演示如何使用Lattice算法提取该表格。
3.2.1 代码实例:Lattice算法提取有边框表格
import camelot
# 读取PDF文件,指定提取第1页的表格,使用Lattice算法
tables = camelot.read_pdf(
'test_table.pdf', # PDF文件路径
pages='1', # 指定提取的页码,支持多页如'1,3,5'或范围'1-5'
flavor='lattice' # 指定提取算法为lattice
)
# 打印提取到的表格数量
print(f"提取到的表格数量:{len(tables)}")
# 查看第一个表格的基本信息
print("第一个表格的基本信息:")
print(tables[0].parsing_report) # 输出解析报告,包含精度、页数等信息
# 将表格转换为Pandas DataFrame
df = tables[0].df
print("\n表格数据(DataFrame格式):")
print(df)
# 将表格导出为CSV文件
tables[0].to_csv('extracted_table.csv')
print("\n表格已导出为extracted_table.csv")
# 将表格导出为JSON文件
tables[0].to_json('extracted_table.json')
print("表格已导出为extracted_table.json")3.2.2 代码说明
camelot.read_pdf()是核心函数,用于读取PDF并提取表格,返回一个TableList对象,包含所有提取到的表格。pages参数用于指定提取的页码,支持单页、多页和页码范围,例如pages='1-3'表示提取第1到3页的表格。flavor参数指定算法类型,lattice为默认值,适用于有边框表格。tables[0].parsing_report会输出解析报告,包含accuracy(提取精度)、whitespace(空白占比)、page(页码)等信息,精度越高说明提取效果越好。tables[0].df将表格转换为Pandas DataFrame,方便后续的数据清洗和分析。to_csv()和to_json()方法可以将表格导出为对应的文件格式,便于分享和存储。
3.2.3 代码实例:Stream算法提取无边框表格
如果需要提取的PDF表格没有边框线,就需要使用stream算法,同时可以通过table_regions参数指定表格所在的区域,提升提取精度。
import camelot
# 读取PDF文件,使用Stream算法提取无边框表格
tables = camelot.read_pdf(
'test_no_border_table.pdf',
pages='1',
flavor='stream',
table_regions=['20, 700, 500, 300'] # 指定表格的坐标区域:x1, y1, x2, y2
)
# 输出解析报告
print("解析报告:")
print(tables[0].parsing_report)
# 查看表格数据
df = tables[0].df
print("\n无边框表格数据:")
print(df)
# 导出为Excel文件(需要安装openpyxl库)
tables[0].to_excel('extracted_no_border_table.xlsx', index=False)
print("\n无边框表格已导出为extracted_no_border_table.xlsx")3.2.4 代码说明
flavor='stream'指定使用Stream算法,适用于无边框表格。table_regions参数的作用是限定表格的提取区域,坐标格式为[x1, y1, x2, y2],其中(x1, y1)是区域的左上角坐标,(x2, y2)是右下角坐标。该参数可以避免PDF中的其他文本干扰表格提取,大幅提升准确率。to_excel()方法可以将表格导出为Excel文件,使用前需要安装openpyxl库,执行pip install openpyxl即可。
3.3 高级用法:自定义提取参数
Camelot提供了丰富的自定义参数,用于处理复杂的PDF表格,例如合并单元格、调整列间距、过滤空白行等。下面的代码将演示如何使用这些参数优化提取效果。
3.3.1 代码实例:处理合并单元格与空白行
import camelot
# 读取包含合并单元格的PDF表格
tables = camelot.read_pdf(
'test_merge_cells.pdf',
pages='1',
flavor='lattice',
strip_text='\n', # 去除单元格内的换行符
suppress_stdout=True # 抑制控制台输出的冗余信息
)
# 查看原始提取的表格数据
print("原始提取数据(含合并单元格):")
print(tables[0].df)
# 处理合并单元格:通过DataFrame的fillna方法填充合并单元格的内容
df = tables[0].df
# 向前填充空值,适用于垂直合并的单元格
df = df.fillna(method='ffill', axis=0)
# 向左填充空值,适用于水平合并的单元格
df = df.fillna(method='ffill', axis=1)
print("\n处理合并单元格后的数据:")
print(df)
# 过滤空白行:删除所有元素均为空的行
df = df.dropna(how='all')
print("\n过滤空白行后的数据:")
print(df)3.3.2 代码说明
strip_text='\n'参数用于去除单元格内的换行符,使文本内容更整洁。suppress_stdout=True参数可以抑制Camelot在控制台输出的冗余日志信息,让输出更简洁。- 合并单元格在提取后会表现为
NaN值,通过Pandas的fillna()方法,使用ffill(向前填充)策略,可以快速填充合并单元格的内容,还原表格的真实结构。 dropna(how='all')方法用于删除所有元素均为空的行,适用于清理包含大量空白行的表格数据。
3.3.3 代码实例:提取多页PDF中的所有表格
如果PDF文件包含多个页面,且每个页面都有表格,可以通过pages='all'参数提取所有页面的表格,并批量导出。
import camelot
import os
# 创建输出目录
output_dir = 'multi_page_tables'
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# 提取多页PDF中的所有表格
tables = camelot.read_pdf(
'multi_page_test.pdf',
pages='all',
flavor='lattice'
)
print(f"共提取到 {len(tables)} 个表格")
# 批量导出所有表格为CSV文件
for i, table in enumerate(tables):
table.to_csv(os.path.join(output_dir, f'table_{i+1}.csv'))
print(f"表格 {i+1} 已导出到 {output_dir}/table_{i+1}.csv")3.3.4 代码说明
pages='all'参数表示提取PDF文件中所有页面的表格,无需手动指定页码。- 通过
enumerate()遍历TableList对象中的每个表格,批量导出为CSV文件,并按序号命名,方便管理。 - 使用
os.makedirs()创建输出目录,避免因目录不存在导致的导出失败。
四、实际应用案例:PDF财务报表数据提取与分析
下面将结合一个实际的应用场景——提取PDF格式的财务报表中的利润表数据,并进行简单的数据分析,演示Camelot库在实际工作中的使用价值。
4.1 案例背景
假设我们有一份名为2024_financial_report.pdf的PDF文件,其中第3页是公司的利润表,表格为有边框格式,包含“项目”“2023年”“2024年”三列数据。我们需要提取该表格数据,并分析2024年相较于2023年的营收变化情况。
4.2 代码实例:数据提取与分析
import camelot
import pandas as pd
import matplotlib.pyplot as plt
# 步骤1:提取PDF中的利润表数据
tables = camelot.read_pdf(
'2024_financial_report.pdf',
pages='3',
flavor='lattice',
strip_text='\n'
)
# 步骤2:转换为DataFrame并清洗数据
profit_df = tables[0].df
# 设置列名:假设表格第一行是表头
profit_df.columns = profit_df.iloc[0]
profit_df = profit_df.drop(0, axis=0)
# 重置索引
profit_df = profit_df.reset_index(drop=True)
# 过滤掉空行
profit_df = profit_df.dropna(how='all')
print("清洗后的利润表数据:")
print(profit_df)
# 步骤3:数据类型转换(将金额列转换为数值类型)
# 假设金额列名为“2023年”和“2024年”
profit_df['2023年'] = pd.to_numeric(profit_df['2023年'], errors='coerce')
profit_df['2024年'] = pd.to_numeric(profit_df['2024年'], errors='coerce')
# 步骤4:分析营收变化——筛选“营业收入”行
revenue_row = profit_df[profit_df['项目'].str.contains('营业收入', na=False)]
if not revenue_row.empty:
revenue_2023 = revenue_row['2023年'].values[0]
revenue_2024 = revenue_row['2024年'].values[0]
revenue_growth = (revenue_2024 - revenue_2023) / revenue_2023 * 100
print(f"\n2023年营业收入:{revenue_2023:.2f} 万元")
print(f"2024年营业收入:{revenue_2024:.2f} 万元")
print(f"营业收入增长率:{revenue_growth:.2f}%")
# 步骤5:可视化营收变化
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决中文显示问题
plt.figure(figsize=(8, 5))
years = ['2023年', '2024年']
revenues = [revenue_2023, revenue_2024]
plt.bar(years, revenues, color=['#3498db', '#e74c3c'])
plt.title('2023-2024年营业收入对比')
plt.ylabel('营业收入(万元)')
for i, v in enumerate(revenues):
plt.text(i, v + 100, f'{v:.2f}', ha='center')
plt.savefig('revenue_comparison.png', dpi=300, bbox_inches='tight')
plt.show()
else:
print("\n未找到营业收入相关数据")4.3 案例说明
- 数据提取:使用Lattice算法提取PDF第3页的利润表数据,通过
strip_text='\n'清理单元格内的换行符。 - 数据清洗:将表格的第一行设为列名,删除表头行和空行,确保数据结构整洁。
- 类型转换:将金额列从字符串类型转换为数值类型,以便进行数学计算,
errors='coerce'参数可以将无法转换的值设为NaN。 - 数据分析:通过筛选包含“营业收入”的行,计算2024年相较于2023年的营收增长率。
- 数据可视化:使用Matplotlib绘制柱状图,直观展示两年的营业收入对比情况,并解决中文显示问题。
这个案例充分体现了Camelot库在实际工作中的价值——从PDF中快速提取结构化数据,结合Pandas和Matplotlib完成数据分析与可视化,大大提升了工作效率。
五、Camelot库常见问题与解决方案
在使用Camelot的过程中,可能会遇到一些常见问题,下面列出了这些问题的解决方案:
- 问题1:提取到的表格为空或不完整
- 解决方案:检查PDF是否为文本型PDF(扫描版PDF无法提取);使用
table_regions参数指定表格区域;尝试切换lattice和stream算法;调整edge_tol参数(边缘容差)或row_tol参数(行容差)。
- 解决方案:检查PDF是否为文本型PDF(扫描版PDF无法提取);使用
- 问题2:报错“Ghostscript not found”
- 解决方案:确认Ghostscript已正确安装,并将其路径添加到系统环境变量中;重启Python环境后重试。
- 问题3:合并单元格处理不彻底
- 解决方案:提取数据后,使用Pandas的
fillna()方法手动填充NaN值;对于复杂的合并单元格,可以结合df.replace()方法进行处理。
- 解决方案:提取数据后,使用Pandas的
- 问题4:多页PDF提取效率低
- 解决方案:避免使用
pages='all'提取不必要的页面,手动指定需要提取的页码;关闭suppress_stdout=False查看详细日志,定位耗时较长的页面。
- 解决方案:避免使用
六、相关资源链接
- Pypi地址:https://pypi.org/project/camelot-py
- Github地址:https://github.com/camelot-dev/camelot
- 官方文档地址:https://camelot-py.readthedocs.io/en/master/
关注我,每天分享一个实用的Python自动化工具。

