【Python私活案例】100元,PDF爬蟲+解析+解析數(shù)據(jù)+存儲(chǔ)Excel文件
使用Python提取pdf信息的那些事
我一直都是一個(gè)pdf電子書和pdf格式控的宅男,沒想到這輩子居然和老朋友以這種方式見面了。還記得上次專注的看pdf文件實(shí)在《明朝那些事》,于是有了今天的Python版的提取pdf信息的那些事。
1.需求
這次是要提取兩個(gè)合同pdf文件中的相關(guān)信息,具體要求是先要讀取excel文件,并將其中的兩種類型的pdf合同連接讀取出來,進(jìn)行逐一的下載,這就是提取pdf文件的鏈接excel:

2.代碼
我使用了requests庫來進(jìn)行了簡(jiǎn)單的pdf文件提取,因?yàn)樗逆溄硬蛔鲵?yàn)證,直接提取,連header都省了,這個(gè)還挺好的。
#?保存pdf文件
os.makedirs('./baoli/',exist_ok=True)
os.makedirs('./fenqi/',exist_ok=True)
for?i?in?df.index:
????baoli_url?=?df.loc[i,'保理合同']#.split('pdf?')[0].__add__('pdf')
????fenqi_url?=?df.loc[i,'分期支付協(xié)議']#.split('pdf?')[0].__add__('pdf')
????baoli_name?=?df.loc[i,'保理合同'].split('.pdf?')[0].replace('/','-').split('-')[-1].__add__('.pdf')
????fenqi_name?=?df.loc[i,'分期支付協(xié)議'].split('.pdf?')[0].replace('/','-').split('-')[-1].__add__('.pdf')
????
????loan_application_no?=?df.loc[i,'loan_application_no']
????baoli_name?=?str(loan_application_no)+'_'+baoli_name
????fenqi_name?=?str(loan_application_no)+'_'+fenqi_name
????print(baoli_url)
????print(fenqi_url)
????res1?=?requests.get(baoli_url)
????res2?=?requests.get(fenqi_url)
????with?open('./baoli/'+baoli_name,'wb')?as?file:
????????file.write(res1.content)
????with?open('./fenqi/'+fenqi_name,'wb')?as?file:
????????file.write(res2.content)
這里我把下載好的文檔自動(dòng)歸類為兩類合同的不同文件夾中,方便他們查找,然后我是用的他們的一個(gè)業(yè)務(wù)字段命名的文件名,這樣居然在后續(xù)的使用中,成為了唯一能夠傳遞這個(gè)字段的方法!!
然后就是對(duì)第一類合同信息的提取,這里我把關(guān)鍵字段做了脫敏處理,這年頭干啥都要小心小心再小心,不然羅翔老師的視頻不是白看了!?
這里我主要用了PyPDF2這個(gè)類庫提取pdf信息,將里面我要提取的對(duì)應(yīng)字段拿到,然后把他們存儲(chǔ)到一個(gè)臨時(shí)列表,這樣的操作應(yīng)用到所有的同類pdf文件,然后將這種臨時(shí)列表全部存儲(chǔ)到一個(gè)最終的結(jié)果列表中,這個(gè)結(jié)果列表事先已經(jīng)存儲(chǔ)好了要生成的dataframe的項(xiàng)字段列,因此最后可以直接通過dataframe的構(gòu)造方法,生成datarame對(duì)象,進(jìn)而直接寫入excel
from?PyPDF2?import?PdfFileReader
from?pathlib?import?Path
baoli_path?=?Path('./baoli/')
baoli_list?=?baoli_path.glob('*.pdf')
baoli?=?[['XXXXX','ZZZZZ','YYYYY','TTTTT','YYYYY']]?
for?i?in?baoli_list:
????path?=?f'./baoli/{i.name}'
????baoli_reader?=?PdfFileReader(path)
????baoli_fields?=?baoli_reader.getFields()
????temp?=?[i.stem.split('_')[0]]
????for?field?in?baoli_fields:
????????if?field?==?'contractNo':
????????????contract_no?=?list(baoli_fields[field].values())[-1]
????????????temp.append(contract_no)
????????????#?print(contract_no)
????????elif?field?==?'signDate':
????????????sign_date?=?list(baoli_fields[field].values())[-1]
????????????temp.append(sign_date)
????????????#?print(sign_date)
????????elif?field?==?'signContractNo':
????????????sign_contract_no?=?list(baoli_fields[field].values())[-1]
????????????temp.append(sign_contract_no)
????????????#?print(sign_contract_no)
????temp.append('《分期支付協(xié)議》')
????baoli.append(temp)
print(baoli)
緊接著就是第二段代碼,邏輯和上面的一模一樣,但是工作量卻遠(yuǎn)遠(yuǎn)超出了第一個(gè),主要是在pdf文件中要逐個(gè)去匹配對(duì)應(yīng)的字段名,這里的字段多達(dá)10幾個(gè)

同時(shí),我需要一一驗(yàn)證這些字段對(duì)應(yīng)的pdf的英文代碼是什么,從而確認(rèn)提取的信息是否準(zhǔn)確,然后才能正確的取數(shù):
#?提取分期協(xié)議信息
fenqi_path?=?Path('./fenqi/')
fenqi_list?=?fenqi_path.glob('*.pdf')
fenqi?=?[['基礎(chǔ)合同編號(hào)','商戶住所',
??????????'商戶統(tǒng)一社會(huì)信用代碼','商戶法定代表人',
??????????'底層合同期限','應(yīng)收賬款','商戶名稱','消費(fèi)者姓名',
??????????'服務(wù)費(fèi)用',
??????????'基礎(chǔ)合同簽署日期']]
for?j?in?fenqi_list:
????path?=?f'./fenqi/{j.name}'
????fenqi_reader?=?PdfFileReader(path)
????fenqi_fields?=?fenqi_reader.getFields()
????temp?=?[]
????date?=?[]
????for?field?in?fenqi_fields:
????????if?field?==?'contractNo':
????????????f_contract_no?=?list(fenqi_fields[field].values())[-1]
????????????temp.append(f_contract_no)
????????????#?print(f_contract_no)
????????elif?field?==?'merchantCreditCode':
????????????f_merchant_credit_code?=?list(fenqi_fields[field].values())[-1]
????????????temp.append(f_merchant_credit_code)
????????????#?print(f_merchant_credit_code)
????????elif?field?==?'merchantAddress':
????????????f_merchant_address?=?list(fenqi_fields[field].values())[-1]
????????????temp.append(f_merchant_address)
????????????#?print(f_merchant_address)
????????elif?field?==?'legalPerson':
????????????legalPerson?=?list(fenqi_fields[field].values())[-1]
????????????temp.append(legalPerson)
????????????#?print(legalPerson)
????????elif?field?==?'merchantName':
????????????merchantName?=?list(fenqi_fields[field].values())[-1]
????????????temp.append(merchantName)
????????????#?print(merchantName)
????????elif?field?==?'userName':
????????????userName?=?list(fenqi_fields[field].values())[-1]
????????????temp.append(userName)
????????????#?print(userName)
????????elif?field?==?'money':
????????????money?=?list(fenqi_fields[field].values())[-1]
????????????temp.append(money)
????????????#?print(money)
????????elif?field?==?'periods':
????????????periods?=?int(list(fenqi_fields[field].values())[-1])+1
????????????temp.append(periods)
????????????#?print(periods)
????????elif?field?==?'serviceMoeny':
????????????serviceMoeny?=?list(fenqi_fields[field].values())[-1]
????????????temp.append(serviceMoeny)
????????????#?print(serviceMoeny)
????????elif?field?==?'yyyy':
????????????year?=?list(fenqi_fields[field].values())[-1]
????????????if?year:
????????????????date.append(year)
????????????else:
????????????????date.append('年為空')
????????????#?print(year)
????????elif?field?==?'mm':
????????????month?=?list(fenqi_fields[field].values())[-1]
????????????if?month:???
????????????????date.append(month)
????????????else:
????????????????date.append("月為空")
????????????#?print(month)
????????elif?field?==?'dd':
????????????day?=?list(fenqi_fields[field].values())[-1]
????????????if?day:
????????????????date.append(day)
????????????else:
????????????????date.append("天為空")
????date?=?date[0]+'年'+date[1]+'月'+date[2]+'日'
????temp.append(date)
????fenqi.append(temp)
print(fenqi)
接下來在做了些生成excel文件的格式整理:
#調(diào)整格式
import?xlwings?as?xw
app?=?xw.App(visible=False,add_book=False)
workbook?=?app.books.open(r'final.xlsx')
worksheet?=?workbook.sheets['總表']
worksheet.autofit()
workbook.save()
workbook.close()
app.quit()
于是,花了幾個(gè)小時(shí)時(shí)間終于完成了所有的工作,但是第二天,詭異的事情發(fā)生了,在pdf匹配字段中,這些字段在代碼里面都算局部變量,但是只有兩個(gè)變量報(bào)錯(cuò), 說這個(gè)變量不存在,而它們的作用域和其他的變量是一摸一樣的,我感覺好奇怪,最后我不得已,將代碼里的臨時(shí)列表temp,提升為內(nèi)層for循環(huán)的全局變量,然后錯(cuò)誤就消失了,此外,我還添加了年月日的空值判斷,因?yàn)樗f她的數(shù)據(jù)集中的日期會(huì)有讀取不正常的情況,所以我就做了這個(gè)樣的判斷,幫她把所有的問題都搞定了,看到她開心的狀態(tài),我覺得我也很有成就感,希望大家一切都順利!
最后,推薦螞蟻老師的Pandas入門課程,極佳的實(shí)戰(zhàn)課
掃碼:Pandas入門到實(shí)戰(zhàn)課

點(diǎn)擊閱讀原文,也能到達(dá)目的地
