最近做了一个需要解析财报pdf的项目,财报的格式大致一样,但是具体细节会有略微不同。
原本是使用pdfplumber来做,做到一半,发现 pdfplumber对于分页了的表格处理很不友好。
原本处理分页的表格,是将上一页的最后一个表格和下一页的第一个表格拼接,但是 pdfplumber 解析的表格出现乱序的情况,最后一个表格的位置出现在解析出的表格列表中间位置,导致合并表格数据失败。
所以中途又重新开始找解析框架,找到了 tabula,这个对于表格处理的某些方面比 pdfplumber 好,至少不会出现表格乱序的情况。
但是这个框架只支持pdf表格解析,不支持文字解析,所以最终还是 pdfplumber 和 tabula 混合使用。
总结来说:
pdfplumber:
优点:
缺点:
tabula:
优点:
缺点:
简单示例:
pdfplumber,文档地址:https://github.com/jsvine/pdfplumber
# 解析pdf
with pdfplumber.open("abc.pdf") as pdf:
# 拿到第一页的对象
page = parse_pdf.pages[0]
# 拿到这一页的文本数据
text = page.extract_text()
# 拿到这一页的所有表格数据
tables = page.extract_tables()
# 遍历表格
for t_index in range(len(tables)):
table = tables[t_index]
# 遍历每一行的数据
for data in table:
print(data)
tabula,文档地址:https://aegis4048.github.io/parse-pdf-files-while-retaining-structure-with-tabula-py
# 解析表格, stream表示流模式识别(建议),guess为猜测,pages是页面下标,从1开始
# multiple_tables是需不需要识别多个表格
tables = tabula.read_pdf(pdf_path, stream=True, guess=True, pages= [1,2],multiple_tables=True)
# 遍历表
for table in tables:
# 通过表格内置下标迭代器来遍历下标(也可能不是下标,而是id
for index in table.index:
# 获取下标所属那一行的值
data = table.loc[index].values
彩蛋(tabula 表格去除全部为空的行和列):
def format_data_frame(table):
"""
格式化data_frame表格,删除全部为空的行和列
:return:
"""
all_data = table.isna()
for t_index in all_data.index:
data = all_data.loc[t_index].values
if all(data):
table = table.drop([t_index], axis=0, inplace=False)
for clo_name in all_data.columns:
data = all_data[clo_name]
if all(data):
table = table.drop(clo_name, axis=1, inplace=False)
return table