即將進行NLP項目,邊學(xué)邊做。
第一步是將大篇的文本數(shù)據(jù)處理成結(jié)構(gòu)化的數(shù)據(jù)。
原理與代碼參考:https://blog.csdn.net/xc_zhou/article/details/81009809
python中讀取pdf的庫挺多,各有各的優(yōu)缺點。本文就介紹目前較好的兩種pdfminer
和pdfplumber
的使用
首先要安裝以下幾個庫
pip install pdfminer
pip install pdfminer3k
pip install pdfminer.six
我只安裝了第一個庫就能成功運行了,如果有問題可以嘗試把下面兩行也安上。
將一個文件夾下所有PDF文件都轉(zhuǎn)為txt的程序:
# -*- coding:utf-8 -*- # 來源:https://blog.csdn.net/xc_zhou/article/details/81009809 import os,re from pdfminer.pdfinterp import PDFResourceManager,PDFPageInterpreter from pdfminer.pdfpage import PDFPage from pdfminer.converter import TextConverter from pdfminer.layout import LAParams ''' pip install pdfminer3k pip install pdfminer.six 安裝這個引入的內(nèi)容不會報錯 ''' #將一個pdf轉(zhuǎn)換成txt def pdfTotxt(filepath,outpath): try: fp = open(filepath, 'rb') outfp=open(outpath,'w') #創(chuàng)建一個PDF資源管理器對象來存儲共享資源,caching = False不緩存 rsrcmgr = PDFResourceManager(caching = False) # 創(chuàng)建一個PDF設(shè)備對象 laparams = LAParams() device = TextConverter(rsrcmgr, outfp, codec='utf-8', laparams=laparams,imagewriter=None) #創(chuàng)建一個PDF解析器對象 interpreter = PDFPageInterpreter(rsrcmgr, device) for page in PDFPage.get_pages(fp, pagenos = set(),maxpages=0, password='',caching=False, check_extractable=True): page.rotate = page.rotate % 360 interpreter.process_page(page) #關(guān)閉輸入流 fp.close() #關(guān)閉輸出流 device.close() outfp.flush() outfp.close() except Exception as e: print("Exception:%s",e) #一個文件夾下的所有pdf文檔轉(zhuǎn)換成txt def fileTotxt(fileDir): files=os.listdir(fileDir) tarDir=fileDir+'txt' if not os.path.exists(tarDir): os.mkdir(tarDir) replace=re.compile(r'\.pdf',re.I) for file in files: filePath=fileDir+'\\'+file outPath=tarDir+'\\'+re.sub(replace,'',file)+'.txt' pdfTotxt(filePath,outPath) print("Saved "+outPath) if __name__ == '__main__': # pdfTotxt('000.pdf', 'test.txt') fileTotxt('./data/pdf/')
折疊
結(jié)果:基本的文本信息都能夠很好的讀取,但有的部分不能很好的讀取,如:
原文 | txt |
---|---|
(數(shù)據(jù)來源于網(wǎng)絡(luò):華安寶利配置證券投資基金基金合同) | |
可以看到句尾換行后,一部分句尾的內(nèi)容會集中到其他地方(目前還沒了解是什么原因……),讀取表格的效果也不佳。 | |
并且,轉(zhuǎn)換的部分主要在pdfTotxt() 函數(shù)中,可以看到pdfminer 構(gòu)造了pdf資源管理器對象、pdf設(shè)備對象、pdf解析器對象來進行轉(zhuǎn)換,過程十分繁瑣。 |
|
于是后面發(fā)現(xiàn)了一個讀取PDF更好的庫:pdfplumber 。 |
先上程序:
import pdfplumber
PDF_PATH = './data/pdf/'
FILE_NAME = '華安寶利配置證券投資基金基金合同'
path = PDF_PATH + FILE_NAME + '.pdf'
pdf = pdfplumber.open(path)
f = open(PDF_PATH + FILE_NAME + '.txt', 'w')
for page in pdf.pages:
# 獲取當(dāng)前頁面的全部文本信息,包括表格中的文字
str = page.extract_text()
print(str)
f.write(str + '\n')
pdf.close()
f.close()
結(jié)果:不會出現(xiàn)如上的明顯錯誤:
原文 | txt |
---|---|
pdfplumber 使用方式簡單,讀取方式為按頁讀取,后續(xù)操作也易于理解和修改。并且讀取表格效果較好,有專門的提取表格的函數(shù)extract_tables() 。 |
|
程序: |
for page in pdf.pages:
for table in page.extract_tables():
# print(table)
for row in table:
print(row)
print('---------- 分割線 ----------')
結(jié)果:
原文 | 輸出結(jié)果 |
---|---|
表格內(nèi)容基本讀取,并且以list 形式存儲。但其中順序不是很對,“最低比例”這列也沒有讀取到,可能讀取結(jié)果因表格的制作而異。 |
根據(jù)效果,選擇使用pdfplumber
讀取pdf。
但讀取pdf普遍存在一些問題:
(1)會根據(jù)PDF的顯示,把相應(yīng)的換行符也讀入進去,但是一句話并沒有結(jié)束。因此會與自然分段的換行符混淆,影響之后將文本一條條提取出來。
(2)會有空行和頁碼。
這些問題會在之后解決
讀取Docx文件主要使用docx
庫,安裝:pip install python-docx
。
程序:
from docx import Document
DOC_PATH = './data/docx/'
FILE_NAME = '文件名'
document = Document(DOC_PATH + FILE_NAME + '.docx')
f = open(DOC_PATH + FILE_NAME + '.txt', 'w')
i = 0
for paragraph in document.paragraphs:
f.write(paragraph.text + '\n')
print(i, paragraph.text)
i += 1
f.close()
由于docx文件與pdf文件的區(qū)別,讀取docx文件比較輕松,且可編輯性很好。
結(jié)果:
目前仍在解決換行的問題。
docx文件讀取已基本將文本內(nèi)容一段段分開,此次NLP項目為分類某一項(例:1、2、3、)的內(nèi)容屬性,因此要將整個文本分成一條條。
關(guān)鍵思想為:根據(jù)一條的數(shù)字編號對其進行編碼。
以某一節(jié)的內(nèi)容為例,最小的分類標(biāo)題為三級標(biāo)題,即(一)1.(1),那么其對應(yīng)的編碼為:111。之后112、113……以此類推。
判斷標(biāo)題編號的程序,主要通過標(biāo)題前面的標(biāo)號實現(xiàn):
COL1NUM = ['(一', '(二', '(三', '(四', '(五', '(六', '(七', '(八', '(九', '(十']
COL2NUM = ['1.', '2.', '3.', '4.', '5.', '6.', '7.', '8.', '9.', '0.']
COL3NUM = ['(1', '(2', '(3', '(4', '(5', '(6', '(7', '(8', '(9']
def sepNum(list):
# (一)1.(1)。(①②③不劃分)
col_num = [0, 0, 0]
newlist = []
title_flag = 0
for line in list:
for index in range(len(COL1NUM)):
if line.find(COL1NUM[index]) == 0:
col_num[0] += 1
col_num[1] = 0
col_num[2] = 0
title_flag = 1
for index in range(len(COL2NUM)):
if 0 <= line.find(COL2NUM[index]) <= 2: # <=2時最多到三位數(shù):111.
col_num[1] += 1
col_num[2] = 0
for index in range(len(COL3NUM)):
if line.find(COL3NUM[index]) == 0:
col_num[2] += 1
if title_flag == 1 or line == '':
title_flag = 0 # 是一級標(biāo)題的話,跳過;或是空行
else:
newlist.append([col_num[0], col_num[1], col_num[2], line])
print(col_num)
return newlist
其中一級標(biāo)題:“(一)”,基本為純標(biāo)題,沒有實際意義,已去掉。得到結(jié)果保存為CSV文件,如下所示:
完整程序放在Github中:https://github.com/AionWU/pythonReadfile
目前程序仍在推進中。
內(nèi)容如有誤或有更好的方法希望大佬們給予批評指正 Orz
聯(lián)系客服