用python提取PDF表格內容儲存到excel
阿新 • • 發佈:2018-12-13
一 提取pdf方法介紹
任務是用python提取PDF裡的表格檔案到excel裡面去。做為一個 學了一個周python的人來說當然像嘗試一下看能不能做到,事實證明是可以的只是可能程式碼有點爛。。。。。。 樣本大概是這樣的 首先網上查一下用python處理pdf檔案的方法,感覺處理pdf檔案的有好多種方法,各自有各自的特點,印象最深的是轉成html檔案的pdf2htmlEX,和提取文字的pdfminer,還有最後用的Tabula。分別介紹一下記錄。
- pdf2htmlEX 做這個的時候不怎麼了解html,而且也有人曾經嘗試過似乎挺麻煩的,所以就沒有去嘗試。
- pdfminer
pdfminer功能非常的強大,可以轉好多東西,用得到直接閱讀
- Tabula 專門用來提取pdf裡的表格的,支援匯出csv.,excel檔案 提取出來一個頁面如果有兩個表格會放到一個list裡,每個表格一個元素。一個表格一個dataframe結構的檔案,所以需要配合pandas模組使用。
二 練習專案介紹
好久之前寫了,一些細節忘記了,不過當時註釋的很清楚直接上程式碼,也是怕哪天電腦突然宕機程式碼沒了。。。換個地兒存。。。這個模組提取的效率是真的慢。。。。。聽說可以調Java的程式提取效率快三倍但是沒學Java也就沒有去了解,以後還用得到應該可以去了解一下。。。。。。
# -*- coding: utf-8 -*-
import os
import gc
from PyPDF2.pdf import PdfFileReader
from tabula import read_pdf
import pandas as pd
from openpyxl import load_workbook, Workbook
import datetime
def data_process2(dataframe2):
"""
三步:
刪除只有一個非空或者全空的列
從第一列開始往後合併直到遇到只有第一列不為空或者全不為空則處理下一步
遇到只有第一行不為空則檢查接下來的第三行如果一樣情況則接下來三行合併成一行
"""
#此迴圈處理只有一個非空或者全空列的情況,防止影響下面的處理
k = 0
while True:
if dataframe2.notnull().sum(axis=0)[k] <= 1:
print("%d空列\n", k, dataframe2.notnull()[k])
if k+1 == dataframe2.columns.size:
dataframe2 = dataframe2.iloc[0:, :k]
else:
dataframe_left = dataframe2.iloc[0:, :k]
dataframe_right = dataframe2.iloc[0:, k + 1:]
dataframe2 = pd.concat([dataframe_left, dataframe_right], axis=1, ignore_index=True)
k = k-1
if k >= dataframe2.columns.size-1:
break
k = k+1
i = 0
t = 0
print("去掉空列後\n", dataframe2)
#空字元代替NaN防止NaN和其他合併時全為空
dataframe2_copy = dataframe2.fillna('', inplace=False)
#此迴圈處理表頭
while True:
if i == 0:
if dataframe2.notnull().sum(axis=1)[0] == dataframe2.columns.size:
break
if dataframe2.notnull().sum(axis=1)[0] == 1 and dataframe2.notnull().iat[0, 0]:
break
i = i + 1
else:
if dataframe2.notnull().sum(axis=1)[i] == dataframe2.columns.size:
t = t+1
break
if dataframe2.notnull().sum(axis=1)[i] == 1 and dataframe2.notnull().iat[i, 0]:
t = t+1
break
dataframe2_copy.iloc[t] = dataframe2_copy.iloc[t] + dataframe2_copy.iloc[i]
i = i+1
if i >= len(dataframe2):
t = t + 1
break
print("處理表頭中\n", dataframe2_copy)
#去掉空行,並且重新索引
dataframe2_copy.dropna(axis=0, how='all', inplace=True)
dataframe2_copy = dataframe2_copy.reset_index(drop=True)
#次迴圈處理表裡的資料
while i < len(dataframe2):
if i+2 >= len(dataframe2):
for p in range(len(dataframe2)-i):
dataframe2_copy.iloc[t] = dataframe2_copy.iloc[i+p]
t = t+1
break
elif dataframe2.notnull().sum(axis=1)[i] == 1 and dataframe2.notnull().iat[i, 0]:
if dataframe2.notnull().sum(axis=1)[i+2] == 1 and dataframe2.notnull().iat[i+2, 0]:
dataframe2_copy.iloc[t] = dataframe2_copy.iloc[i] + dataframe2_copy.iloc[i+1] + dataframe2_copy.iloc[i+2]
i = i+3
elif i+4 < len(dataframe2):
if dataframe2.notnull().sum(axis=1)[i + 1] == 1 and dataframe2.notnull().sum(axis=1)[i + 3] == 1 and dataframe2.notnull().sum(axis=1)[i + 4] == 1 and dataframe2.notnull().iat[i+1, 0] and dataframe2.notnull().iat[i+3, 0] and dataframe2.notnull().iat[i+4, 0]:
dataframe2_copy.iloc[t] = dataframe2_copy.iloc[i] + dataframe2_copy.iloc[i + 1] + dataframe2_copy.iloc[i + 2] + dataframe2_copy.iloc[i + 3] + dataframe2_copy.iloc[i + 4]
i = i + 5
else:
dataframe2_copy.iloc[t] = dataframe2_copy.iloc[i]
i = i + 1
else:
dataframe2_copy.iloc[t] = dataframe2_copy.iloc[i]
i = i + 1
else:
dataframe2_copy.iloc[t] = dataframe2_copy.iloc[i]
i = i+1
t = t+1
print("一個表的資料\n",dataframe2_copy)
return dataframe2_copy.iloc[:t]
def data_process1(dataframes):
"""
根據兩個空格拆分列資料合併
適用於資料均為str型別表格
如果非str型合併後為空資料丟失
"""
dataframes.fillna('', inplace=True)
print("處理前資料:\n", dataframes)
n = 0
while True:
try:
dataframes[n].str.split(' ', expand=True)#一列全是非str pass
dataframes[n] = dataframes[n].astype('str')#處理有一部分為非str情況,防止資料丟失
over_data = dataframes[n].str.split(' ', expand=True)
over_data.fillna('', inplace=True)
except:
print("遇到非str型的列 pass")
n = n+1
if n >= dataframes.columns.size:
break
else:
continue
print("重疊的列:\n", over_data)
if n-1 < 0:
dataframe_right = dataframes.iloc[0:, n + 1:]
dataframes = pd.concat([over_data, dataframe_right], axis=1, ignore_index=True)
elif n+1 > dataframes.columns.size:
dataframe_left = dataframes.iloc[0:, :n]
dataframes = pd.concat([dataframe_left, over_data], axis=1, ignore_index=True)
else:
dataframe_left = dataframes.iloc[0:, :n]
dataframe_right = dataframes.iloc[0:, n+1:]
dataframes = pd.concat([dataframe_left, over_data, dataframe_right], axis=1, ignore_index=True)
n = n + over_data.columns.size
if n >= dataframes.columns.size:
break
print("處理後資料\n:", dataframes)
return dataframes
def getCashflowAggregation(dataframe1):
pass
def pdf_to_xlsx(folder):
"""
提取資料夾的PDF裡表格資料
對資料做初步整理
對每個dataframe識別提取想要的資料儲存到相應的sheet裡,
輸出同名xlsx格式檔案
"""
files = os.listdir(folder)
#遍歷資料夾,找出PDF檔案
pdfFile = [f for f in files if f.endswith(".pdf")]
for pdfFiles in pdfFile:
#建立一個和PDF同名的xlsx檔案
pdfPath = os.path.join(folder, pdfFiles)
xlsPath = pdfPath[:-3] + "xlsx"
#建立Workbook然後和所要儲存的資料表格連線,之後每次儲存都會儲存到不同的Sheet中
Workbook(xlsPath)
book = Workbook()
book.save(filename=xlsPath)
#獲取PDF的頁數
pdf = PdfFileReader(open(pdfPath, "rb"))
page_counts = pdf.getNumPages()
dataframe2 = pd.DataFrame()
#遍歷PDF每一頁,提取出表格資料
for page in range(1, page_counts+1):
try:
pf = read_pdf(pdfPath, encoding='gbk', multiple_tables=True,pages = page)
if len(pf) != 0:
for t in range(len(pf)):
dataframe1 = pf[t]
dataframe1 = data_process2(dataframe1)#處理表頭
dataframe1 = data_process1(dataframe1)#按空格拆分合並項
#CashflowAggregation = getCashflowAggregation(dataframe1)
#列數相同的表格合併,並且刪除重複項並儲存
if dataframe2.empty:
dataframe2 = dataframe1
elif dataframe1.columns.size == dataframe2.columns.size:
dataframe2 = pd.concat([dataframe2,dataframe1],ignore_index=True)
#刪除重複項會影響池分佈的匹配提取,但是可以很好的處理靜動態池和現金流歸集
#dataframe2.drop_duplicates(keep="first", inplace=True)#在原來的資料裡刪除重複項
print(dataframe2)
else:
print("列數:", dataframe1.columns.size)
print(dataframe2)
#儲存在不同的工作簿
writer = pd.ExcelWriter(xlsPath, engin='openpyxl')
book = load_workbook(writer.path)
writer.book = book
dataframe2.to_excel(writer, sheet_name='shet')
writer.close()
dataframe2 = dataframe1
del(pf)
gc.collect()
except:
gc.collect()
print("Error Pass")
continue
#儲存最後的資料表格到另一個工作表裡
writer = pd.ExcelWriter(xlsPath, engin='openpyxl')
book = load_workbook(writer.path)
writer.book = book
dataframe2.to_excel(writer, sheet_name='shet')
writer.close()
star_time = datetime.datetime.now()
pdf_to_xlsx("D:\\2018暑假\\新建資料夾")
stop_time = datetime.datetime.now()
print("程式執行時間:", stop_time-star_time)