使用 python camelot 实现提取 pdf 中的表格内容

场景描述

最近有个需求需要处理下从南京统计局下载的宏观数据pdf,需要将pdf中的表格数据提取出来进一步加工,样例格式如下。

可以看到格式还是比较标准的,我本来以为网上随便一搜python pdf table提取,便能简单的处理大功搞成,然而实际还是踩了不少坑,因此还是记录下。

具体的pdf这里就不展示了,以camelot的样例pdf为例,下载可以点击此链接

技术选型

首先,我确实是在网上搜索python pdf table extract,基本很快就锁定了 pdfplumber,然而在一通操作后,发现pdfplumber的默认识别不太准确,一个很大的原因是pdf的表格很多并不是以标准的线画的,虽然可以使用text方式识别+定制化的一些参数,但是调整太累了,后面本人就放弃了。pdfplumber的官方文档参见pdfplumbergit地址,里面对于一些对象及配置有详尽的描述。另外,知乎的这篇关于python提取pdf不规则表格写得非常不错,里面有讲碰到不规则表格,提取内容错误时,如何利用 debug_tablefinder 画出红线,进而调整进阶参数以优化提取效果。

在pdfplumber碰壁后,继而了解到camelot在无线框表格上效果更好,因此果断尝试,不得不说最终的效果还是不错的。

camelot的git地址参见camelot git 地址,相对来说,camelot的文档就没有那么详尽了,不得不说是一个遗憾。

环境安装

camelot的安装挺坑的。。。,以下只是本人的安装和解决方案。

1. camelot安装

千万不要直接使用pip install camelot进行安装,真正的命令为

1
2
pip install camelot-py
pip install opencv-python

安装完后,本人碰到了

1
Python-camelot (Error: GhostscriptNotFound 

这个问题,参考网上的,到ghostscript官网下载对应的版本。

本人为windows,因此下载了ghostscript-10.01.1.tar.xz,解压完需要添加

1
2
C:\Program Files\gs\gs9.26\bin
C:\Program Files\gs\gs9.26\lib

到path下,不然依然会报错。

最后,你需要安装下ghostscript

1
pip install ghostscript

不然会得到以下错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PS C:/Users/ivan/AppData/Local/Programs/Python/Python311/python tjj_hgsj_py/nj_tjj.py
Traceback (most recent call last):
File "tjj_hgsj_py\nj_tjj.py", line 20, in <module>
tables= camelot.read_pdf(pdfFilePath)####从1开始计数
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\ivan\AppData\Local\Programs\Python\Python311\Lib\site-packages\camelot\io.py", line 113, in read_pdf
tables = p.parse(
^^^^^^^^
File "C:\Users\ivan\AppData\Local\Programs\Python\Python311\Lib\site-packages\camelot\handlers.py", line 176, in parse
t = parser.extract_tables(
^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\ivan\AppData\Local\Programs\Python\Python311\Lib\site-packages\camelot\parsers\lattice.py", line 421, in extract_tables
self.backend.convert(self.filename, self.imagename)
File "C:\Users\ivan\AppData\Local\Programs\Python\Python311\Lib\site-packages\camelot\backends\ghostscript_backend.py", line 36, in convert
import ghostscript
ModuleNotFoundError: No module named 'ghostscript'

至此,camelot安装完成。

代码实现

具体代码可以查看 camelot_pdf_table_parse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import os
import pandas as pd
import camelot


# 读取pdf文件,获取pdf的表格数据,并保存为csv
pdfFilePath="foo.pdf"
csvFilePath="table.csv"
separate_coma=","

# 使用camelot解析table,all为解析所有的pdf page
tables= camelot.read_pdf(pdfFilePath,pages='all')
# 将所有的table 拼接为一个df
table_df=tables[0].df
for i in range(1,len(tables)):
table_df=table_df._append(tables[i].df)
# 加入自定义字段
table_df['report_date']='2023-02-28'
# 调整顺序,放入第一个
table_df.insert(0,'report_date',table_df.pop('report_date'))
print(table_df)
# 保存为csv文件,为后续入库方便,去除index
table_df.to_csv(csvFilePath,index=None)
print("foo table data finished")

整体代码就想对比较简单了,但是也有一些细节需要处理,方能最后使用,比如

  • 读取所有page,camelot默认只读取pdf的第一页,因此需要all参数。
  • 拼接dataframe
  • 新增自定义列
  • 保存csv去除行号

实现效果

pdf原始表格

提取后的dataframe效果

1
2
3
4
5
6
7
8
  report_date             0            1                2                     3                  4                  5                 6
0 2023-02-28 Cycle \nName KI \n(1/km) Distance \n(mi) Percent Fuel Savings
1 2023-02-28 Improved \nSpeed Decreased \nAccel Eliminate \nStops Decreased \nIdle
2 2023-02-28 2012_2 3.30 1.3 5.9% 9.5% 29.2% 17.4%
3 2023-02-28 2145_1 0.68 11.2 2.4% 0.1% 9.5% 2.7%
4 2023-02-28 4234_1 0.59 58.7 8.5% 1.3% 8.5% 3.3%
5 2023-02-28 2032_2 0.17 57.8 21.7% 0.3% 2.7% 1.2%
6 2023-02-28 4171_1 0.07 173.9 58.1% 1.6% 2.1% 0.5%

最终的csv文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
report_date,0,1,2,3,4,5,6
2023-02-28,"Cycle
Name","KI
(1/km)","Distance
(mi)",Percent Fuel Savings,,,
2023-02-28,,,,"Improved
Speed","Decreased
Accel","Eliminate
Stops","Decreased
Idle"
2023-02-28,2012_2,3.30,1.3,5.9%,9.5%,29.2%,17.4%
2023-02-28,2145_1,0.68,11.2,2.4%,0.1%,9.5%,2.7%
2023-02-28,4234_1,0.59,58.7,8.5%,1.3%,8.5%,3.3%
2023-02-28,2032_2,0.17,57.8,21.7%,0.3%,2.7%,1.2%
2023-02-28,4171_1,0.07,173.9,58.1%,1.6%,2.1%,0.5%

踩坑点及解决方法

Python-camelot (Error: GhostscriptNotFound

需要安装ghostscript
ghostscript官网下载对应的版本。

ModuleNotFoundError: No module named ‘ghostscript’

安装完ghostscript程序后,还需安装ghostscript模块

1
pip install ghostscript

camelot只能读取pdf的第一页

参数需要填all

1
2
tables= camelot.read_pdf(pdfFilePath,pages='all')