Python數據預處理之抽取文本信息(2)
白寧超 2018年12月28日10:28:48
摘要:大數據技術與我們日常生活越來越緊密,要做大數據,首要解決數據問題。原始數據存在大量不完整、不一致、有異常的數據,嚴重影響到數據建模的執行效率,甚至可能導致模型結果的偏差,因此要數據預處。數據預處理主要是將原始數據經過文本抽取、數據清理、數據集成、數據處理、數據變換、數據降維等處理后,不僅提高了數據質量,而且更好的提升算法模型性能。數據預處理在數據挖掘、自然語言處理、機器學習、深度學習算法中起着重要的作用。(本文原創,轉載必須注明出處.)
1 數據類型與數據采集
通常說的數據指的的數字、圖表信息這些。在大數據領域所謂的數據總體包括結構化數據、半結構化數據和非結構化數據。
結構化數據
結構化的數據是指可以使用關系型數據庫表示和存儲,表現為二維形式的數據。一般特點是:數據以行為單位,一行數據表示一個實體的信息,每一行數據的屬性是相同的。比如:
| id | name | age | gender |
|---|---|---|---|
| 1 | 張三 | 12 | 男 |
| 2 | 李花 | 13 | 女 |
| 3 | 王五 | 18 | 男 |
- 數據特點:關系模型數據,關系數據庫表示。
- 常見格式:比如MySQL、Oracle、SQL Server等。
- 應用場合:數據庫、系統網站、數據備份、ERP等。
- 數據采集:DB導出、SQL等方式。
結構化的數據的存儲和排列是很有規律的,這對查詢和修改等操作很有幫助。但是,它的擴展性不好。
半結構化數據
半結構化數據是結構化數據的一種形式,它並不符合關系型數據庫或其他數據表的形式關聯起來的數據模型結構,但包含相關標記,用來分隔語義元素以及對記錄和字段進行分層。因此,它也被稱為自描述的結構。半結構化數據,屬於同一類實體可以有不同的屬性,即使他們被組合在一起,這些屬性的順序並不重要。常見的半結構數據有XML如下:
<person>
<name>李花</name>
<age>13</age>
<gender>女</gender>
</person>
- 數據特點:非關系模型數據,還有一定的格式。
- 常見格式:比如Email、HTML、XML、JSON等。
- 應用場合:郵件系統、檔案系統、新聞網站等。
- 數據采集:網絡爬蟲、數據解析等方式。
不同的半結構化數據的屬性的個數是不定的。有些人說半結構化數據是以樹或者圖的數據結構存儲的數據,上面的例子中,標簽是樹的根節點,和標簽是子節點。通過這樣的數據格式,可以自由地表達很多有用的信息,包括自我描述信息(元數據)。所以,半結構化數據的擴展性是很好的。
非結構化數據
就是沒有固定結構的數據。各種文檔、圖片、視頻/音頻等都屬於非結構化數據。對於這類數據,我們一般直接整體進行存儲,而且一般存儲為二進制的數據格式。如下所示:
- 數據特點:沒有固定格式的數據
- 常見格式:Word、PDF、PPT、圖片、音視頻等。
- 應用場合:圖片識別、人臉識別、醫療影像、文本分析等。
- 數據采集:網絡爬蟲、數據存檔等方式。
2 常見的文本抽取方法
針對數據不同形式,通過特定方式的數據采集方式(文檔下載、數據庫導出、網絡爬蟲、語音收集、圖片解析等等)獲取數據,無論是結構化的數據庫文件、半結構化的網頁數據,還是非結構化的圖片、音視頻。我們最終的目的都是將數據傳入到電腦之中,通過算法模型挖掘其潛在的價值,為最終的AI技術做支撐。不同的是,在結構化和半結構化數據數據集成過程中,我們可以提取相關文本信息,做進一步的數據預處理;而非結構化的圖片、音視頻我們采用一定的技術手段,獲取其對應的數據點矩陣。這一點不太容易理解,我們比如說想解析一張圖片的數據,我們知道圖片是有長寬高組成的,還包括紅藍綠三種基本色。那么我們就找到對應的多維特征,采用數據點占位表示,比如:
| 圖片名 | 長(bit) | 寬(bit) | 紅 | 綠 | 藍 |
|---|---|---|---|---|---|
| 貓1 | 12 | 100 | 0 | 0 | 1 |
| 狗2 | 101 | 234 | 1 | 1 | 1 |
| 豬3 | 202 | 24 | 0 | 1 | 0 |
上面就數據表示貓1這張圖片,長寬位點(12,100)處只有藍色構成;狗2這張圖片,長寬位點(101,234)處有紅綠藍3中色構成;豬3這張圖片,長寬位點(202,24)處只有綠構成。這就是非結構數據圖片轉化為數值型數據的原理。完整流程數據挖掘的流程圖如下所示:

我根據不同的數據類型,采用對應的數據采集方式獲取目標數據。這時候的數據質量很差,存在文本格式不同,數據表示形式不同等諸多問題。這里我們單純的考慮文本信息的處理,就文本信息而言,你采集的數據可能是網頁、數據庫文件、pdf文檔、word文檔等等。我們想去處理這些數據,還需要對數據進行集成即轉化為統一的數據格式,這里我們就需要文本信息抽取,常見的抽取方式包括以下幾個內容:在線格式轉換工具、office內置格式轉換、自己開發文本抽取工具。詳見下圖:

經過實際操作會發現采用在線格式轉換工具存在幾個弊端,其限制文件轉化的數據,要么就是收費的;而采用本地的office自帶文檔,一個個另存為文本,肯定不現實。基於上述情況,我們對工具抽取的弊端總結如下:
- 格式轉換后,識別亂碼較多
- 不支持或者限制支持批量處理
- 批量轉化收費問題
- 格式轉換后的txt文件存在編碼問題
- 生成文件名一堆數字亂碼
- 操作不夠靈活便捷
我們針對以上問題,就去尋求解決方式,那就是自己動手豐衣足食,我們自己去打造批量文本抽取問題,我們期待效果是:
- 支持PDF/Word等多格式文本抽取
- 自動過濾不符合指定格式的文件
- 生成的目標文件與原文件目錄一致
- 生成文檔采用統一的編碼格式保存(如:UTF-8 )
- 支持默認保存路徑和自定義保存路徑
3 抽取Word文檔文本
做word文檔抽取工作,我們運行環境是在win10-64bit下,python3.5,Anaconda4.4版本下執行的,所使用的插件是win32com。下載地址:https://pan.baidu.com/s/1-2BsiTs8XjMIe5Gnh_GFjw 密碼: 7j3t
預裝完win32com以后,以下代碼便完成抽取word文本信息。
算法思路:
- 定義文件路徑和轉存路徑:split
- 修改新的文件名:fnmatch
- 設置完整的保存路徑:join
- 啟動應用程序格式轉換:Dispatch
- 保存文本:SaveAs
算法流程:

代碼實現:
#coding=utf-8
"""
Description: Word文件轉化TXT文本
Author:伏草惟存
Prompt: code in Python3 env
Install package: pip install pypiwin32
"""
import os,fnmatch
from win32com import client as wc
from win32com.client import Dispatch
'''
功能描述:word文件轉存txt文件,默認存儲當前路徑下;用戶可以指定存儲文件路徑。
參數描述:1 filePath:文件路徑 2 savePath: 指定保存路徑
'''
def Word2Txt(filePath,savePath=''):
# 1 切分文件上級目錄和文件名
dirs,filename = os.path.split(filePath)
# print(dirs,'\n',filename)
# 2 修改轉化后的文件名
new_name = ''
if fnmatch.fnmatch(filename,'*.doc'):
new_name = filename[:-4]+'.txt'
elif fnmatch.fnmatch(filename,'*.docx'):
new_name = filename[:-5]+'.txt'
else: return
print('->',new_name)
# 3 文件轉化后的保存路徑
if savePath=='': savePath = dirs
else: savePath = savePath
word_to_txt = os.path.join(savePath,new_name)
print('->',word_to_txt)
# 4 加載處理應用,word轉化txt
wordapp = wc.Dispatch('Word.Application')
mytxt = wordapp.Documents.Open(filePath)
mytxt.SaveAs(word_to_txt,4)
mytxt.Close()
if __name__=='__main__':
filepath = os.path.abspath(r'../dataSet/filename.doc')
# savepath = ''
Word2Txt(filepath)
4 抽取PDF文檔文本
算法思路:
- 定義文件路徑和轉存路徑:split
- 修改新的文件名:fnmatch
- 設置完整的保存路徑:join
- 啟動應用程序格式轉換:Dispatch
- 保存文本:SaveAs
算法流程:

代碼實現:
# coding=utf-8
"""
Description: PDF文件轉化TXT文本
Author:伏草惟存
Prompt: code in Python3 env
"""
import os,fnmatch
from win32com import client as wc
from win32com.client import Dispatch,gencache
'''
功能描述:pdf文件轉化txt文本
參數描述:1 filePath:文件路徑 2 savePath: 指定保存路徑
'''
def Pdf2Txt(filePath,savePath=''):
# 1 切分文件上級目錄和文件名
dirs,filename = os.path.split(filePath)
# print('目錄:',dirs,'\n文件名:',filename)
# 2 修改轉化后的文件名
new_name = ""
if fnmatch.fnmatch(filename,'*.pdf') or fnmatch.fnmatch(filename,'*.PDF'):
new_name = filename[:-4]+'.txt' # 截取".pdf"之前的文件名
else: return
print('新的文件名:',new_name)
# 3 文件轉化后的保存路徑
if savePath=="": savePath = dirs
else: savePath = savePath
pdf_to_txt = os.path.join(savePath,new_name)
print('保存路徑:',pdf_to_txt)
# 4 加載處理應用,pdf轉化txt
wordapp = wc.Dispatch('Word.Application')
mytxt = wordapp.Documents.Open(filePath)
mytxt.SaveAs(pdf_to_txt,4)
mytxt.Close()
if __name__=='__main__':
# 使用絕對路徑
filePath = os.path.abspath(r'../dataSet/Corpus/pdftotxt/2018年世界新聞自由日.pdf')
# savePath = r'E:\\'
Pdf2Txt(filePath)
5 文本抽取工具與編碼
算法思路:
- 定義文件夾路徑和轉存夾路徑:split
- 修改新的文件名:TranType(filename, typename)、fnmatch
- 設置完整的保存路徑:join
- 啟動應用程序格式轉換:Dispatch
- 保存文本:SaveAs
代碼實現
#coding=utf-8
"""
Description: 多文檔格式轉換工具
Author:伏草惟存
Prompt: code in Python3 env
"""
import os,fnmatch
from win32com import client as wc
from win32com.client import Dispatch,gencache
'''
功能描述:抽取文件文本信息
參數描述:1 filePath:文件路徑 2 savePath: 指定保存路徑
'''
def Files2Txt(filePath,savePath=''):
try:
# 1 切分文件上級目錄和文件名
dirs,filename = os.path.split(filePath)
# print('目錄:',dirs,'\n文件名:',filename)
# 2 修改轉化后的文件名
typename = os.path.splitext(filename)[-1].lower() # 獲取后綴
new_name = TranType(filename,typename)
# print('新的文件名:',new_name)
# 3 文件轉化后的保存路徑
if savePath=="": savePath = dirs
else: savePath = savePath
new_save_path = os.path.join(savePath,new_name)
print('保存路徑:',new_save_path)
# 4 加載處理應用
wordapp = wc.Dispatch('Word.Application')
mytxt = wordapp.Documents.Open(filePath)
mytxt.SaveAs(new_save_path,4)
mytxt.Close()
except Exception as e:
pass
'''
功能描述:根據文件后綴修改文件名
參數描述:1 filePath:文件路徑 2 typename 文件后綴
返回數據:new_name 返回修改后的文件名
'''
def TranType(filename,typename):
# 新的文件名稱
new_name = ""
if typename == '.pdf' : # pdf->txt
if fnmatch.fnmatch(filename,'*.pdf') :
new_name = filename[:-4]+'.txt' # 截取".pdf"之前的文件名
else: return
elif typename == '.doc' or typename == '.docx' : # word->txt
if fnmatch.fnmatch(filename, '*.doc') :
new_name = filename[:-4]+'.txt'
elif fnmatch.fnmatch(filename, '*.docx'):
new_name = filename[:-5]+'.txt'
else: return
else:
print('警告:\n您輸入[',typename,']不合法,本工具支持pdf/doc/docx格式,請輸入正確格式。')
return
return new_name
if __name__ == '__main__':
filePath1 = os.path.abspath(r'../dataSet/Corpus/wordtotxt/一種改進的朴素貝葉斯文本分類方法研究.doc')
filePath2 = os.path.abspath(r'../dataSet/Corpus/pdftotxt/改進朴素貝葉斯文本分類方法研究.pdf')
filePath3 = os.path.abspath(r'../dataSet/Corpus/wordtotxt/科技項目數據挖掘決策架構.docx')
Files2Txt(filePath3)
遍歷讀取文件
- 遍歷文件的類TraversalFun : TraversalDir、 AllFiles
- 遍歷目錄文件TraversalDir : AllFiles(self.rootDir)
- 遞歸遍歷文件AllFiles: AllFiles(self,rootDir)
- 判斷是否為文件isfile :打印出文件名
- 判斷是否是目錄isdir :遞歸遍歷
遍歷文件源碼實現
# coding=utf-8
"""
Description: 遍歷讀取文件名
Author:伏草惟存
Prompt: code in Python3 env
"""
import os,time
'''
功能描述:遍歷目錄處理子文件
參數描述: 1 rootDir 目標文件的根目錄
'''
class TraversalFun():
# 1 初始化
def __init__(self,rootDir):
self.rootDir = rootDir # 目錄路徑
# 2 遍歷目錄文件
def TraversalDir(self):
TraversalFun.AllFiles(self,self.rootDir)
# 3 遞歸遍歷所有文件,並提供具體文件操作功能
def AllFiles(self,rootDir):
# 返回指定目錄包含的文件或文件夾的名字的列表
for lists in os.listdir(rootDir):
# 待處理文件夾名字集合
path = os.path.join(rootDir, lists)
# 核心算法,對文件具體操作
if os.path.isfile(path):
print(os.path.abspath(path))
# 遞歸遍歷文件目錄
elif os.path.isdir(path):
TraversalFun.AllFiles(self,path)
if __name__ == '__main__':
time_start=time.time()
# 根目錄文件路徑
rootDir = r"../dataSet/Corpus/EnPapers"
tra=TraversalFun(rootDir) # 默認方法參數打印所有文件路徑
tra.TraversalDir() # 遍歷文件並進行相關操作
time_end=time.time()
print('totally cost',time_end-time_start,'s')
6 實戰案例:遍歷文件批量抽取新聞文本內容
算法思路
- 引用外部文本抽取模塊:import ExtractTxt as ET
- 參數方法使用:TraversalFun(rootDir,ET.Files2Txt,saveDir)
- 創建保存根目錄:os.path.abspath
- 遞歸遍歷文件:func(path, save_dir)
源碼實現
# coding=utf-8
"""
Description: 批量文檔格式自動轉化txt
Author:伏草惟存
Prompt: code in Python3 env
"""
import ExtractTxt as ET
import os,time
'''
功能描述:遍歷目錄,對子文件單獨處理
參數描述:1 rootDir 根目錄 2 deffun:方法參數 3 saveDir: 保存路徑
'''
class TraversalFun():
# 1 初始化
def __init__(self,rootDir,func=None,saveDir=""):
self.rootDir = rootDir # 目錄路徑
self.func = func # 參數方法
self.saveDir = saveDir # 保存路徑
# 2 遍歷目錄文件
def TraversalDir(self):
# 切分文件上級目錄和文件名
dirs,latername = os.path.split(self.rootDir)
# print(rootDir,'\n',dirs,'\n',latername)
# 保存目錄
save_dir = ""
if self.saveDir=="": # 默認文件保存路徑
save_dir = os.path.abspath(os.path.join(dirs,'new_'+latername))
else: save_dir = self.saveDir
# 創建目錄文件
if not os.path.exists(save_dir): os.makedirs(save_dir)
print("保存目錄:\n"+save_dir)
# 遍歷文件並將其轉化txt文件
TraversalFun.AllFiles(self,self.rootDir,save_dir)
# 3 遞歸遍歷所有文件,並提供具體文件操作功能
def AllFiles(self,rootDir,save_dir=''):
# 返回指定目錄包含的文件或文件夾的名字的列表
for lists in os.listdir(rootDir):
# 待處理文件夾名字集合
path = os.path.join(rootDir, lists)
# 核心算法,對文件具體操作
if os.path.isfile(path):
self.func(os.path.abspath(path),os.path.abspath(save_dir))
# 遞歸遍歷文件目錄
if os.path.isdir(path):
newpath = os.path.join(save_dir, lists)
if not os.path.exists(newpath):
os.mkdir(newpath)
TraversalFun.AllFiles(self,path,newpath)
if __name__ == '__main__':
time_start=time.time()
# 根目錄文件路徑
rootDir = r"../dataSet/Corpus/EnPapers"
# saveDir = r"./Corpus/TxtEnPapers"
tra=TraversalFun(rootDir,ET.Files2Txt) # 默認方法參數打印所有文件路徑
tra.TraversalDir() # 遍歷文件並進行相關操作
time_end=time.time()
print('totally cost',time_end-time_start,'s')
7源碼獲取


