導(dǎo)讀:本文的目標(biāo)是介紹一些Python庫(kù),幫助你從類似于PDF和Word DOCX 這樣的二進(jìn)制文件中提取數(shù)據(jù)。我們也將了解和學(xué)習(xí)如何從網(wǎng)絡(luò)信息源(web feeds)(如RSS)中獲取數(shù)據(jù),以及利用一個(gè)庫(kù)幫助解析HTML文本并從文檔中提取原始文本。
我們還將學(xué)習(xí)如何從不同來(lái)源提取原始文本,對(duì)其進(jìn)行規(guī)范化,并基于它創(chuàng)建一個(gè)用戶定義的語(yǔ)料庫(kù)。
在本文中,你將學(xué)習(xí)7個(gè)不同的實(shí)例。我們將學(xué)習(xí)從PDF文件、Word文檔和Web中獲取數(shù)據(jù)。PDF和Word文檔是二進(jìn)制文件,通過Web,你將獲得HTML格式的數(shù)據(jù),因此,我們也會(huì)對(duì)數(shù)據(jù)執(zhí)行規(guī)范化和原始文本轉(zhuǎn)換任務(wù)。
作者:克里希納·巴夫薩、納雷什·庫(kù)馬爾、普拉塔普·丹蒂
如需轉(zhuǎn)載請(qǐng)聯(lián)系大數(shù)據(jù)(ID:hzdashuju)
01 字符串操作的重要性
作為一名NLP專家,你將要處理大量的文本內(nèi)容。當(dāng)你在處理文本時(shí),你必須知道一些字符串操作。我們將從幾個(gè)簡(jiǎn)短的范例入手,幫助你理解str類及其在Python中的相關(guān)操作。
1. 準(zhǔn)備工作
這里,你僅僅需要Python解釋器和一個(gè)文本編輯器。我們將使用join(連接)、split(分割)、addition(加法)和multiplication(乘法)運(yùn)算符以及索引。
2. 如何實(shí)現(xiàn)
(1)創(chuàng)建一個(gè)新的Python文件,命名為StringOps1.py。
(2)定義以下兩個(gè)對(duì)象:
namesList = ['Tuffy','Ali','Nysha','Tim' ]
sentence = 'My dog sleeps on sofa'
第一個(gè)對(duì)象nameList是一個(gè)包含若干名字的字符串列表,第二個(gè)對(duì)象sentence是一個(gè)包含一句話的字符串對(duì)象。
(3)首先,我們看看join函數(shù)的特點(diǎn)以及它的功能:
names = ';'.join(namesList)
print(type(names), ':', names)
join()函數(shù)可以被任意一個(gè)string對(duì)象調(diào)用,它的輸入?yún)?shù)是一個(gè)str對(duì)象的列表。通過將調(diào)用字符串的內(nèi)容作為連接分隔符,它將所有str對(duì)象連接成一個(gè)str對(duì)象,并返回連接后的對(duì)象。運(yùn)行這兩行代碼后,你得到的輸出如下:
<class 'str'> : Tuffy;Ali;Nysha;Tim
(4)接下來(lái),我們來(lái)看split方法的功能:
wordList = sentence.split(' ')
print((type(wordList)), ':', wordList)
當(dāng)split函數(shù)調(diào)用一個(gè)字符串時(shí),它會(huì)將其內(nèi)容分割為多個(gè)str對(duì)象,創(chuàng)建一個(gè)包含這些字符串對(duì)象的列表,并返回該列表。該函數(shù)接受單個(gè)str對(duì)象作為參數(shù),表示分隔符。運(yùn)行代碼,得到如下輸出:
<class 'list'> : ['My', 'dog', 'sleeps', 'on', 'sofa']
(5)算術(shù)運(yùn)算符+和*也可以用于字符串。添加以下代碼并輸出:
additionExample = 'ganehsa' + 'ganesha' + 'ganesha'
multiplicationExample = 'ganesha' * 2
print('Text Additions :', additionExample)
print('Text Multiplication :', multiplicationExample)
我們首先看一下輸出結(jié)果,隨后討論其工作原理:
Text Additions: ganehsaganeshaganesha
Text Multiplication: ganeshaganesha
+運(yùn)算符被稱為連接符,它將字符串連接為單個(gè)str對(duì)象,產(chǎn)生一個(gè)新的字符串。如前所述,我們也可以使用*運(yùn)算符對(duì)字符串做乘法。此外,需要注意的是這些操作不會(huì)添加任何額外的內(nèi)容,例如在字符串之間插入空格。
(6)接下來(lái),我們來(lái)了解一下字符串中的字符索引。添加下列幾行代碼:
str = 'Python NLTK'
print(str[1])
print(str[-3])
首先,我們聲明一個(gè)新的 string 對(duì)象。然后可以直接訪問字符串中的第二個(gè)字符(y)。這里還有個(gè)小技巧:Python允許你在訪問任何列表對(duì)象時(shí)使用負(fù)索引,比如說(shuō)-1意味著最后一個(gè)成員,-2是倒數(shù)第二個(gè)成員,依此類推。例如,在前面代碼的str對(duì)象中,索引7和-4是相同的字符N:
Output: <class 'str'> : Tuffy;Ali;Nysha;Tim
<class 'list'> : ['My', 'dog', 'sleeps', 'on', 'sofa']
Text Additions : ganehsaganeshaganesha
Text Multiplication : ganeshaganesha
y L
3. 工作原理
我們使用split()函數(shù)將一個(gè)字符串變成了一個(gè)字符串列表,并使用join()函數(shù)將一個(gè)字符串列表變成了一個(gè)字符串。接下來(lái)我們了解了有關(guān)字符串的一些算術(shù)運(yùn)算符的用法。
需要注意的是,我們不能在字符串中使用“-”(負(fù)號(hào))和“/”(除法)運(yùn)算符。最后,我們了解了如何在任一字符串中訪問單個(gè)字符,特別值得一提的是,我們可以在訪問字符串時(shí)使用負(fù)索引。
本段實(shí)例非常簡(jiǎn)單和直觀,主要是介紹Python允許的一些常見和不常見的字符串操作。接下來(lái),我們將在以上操作基礎(chǔ)上繼續(xù)學(xué)習(xí)一些字符串操作。
02 深入實(shí)踐字符串操作
接下來(lái),我們將了解子字符串、字符串替換以及如何訪問一個(gè)字符串的所有字符。
1. 如何實(shí)現(xiàn)
(1)創(chuàng)建一個(gè)新的Python文件,命名為StringOps2.py并定義以下string對(duì)象:
str = 'NLTK Dolly Python'
(2)訪問str對(duì)象中以第四個(gè)字符作為結(jié)束的子串。
print('Substring ends at:',str[:4])
我們知道索引從零開始,因此將返回由第0個(gè)到第3個(gè)字符組成的子串。運(yùn)行代碼,輸出如下:
Substring ends at: NLTK
(3)訪問str對(duì)象中從某個(gè)點(diǎn)開始直到末尾的子串:
print('Substring starts from:',str[11:] )
以上代碼指示解釋器返回str對(duì)象中從索引11到結(jié)束的一個(gè)子串。運(yùn)行代碼,得到以下輸出:
Substring starts from: Python
(4)從str對(duì)象中訪問包含Dolly的子串。添加以下行:
print('Substring :',str[5:10])
以上代碼返回從索引5到10的字符,不包括第10個(gè)字符。輸出是:
Substring : Dolly
(5)我們?cè)谇耙欢沃幸呀?jīng)了解了負(fù)索引在字符串操作中的應(yīng)用?,F(xiàn)在我們?cè)囋嚳此讷@取子串中的作用:
print('Substring fancy:', str[-12:-7])
Run and check the output, it will be –
Substring fancy: Dolly
這里得到的輸出與上一步完全相同!為了理解這個(gè)結(jié)果,我們做一些計(jì)算:-1表示最后一個(gè)字符,-2是倒數(shù)第二個(gè)字符,依此類推。你將會(huì)發(fā)現(xiàn)[5:10]和[-12:-7]在這個(gè)例子中得出的子串是相同的。
(6)了解in操作符在if語(yǔ)句中的用法:
if 'NLTK' in str:
print('found NLTK')
運(yùn)行以上代碼,程序的輸出如下所示:
found NLTK
如上所示,in操作符會(huì)檢查左邊的字符串是否屬于右邊字符串的子串。
(7)了解str對(duì)象中replace函數(shù)的使用:
replaced = str.replace('Dolly', 'Dorothy')
print('Replaced String:', replaced)
replace函數(shù)只需要兩個(gè)參數(shù)。第一個(gè)是需要被替換的子字符串,第二個(gè)是用來(lái)替換前面子字符串的新子字符串。replace函數(shù)返回一個(gè)新的string對(duì)象,并且它不會(huì)修改調(diào)用它的字符串,運(yùn)行代碼,有如下輸出:
Replaced String: NLTK Dorothy Python
(8)最后,迭代上面得到的replaced對(duì)象并訪問它的每一個(gè)字符:
print('Accessing each character:')
for s in replaced:
print(s)
以上操作每次在新的一行輸出replaced對(duì)象的每個(gè)字符,最終輸出如下:
Output: Substring ends at: NLTK
Substring starts from: Python
Substring : Dolly
Substring fancy: Dolly
found NLTK
Replaced String: NLTK Dorothy Python
Accessing each character:
N
L
T
K
D
o
r
o
t
h
y
P
y
t
h
o
n
2. 工作原理
字符串對(duì)象只是一個(gè)字符列表。正如第一步所示,我們可以像訪問一個(gè)列表那樣用for語(yǔ)句來(lái)訪問字符串中的每個(gè)字符。任何列表的方括號(hào)內(nèi)的字符“:”表示我們想要的一個(gè)子列表。
方括號(hào)內(nèi),如果字符“:”之后是一個(gè)數(shù)字n,表示我們希望獲得一個(gè)從列表索引0開始到索引n-1結(jié)束的子列表。同樣地,一個(gè)數(shù)字m后跟著字符“:”,則表示我們想要一個(gè)從列表索引m開始到列表末尾的子列表。
03 在Python中讀取PDF文件
這個(gè)實(shí)例是從Python中訪問PDF文件。首先,你需要安裝PyPDF2庫(kù)。
1. 準(zhǔn)備工作
假設(shè)你已經(jīng)安裝了pip。然后,在Python2或Python3版本上用pip安裝PyPDF2庫(kù),你只需要在命令行中運(yùn)行以下命令:
pip install pypdf2
如果你成功安裝了PyPDF2庫(kù),就完成了準(zhǔn)備工作。與此同時(shí),你需要通過以下鏈接下載一些我們將在本段用到的測(cè)試文檔:
https://www.dropbox.com/sh/bk18dizhsu1p534/AABEuJw4TArUbzJf4Aa8gp5Wa?dl=0
2. 如何實(shí)現(xiàn)
(1)創(chuàng)建一個(gè)新的Python文件,命名為pdf.py并添加以下代碼:
from PyPDF2 import PdfFileReader
這行代碼會(huì)導(dǎo)入PyPDF2庫(kù)中的PdfFileReader類。
(2)在上面創(chuàng)建的文件中添加如下Python函數(shù),它的功能是讀取一個(gè)PDF文件并返回其全文:
def getTextPDF(pdfFileName, password = '')
該函數(shù)需要兩個(gè)參數(shù),一個(gè)是你要讀取的PDF文件路徑,一個(gè)是這個(gè)PDF文件的密碼(如果有的話)??梢?,password 參數(shù)是可選的。
(3)現(xiàn)在我們來(lái)定義這個(gè)函數(shù)。在該函數(shù)下添加如下代碼:
pdf_file = open(pdfFileName, 'rb')
read_pdf = PdfFileReader(pdf_file)
第一行代碼會(huì)以讀取和反向查找模式打開文件。第一行本質(zhì)是一個(gè)Python文件打開命令/函數(shù),僅能打開非文本的二進(jìn)制文件。第二行將打開的文件傳遞給PdfFileReader類,用于處理PDF文檔。
(4)如果文件設(shè)置了密碼保護(hù),接下來(lái)是解密被密碼保護(hù)的PDF文件:
if password != '':
read_pdf.decrypt(password)
如果在函數(shù)調(diào)用時(shí)設(shè)置了密碼,那么我們?cè)诮饷苓@個(gè)文件時(shí)也同樣需要密碼。
(5)從PDF文件中讀取文本:
text = []
for i in range(0,read_pdf.getNumPages()-1):
text.append(read_pdf.getPage(i).extractText())
創(chuàng)建一個(gè)字符串列表,并將每一頁(yè)的文本都添加到這個(gè)列表中。
(6)返回最終的輸出結(jié)果:
return '\n'.join(text)
將列表中所有的字符串都連接起來(lái),并且在每個(gè)字符串之間都加一個(gè)換行符,返回連接后的單一字符串。
(7)在pdf.py目錄下創(chuàng)建另一個(gè)名為TestPDFs.py 的文件,添加以下導(dǎo)入語(yǔ)句:
import pdf
(8)現(xiàn)在我們打印輸出兩個(gè)文檔中的文本,其中一個(gè)是受密碼保護(hù)的,一個(gè)是未加密的:
pdfFile = 'sample-one-line.pdf'
pdfFileEncrypted = 'sample-one-line.protected.pdf'
print('PDF 1: \n',pdf.getTextPDF(pdfFile))
print('PDF 2: \n',pdf.getTextPDF(pdfFileEncrypted,'tuffy'))
輸出:本實(shí)例的前六步只是創(chuàng)建了一個(gè)Python函數(shù),并不向控制臺(tái)輸出內(nèi)容,第七和第八步會(huì)輸出以下內(nèi)容:
This is a sample PDF document I am using to demonstrate in the
tutorial.
This is a sample PDF document
password protected.
3. 工作原理
PyPDF2是用于提取PDF文件內(nèi)容的一個(gè)純Python庫(kù)。該庫(kù)有很多功能,可用于裁剪頁(yè)面、疊加圖像數(shù)字簽名、創(chuàng)建新的PDF文件等。但是,對(duì)NLP工程師需要實(shí)現(xiàn)的文本分析任務(wù)來(lái)說(shuō),該庫(kù)只用來(lái)讀取內(nèi)容。
在第二步中,以反向查找模式打開文件很重要,因?yàn)楫?dāng)加載文件內(nèi)容時(shí),PyPDF2模塊試圖從尾部開始讀取文件內(nèi)容。此外,如果PDF文件是受密碼保護(hù)的,而你沒有在訪問文件前解密文件,Python解釋器將拋出一個(gè)PdfReadError錯(cuò)誤。
04 在Python中讀取Word文件
這里,我們將學(xué)習(xí)如何加載和讀取Word/DOCX文檔。用于讀取Word/DOCX文件的相關(guān)庫(kù)會(huì)更加全面,在這些庫(kù)中我們還可以處理段落邊界、文本樣式以及對(duì)所謂的run對(duì)象的操作。我們將會(huì)了解以上提到的所有內(nèi)容,因?yàn)檫@些內(nèi)容在文本分析任務(wù)中是至關(guān)重要的。
Tip: 如果你沒有安裝Microsoft Word軟件,你可以使用Liber Office和Open Office軟件的開源版本來(lái)創(chuàng)建和編輯“.docx”文件。
1. 準(zhǔn)備工作
假設(shè)你已經(jīng)在你的機(jī)器上安裝了pip,我們將使用pip來(lái)安裝python-docx庫(kù)。不要將它與另一個(gè)名為docx的庫(kù)混淆,這是兩個(gè)完全不同的庫(kù)。我們將從python docx庫(kù)中導(dǎo)入docx對(duì)象。在命令行中執(zhí)行下面的命令將安裝這個(gè)庫(kù):
pip install python-docx
成功安裝了該庫(kù)后,繼續(xù)下一步,我們將在這個(gè)實(shí)例中使用一個(gè)測(cè)試文檔,如果你已經(jīng)通過本文第一段提供的鏈接下載了所有文檔,你應(yīng)該已具備相關(guān)文檔。如果沒有,請(qǐng)從以下鏈接下載sample-one-line.docx文檔。
https://www.dropbox.com/sh/bk18dizhsu1p534/AABEuJw4TArUbzJf4Aa8gp5Wa?dl=0
現(xiàn)在,準(zhǔn)備工作就全部完成了。
2. 如何實(shí)現(xiàn)
(1)創(chuàng)建一個(gè)新的Python文件,命名為word.py并添加以下導(dǎo)入代碼:
import docx
這里只需導(dǎo)入python-docx模塊的docx對(duì)象。
(2)定義getTextWord函數(shù):
def getTextWord(wordFileName):
該函數(shù)需要一個(gè)字符串參數(shù)wordFileName,包含你要讀取的Word文件的絕對(duì)路徑。
(3)初始化doc 對(duì)象:
doc = docx.Document(wordFileName)
此時(shí)doc對(duì)象加載了你要讀取的Word文件。
(4)接下來(lái)我們要從已經(jīng)加載文檔的doc對(duì)象中讀取文本,添加以下代碼來(lái)實(shí)現(xiàn):
fullText = []
for para in doc.paragraphs:
fullText.append(para.text)
首先初始化一個(gè)字符串列表fullText,然后采用for循環(huán)逐段從文檔中讀取文本,并把每段都放到fullText列表中去。
(5)然后,我們將所有的片段/段落連接為一個(gè)字符串對(duì)象,并將其作為函數(shù)的輸出結(jié)果返回:
return '\n'.join(fullText)
通過以上操作,我們將fullText數(shù)組的所有元素用“\ n”分隔符連接起來(lái),并返回連接后的對(duì)象。最后保存該P(yáng)ython文件并退出。
(6)創(chuàng)建另一個(gè)Python文件,命名為TestDocX.py,并添加以下導(dǎo)入聲明:
import docx
import word
這里只需導(dǎo)入docx庫(kù)以及我們?cè)谇拔宀街袑?shí)現(xiàn)的word.py文件。
(7)現(xiàn)在我們將要讀取一個(gè)DOCX文件并使用我們?cè)趙ord.py中實(shí)現(xiàn)的API打印輸出它的全部?jī)?nèi)容。添加以下兩行代碼:
docName = 'sample-one-line.docx'
print('Document in full :\n',word.getTextWord(docName))
首先在第一行代碼中初始化文檔的路徑,然后使用API打印輸出文檔的全部?jī)?nèi)容。當(dāng)你運(yùn)行這部分代碼時(shí),得到以下輸出:
Document in full :
這是一個(gè)帶有一些粗體文本、一些斜體文本和一些下劃線文本的PDF示例文檔。我們還嵌入了一個(gè)標(biāo)題,如下所示:
This is my TITLE.
This is my third paragraph.
(8)正如前面提到的,Word / DOCX文檔是一個(gè)更加豐富的信息來(lái)源,除了提供文本內(nèi)容外,還能提供很多信息?,F(xiàn)在我們來(lái)看有關(guān)段落的信息。添加以下四行代碼:
doc = docx.Document(docName)
print('Number of paragraphs :',len(doc.paragraphs))
print('Paragraph 2:',doc.paragraphs[1].text)
print('Paragraph 2 style:',doc.paragraphs[1].style)
以上代碼的第二行打印出了給定文檔中段落的數(shù)量。第三行打印出了文檔中第二段的內(nèi)容。而第四行將會(huì)打印出第二段的樣式,比如在這個(gè)例子中的樣式就是Title類型。當(dāng)你運(yùn)行以上代碼后,輸出將如下所示:
Number of paragraphs : 3
Paragraph 2: This is my TITLE.
Paragraph 2 style: _ParagraphStyle('Title') id: 4374023248
(9)接下來(lái),我們將了解什么是run對(duì)象。添加以下代碼:
print('Paragraph 1:',doc.paragraphs[0].text)
print('Number of runs in paragraph 1:',len(doc.paragraphs[0].runs))
for idx, run in enumerate(doc.paragraphs[0].runs):
print('Run %s : %s' %(idx,run.text))
首先,我們獲得文檔第一段的全部?jī)?nèi)容。然后,我們獲得第一段中run對(duì)象的數(shù)目。最后,我們把每個(gè)run對(duì)象打印輸出。
(10)為了明確每個(gè)run對(duì)象的格式,添加以下代碼:
print('is Run 0 underlined:',doc.paragraphs[0].runs[5].underline)
print('is Run 2 bold:',doc.paragraphs[0].runs[1].bold)
print('is Run 7 italic:',doc.paragraphs[0].runs[3].italic)
這段代碼的各行分別在檢查相應(yīng)run對(duì)象的下劃線樣式、粗體樣式以及斜體樣式。最終輸出如下:
Output: Document in full :
This is a sample PDF document with some text in BOLD, some in
ITALIC and some underlined. We are also embedding a Title down
below.
This is my TITLE.
This is my third paragraph.
Number of paragraphs : 3
Paragraph 2: This is my TITLE.
Paragraph 2 style: _ParagraphStyle('Title') id: 4374023248
Paragraph 1: This is a sample PDF document with some text in BOLD,
some in ITALIC and some underlined. We're also embedding a Title
down below.
Number of runs in paragraph 1: 8
Run 0 : This is a sample PDF document with
Run 1 : some text in BOLD
Run 2 : ,
Run 3 : some in ITALIC
Run 4 : and
Run 5 : some underlined.
Run 6 : We are also embedding a Title down below
Run 7 : .
is Run 0 underlined: True
is Run 2 bold: True
is Run 7 italic: True
3. 工作原理
首先,我們?cè)趙ord.py文件中寫了一個(gè)函數(shù),它將讀取給定的DOCX文件并返回一個(gè)包含文件全部?jī)?nèi)容的字符串對(duì)象。前面的輸出內(nèi)容大都是不需要解釋的,我特別闡述了關(guān)于Paragraph和Run的輸出內(nèi)容。DOCX文件的結(jié)構(gòu)可以用python-docx庫(kù)的三個(gè)數(shù)據(jù)類型來(lái)表示,其中最高一級(jí)是Document對(duì)象。
每個(gè)文檔都包含多個(gè)段落。文檔中出現(xiàn)新的一行或一個(gè)回車,就表示開始一個(gè)新的段落。每個(gè)段落用多個(gè)Run對(duì)象表示段落內(nèi)格式的變化,這里的格式包含有字體、尺寸、顏色和其他樣式元素(如粗體、斜體、下劃線等等)。這些元素每次發(fā)生變化時(shí),都會(huì)創(chuàng)建一個(gè)新的Run對(duì)象。
05 使用PDF、DOCX和純文本文件,創(chuàng)建用戶自定義的語(yǔ)料庫(kù)
現(xiàn)在我們要?jiǎng)?chuàng)建自己的語(yǔ)料庫(kù),而不是使用從互聯(lián)網(wǎng)上得到的語(yǔ)料庫(kù)。
1. 準(zhǔn)備工作
在準(zhǔn)備方面,我們將使用本文第一個(gè)實(shí)例中提到的Dropbox文件夾中的幾個(gè)文件。如果你已經(jīng)從那個(gè)文件夾中下載了全部的文件,那么你已經(jīng)完成了準(zhǔn)備工作。否則,請(qǐng)從
https://www.dropbox.com/sh/bk18dizhsu1p534/AABEuJw4TArUbzJf4Aa8gp5Wa?dl=0
下載如下文件:
sample_feed.txt
sample-pdf.pdf
sample-one-line.docx
如果你沒有按照本文的順序來(lái)完成實(shí)例,那么你需要先回頭看看本文的前兩個(gè)實(shí)例。我們將用到本文前兩個(gè)實(shí)例中完成的兩個(gè)模塊 word.py和pdf.py。本段實(shí)例更多是關(guān)于本文前兩個(gè)實(shí)例所做工作的應(yīng)用以及語(yǔ)料庫(kù)概念的應(yīng)用。下面我們來(lái)看實(shí)際的代碼。
2. 如何實(shí)現(xiàn)
(1)創(chuàng)建一個(gè)新的Python文件,命名為createCorpus.py并添加以下代碼:
import os
import word, pdf
from nltk.corpus.reader.plaintext import PlaintextCorpusReader
我們導(dǎo)入os庫(kù)用于與文件有關(guān)的操作,word庫(kù)和pdf庫(kù)是本文前兩段完成的庫(kù),最后導(dǎo)入的PlaintextCorpusReader是為了完成語(yǔ)料庫(kù)建立這一最終目標(biāo)。
(2)編寫一個(gè)簡(jiǎn)單的函數(shù),用來(lái)打開并讀取一個(gè)純文本文件,并將其全部?jī)?nèi)容作為string對(duì)象返回。添加以下代碼:
def getText(txtFileName):
file = open(txtFileName, 'r')
return file.read()
第一行代碼定義了函數(shù)及其輸入?yún)?shù)。第二行代碼以只讀方式打開文件(open函數(shù)的第二個(gè)參數(shù)r表示以只讀方式打開)。第三行代碼讀取打開文件的內(nèi)容并將其作為string對(duì)象返回。
(3)在磁盤或文件系統(tǒng)中創(chuàng)建一個(gè)新文件夾corpus。添加以下三行代碼:
newCorpusDir = 'mycorpus/'
if not os.path.isdir(newCorpusDir):
os.mkdir(newCorpusDir)
第一行定義的string對(duì)象包含了新文件夾名,第二行檢查該文件夾在磁盤或文件系統(tǒng)中是否存在,第三行則通過執(zhí)行os.mkdir()函數(shù)在磁盤上創(chuàng)建一個(gè)給定名字的文件夾。以上代碼執(zhí)行后將在你的Python文件所在的工作目錄下創(chuàng)建一個(gè)名為mycorpus的新文件夾。
(4)然后,逐個(gè)讀取前面提到的三個(gè)文件。首先從純文本文件開始,添加以下代碼:
txt1 = getText('sample_feed.txt')
調(diào)用之前完成的getText函數(shù),它將讀取Sample_feed.txt文件并將輸出結(jié)果存入名為txt1的字符串對(duì)象中。
(5)現(xiàn)在,添加以下代碼來(lái)讀取PDF文件:
txt2 = pdf.getTextPDF('sample-pdf.pdf')
這里使用了PDF.py模塊的getTextPDF()函數(shù),它將讀取sample-pdf.pdf文件并將文件內(nèi)容存入名為txt2的字符串對(duì)象中。
(6)最后,通過以下代碼讀取DOCX文件:
txt3 = word.getTextWord('sample-one-line.docx')
這里使用了word.py模塊的getTexWord()函數(shù),它將讀取sample-one-line.docx文件并將文件內(nèi)容存入名為txt3的字符串對(duì)象中。
(7)接下來(lái),將上面讀到的三個(gè)字符串對(duì)象寫到磁盤文件中。添加以下代碼:
files = [txt1,txt2,txt3]
for idx, f in enumerate(files):
with open(newCorpusDir+str(idx)+'.txt', 'w') as fout:
fout.write(f)
第一行:創(chuàng)建一個(gè)包含以上三個(gè)字符串對(duì)象的數(shù)組
第二行:使用for循環(huán)來(lái)遍歷files數(shù)組
第三行:以只寫模式打開一個(gè)新文件(采用w選項(xiàng)調(diào)用open函數(shù))
第四行:將當(dāng)前字符串內(nèi)容寫到文件中
(8)在mycorpus目錄下,也就是我們之前存放文件的目錄下新建一個(gè)PlainTextCorpus對(duì)象:
newCorpus = PlaintextCorpusReader(newCorpusDir, '.*')
以上一行代碼看似簡(jiǎn)單,但是它在內(nèi)部做了很多的文本處理,如識(shí)別段落、句子、單詞等等。該函數(shù)的兩個(gè)參數(shù)分別是語(yǔ)料庫(kù)目錄的路徑以及要處理的文件名模式(這里我們已經(jīng)設(shè)置corpus reader可以處理該目錄下所有的文件)。通過以上步驟,我們創(chuàng)建了一個(gè)用戶自定義的語(yǔ)料庫(kù)。
(9)接下來(lái),我們來(lái)看PlainTextCorpusReader是否加載正常。添加以下代碼來(lái)進(jìn)行測(cè)試:
print(newCorpus.words())
print(newCorpus.sents(newCorpus.fileids()[1]))
print(newCorpus.paras(newCorpus.fileids()[0]))
第一行代碼將打印輸出語(yǔ)料庫(kù)包含的所有單詞數(shù)組(部分)。第二行代碼將打印輸出文件1.txt中的句子。第三行代碼將打印輸出文件0.txt中的段落:
Output: ['Five', 'months', '.', 'That', ''', 's', 'how', ...]
[['A', 'generic', 'NLP'], ['(', 'Natural', 'Language',
'Processing', ')', 'toolset'], ...]
[[['Five', 'months', '.']], [['That', ''', 's', 'how', 'long',
'it', ''', 's', 'been', 'since', 'Mass', 'Effect', ':',
'Andromeda', 'launched', ',', 'and', 'that', ''', 's', 'how',
'long', 'it', 'took', 'BioWare', 'Montreal', 'to', 'admit', 'that',
'nothing', 'more', 'can', 'be', 'done', 'with', 'the', 'ailing',
'game', ''', 's', 'story', 'mode', '.'], ['Technically', ',', 'it',
'wasn', ''', 't', 'even', 'a', 'full', 'five', 'months', ',', 'as',
'Andromeda', 'launched', 'on', 'March', '21', '.']], ...]
3. 工作原理
該實(shí)例最后一步的輸出很簡(jiǎn)單直接,展示了各個(gè)對(duì)象不同的特征。輸出內(nèi)容的第一行是新語(yǔ)料庫(kù)的單詞列表,它與句子、段落、文件等更高級(jí)的結(jié)構(gòu)沒有關(guān)系。
第二行是1.txt文件中所有句子組成的列表,其中每個(gè)句子都是由該句子中單詞組成的列表。
第三行是0.txt文件中所有段落組成的列表,其中每個(gè)段落對(duì)象又是由該段落中的句子組成的列表。從中可以發(fā)現(xiàn),這些段落和句子保留了很多原有的結(jié)構(gòu)。
06 讀取RSS信息源的內(nèi)容
豐富網(wǎng)站摘要(Rich Site Summary,RSS)信息源(feed)是一種計(jì)算機(jī)可讀格式,用于傳送互聯(lián)網(wǎng)上定期更新的內(nèi)容。大多數(shù)提供通知信息的網(wǎng)站以這種格式提供更新,例如新聞文章、在線出版物等。訂閱者可以通過規(guī)范化格式定期訪問其更新信息。
1. 準(zhǔn)備工作
本段實(shí)例的目標(biāo)是讀取一個(gè)RSS信息源并訪問其中的一條內(nèi)容。為此,我們將使用全球之聲(Mashable)提供的RSS信息源。全球之聲是一個(gè)數(shù)字媒體網(wǎng)站。簡(jiǎn)而言之,它是一個(gè)科技和社交媒體的博客列表。該網(wǎng)站的RSS信息源網(wǎng)址(URL)是:
http://feeds.mashable.com/Mashable
另外,我們需要用feedparser庫(kù)來(lái)讀取RSS信息源。打開終端并運(yùn)行以下命令即可在你的計(jì)算機(jī)上安裝這個(gè)庫(kù):
pip install feedparser
安裝好feedparser庫(kù)后,我們就可以開始實(shí)現(xiàn)第一個(gè)讀取RSS信息源的Python程序。
2. 如何實(shí)現(xiàn)
(1)創(chuàng)建一個(gè)新的Python文件,命名為rssReader.py,并添加以下代碼:
import feedparser
(2)將全球之聲信息源(Mashable feed)載入內(nèi)存中,添加以下代碼:
myFeed = feedparser.parse('http://feeds.mashable.com/Mashable')
myFeed對(duì)象包含全球之聲信息源的第一頁(yè),通過feedparser自動(dòng)下載和解析該信息源并填充到合適的位置。myFeed對(duì)象的條目列表將包含每個(gè)帖子(post)。
(3)檢查當(dāng)前信息源的標(biāo)題并計(jì)算帖子數(shù)目:
print('Feed Title :', myFeed['feed']['title'])
print('Number of posts :', len(myFeed.entries))
在第一行代碼中,我們通過myFeed對(duì)象獲取到了信息源的標(biāo)題。在第二行代碼中,我們計(jì)算了myFeed對(duì)象中entries對(duì)象的長(zhǎng)度。如前所述,entries對(duì)象是一個(gè)包含解析后信息源中所有帖子的列表。運(yùn)行代碼,輸出如下所示:
Feed Title: Mashable
Number of posts : 30
標(biāo)題是Mashable,當(dāng)前,Mashable每次最多存放30個(gè)帖子到信息源。
(4)從entries列表中獲取第一個(gè)post,并打印輸出其標(biāo)題:
post = myFeed.entries[0]
print('Post Title :',post.title)
在第一行代碼中,我們獲取了entries列表中的第一個(gè)元素并將其加載到post對(duì)象中。在第二行代碼中,我們打印輸出了post對(duì)象的標(biāo)題。運(yùn)行代碼,輸出應(yīng)該與以下內(nèi)容相似:
Post Title: The moon literally blocked the sun on Twitter
這里提到輸出內(nèi)容應(yīng)該與其相似而不是完全一樣,是因?yàn)樾畔⒃丛诓粩嘧晕腋隆?/span>
(5)訪問post的原始HTML內(nèi)容,并將其打印輸出:
content = post.content[0].value
print('Raw content :\n',content)
首先,我們?cè)L問post的內(nèi)容對(duì)象并獲取其具體值,打印輸出如下:
Output: Feed Title: Mashable
Number of posts : 30
Post Title: The moon literally blocked the sun on Twitter
Raw content :
<img alt=''
src='https://i.amz.mshcdn.com/DzkxxIQCjyFHGoIBJoRGoYU3Y8o=/575x323/
filters:quality(90)/https%3A%2F%2Fblueprint-apiproduction.s3.amazonaws.com%2Fuploads%2Fcard%2Fimage%2F569570%2F0ca
3e1bf-a4a2-4af4-85f0-1bbc8587014a.jpg' /><div style='float: right;
width: 50px;'><a
>Augus
t 21, 2017</a></p>
</blockquote></div></div>
3. 工作原理
互聯(lián)網(wǎng)上大多數(shù)的RSS信息源都以時(shí)間順序排列,將最新的帖子放到最上面。因此,在該實(shí)例中我們每次訪問的都是信息源提供的最新內(nèi)容。信息源本身是不斷更新的。所以,每次運(yùn)行程序時(shí),輸出的格式保持不變,但是輸出的內(nèi)容卻可能發(fā)生改變,這取決于信息源更新的速度。
另外,我們?cè)诳刂婆_(tái)直接輸出原始的HTML文本而不是其文本內(nèi)容。接下來(lái),我們將解析HTML并從頁(yè)面獲取我們需要的信息。最后,本實(shí)例可以附加以下內(nèi)容:讀取你想要的任何信息源,將信息源中所有帖子的信息存儲(chǔ)到磁盤,并利用它創(chuàng)建一個(gè)純文本的語(yǔ)料庫(kù)。當(dāng)然,你可以從上一個(gè)和下一個(gè)實(shí)例中獲得啟發(fā)。
07 使用BeautifulSoup解析HTML
大多數(shù)情況下,你需要處理的網(wǎng)上數(shù)據(jù)都以HTML頁(yè)面的形式存在。因此,我們認(rèn)為有必要向你介紹Python的HTML解析方法。有很多Python模塊可以用來(lái)解析HTML,在接下來(lái)的實(shí)例中,我們將使用BeautifulSoup4庫(kù)來(lái)解析HTML。
1. 準(zhǔn)備工作
BeautifulSoup4包適用于Python2和Python3。在使用這個(gè)包之前,我們需要提前下載并將它安裝在解釋器上。和之前一樣,我們將使用pip來(lái)安裝這個(gè)包。在命令行運(yùn)行以下命令:
pip install beautifulsoup4
另外,你還需要本文Dropbox文件夾中的sample-html.html文件。如果你還沒有下載該文件,請(qǐng)從以下鏈接下載:
https://www.dropbox.com/sh/bk18dizhsu1p534/AABEuJw4TArUbzJf4Aa8gp5Wa?dl=0
2. 如何實(shí)現(xiàn)
(1)完成所有準(zhǔn)備工作后,從導(dǎo)入以下聲明開始:
from bs4 import BeautifulSoup
從bs4模塊中導(dǎo)入BeautifulSoup類,它將用于解析HTML。
(2)將一個(gè)HTML文件加載到BeautifulSoup對(duì)象中:
html_doc = open('sample-html.html', 'r').read()
soup = BeautifulSoup(html_doc, 'html.parser')
在第一行代碼中,我們將sample-html.html文件的內(nèi)容加載到str對(duì)象html_doc中。然后,創(chuàng)建了一個(gè)BeautifulSoup對(duì)象,需要解析的HTML文件作為第一個(gè)參數(shù),html.parser作為第二個(gè)參數(shù)。通過以上操作,BeautifulSoup對(duì)象使用html解析器來(lái)解析文檔。它將文檔內(nèi)容加載到soup對(duì)象中進(jìn)行解析以備使用。
(3)soup對(duì)象最主要、最簡(jiǎn)單且最有用的功能就是去除所有的HTML標(biāo)簽并獲取文本內(nèi)容。添加以下代碼:
print('\n\nFull text HTML Stripped:')
print(soup.get_text())
在soup對(duì)象上調(diào)用的get_text()方法將返回HTML標(biāo)簽去除后的文件內(nèi)容。運(yùn)行以上代碼,將得到以下輸出:
Full text HTML Stripped:
Sample Web Page
Main heading
This is a very simple HTML document
Improve your image by including an image.
Add a link to your favorite Web site.
This is a new sentence without a paragraph break, in bold italics.
This is purely the contents of our sample HTML document without any
of the HTML tags.
(4)有時(shí)不僅需要去除HTML標(biāo)簽,可能還需要獲取特定標(biāo)簽的內(nèi)容。訪問其中的一個(gè)標(biāo)簽:
print('Accessing the <title> tag :', end=' ')
print(soup.title)
soup.title將返回文件中的第一個(gè)標(biāo)題(title)標(biāo)簽。以上代碼的輸出如下所示:
Accessing the <title> tag : <title>Sample Web Page</title>
(5)現(xiàn)在,我們需要某個(gè)HTML標(biāo)簽的文本內(nèi)容。通過以下代碼獲取<h1>標(biāo)簽的內(nèi)容:
print('Accessing the text of <H1> tag :', end=' ')
print(soup.h1.string)
soup.h1.string命令將返回以<h1>標(biāo)簽開頭的文本。以上代碼的輸出如下所示:
Accessing the text of <H1> tag : Main heading
(6)訪問標(biāo)簽的屬性。這里,我們將訪問img標(biāo)簽的alt屬性。添加以下代碼行:
print('Accessing property of <img> tag :', end=' ')
print(soup.img['alt'])
通過仔細(xì)觀察,你會(huì)發(fā)現(xiàn)訪問標(biāo)簽屬性的語(yǔ)法和訪問標(biāo)簽文本的語(yǔ)法是不同的。運(yùn)行以上代碼,得到以下輸出:
Accessing property of <img> tag : A Great HTML Resource
(7)最后,一個(gè)HTML文件中同一類型的標(biāo)簽可能多次出現(xiàn)。使用“.”語(yǔ)法僅能獲取文件中第一次出現(xiàn)的標(biāo)簽。為了獲取所有的標(biāo)簽,我們將使用find_all()函數(shù),如下所示:
print('\nAccessing all occurences of the <p> tag :')
for p in soup.find_all('p'):
print(p.string)
在BeautifulSoup對(duì)象上調(diào)用find_all()函數(shù),參數(shù)是標(biāo)簽名,它將搜索整個(gè)HTML樹并返回符合條件的標(biāo)簽列表。我們使用for循環(huán)來(lái)遍歷該列表,并將BeautifulSoup對(duì)象中所有<p>標(biāo)簽的內(nèi)容/文本打印并輸出:
Output: Full text HTML Stripped:
Sample Web Page
Main heading
This is a very simple HTML document
Improve your image by including an image.
Add a link to your favorite Web site.
This is a new sentence without a paragraph break, in bold italics.
Accessing the <title> tag : <title>Sample Web Page</title>
Accessing the text of <H1> tag : Main heading
Accessing property of <img> tag : A Great HTML Resource
Accessing all occurences of the <p> tag :
This is a very simple HTML document
Improve your image by including an image.
None
3. 工作原理
BeautifulSoup4是一個(gè)很方便的庫(kù),可以用于解析任何HTML和XML內(nèi)容。它支持Python內(nèi)置的HTML解析器,但是你也可以使用其他第三方的解析器,例如,lxml解析器和純Python的html5lib解析器。
這里,我們使用Python內(nèi)置的HTML解析器。如果你了解了HTML并會(huì)編寫簡(jiǎn)單的HTML代碼的話,輸出結(jié)果是非常容易理解的。
關(guān)于作者:克里希納·巴夫薩(KrishnaBhavsar)花了大約10年時(shí)間在各行業(yè)領(lǐng)域如酒店業(yè)、銀行業(yè)、醫(yī)療行業(yè)等進(jìn)行自然語(yǔ)言處理、社交媒體分析和文本挖掘方面的研究。他致力于用不同的NLP語(yǔ)料庫(kù)如StanfordCoreNLP、IBM的 SystemText和BigInsights、GATE和NLTK來(lái)解決與文本分析有關(guān)的行業(yè)問題。
聯(lián)系客服