歡迎光臨
每天分享高質量文章

實用乾貨:7個實體教你從PDF、Word和網頁中提取資料

導讀:本文的標的是介紹一些Python庫,幫助你從類似於PDF和Word DOCX 這樣的二進位制檔案中提取資料。我們也將瞭解和學習如何從網路資訊源(web feeds)(如RSS)中獲取資料,以及利用一個庫幫助解析HTML文字並從檔案中提取原始文字。

我們還將學習如何從不同來源提取原始文字,對其進行規範化,並基於它建立一個使用者定義的語料庫。

在本文中,你將學習7個不同的實體。我們將學習從PDF檔案、Word檔案和Web中獲取資料。PDF和Word檔案是二進位制檔案,透過Web,你將獲得HTML格式的資料,因此,我們也會對資料執行規範化和原始文字轉換任務。

 

 

作者:克裡希納·巴夫薩、納雷什·庫馬爾、普拉塔普·丹蒂

如需轉載請聯絡大資料(ID:hzdashuju)

 

 

 

01 字串操作的重要性

 

作為一名NLP專家,你將要處理大量的文字內容。當你在處理文字時,你必須知道一些字串操作。我們將從幾個簡短的範例入手,幫助你理解str類及其在Python中的相關操作。

 

1. 準備工作

 

這裡,你僅僅需要Python直譯器和一個文字編輯器。我們將使用join(連線)、split(分割)、addition(加法)和multiplication(乘法)運運算元以及索引。

 

2. 如何實現

 

(1)建立一個新的Python檔案,命名為StringOps1.py。

 

(2)定義以下兩個物件:

 

namesList = ['Tuffy','Ali','Nysha','Tim' ]
sentence = 'My dog sleeps on sofa'

 

第一個物件nameList是一個包含若干名字的字串串列,第二個物件sentence是一個包含一句話的字串物件。

 

(3)首先,我們看看join函式的特點以及它的功能:

 

names = ';'.join(namesList)
print(type(names), ':', names)

 

join()函式可以被任意一個string物件呼叫,它的輸入引數是一個str物件的串列。透過將呼叫字串的內容作為連線分隔符,它將所有str物件連線成一個str物件,並傳回連線後的物件。執行這兩行程式碼後,你得到的輸出如下:

 

 : Tuffy;Ali;Nysha;Tim

 

(4)接下來,我們來看split方法的功能:

 

wordList = sentence.split(' ')
print((type(wordList)), ':', wordList)

當split函式呼叫一個字串時,它會將其內容分割為多個str物件,建立一個包含這些字串物件的串列,並傳回該串列。該函式接受單個str物件作為引數,表示分隔符。執行程式碼,得到如下輸出:

 

 : ['My', 'dog', 'sleeps', 'on', 'sofa']

 

(5)算術運運算元+和*也可以用於字串。新增以下程式碼並輸出:

 

additionExample = 'ganehsa' + 'ganesha' + 'ganesha'
multiplicationExample = 'ganesha' * 2
print('Text Additions :', additionExample)
print('Text Multiplication :', multiplicationExample)

 

我們首先看一下輸出結果,隨後討論其工作原理:

 

Text Additions: ganehsaganeshaganesha
Text Multiplication: ganeshaganesha

 

+運運算元被稱為連線符,它將字串連線為單個str物件,產生一個新的字串。如前所述,我們也可以使用*運運算元對字串做乘法。此外,需要註意的是這些操作不會新增任何額外的內容,例如在字串之間插入空格。

 

(6)接下來,我們來瞭解一下字串中的字元索引。新增下列幾行程式碼:

 

str = 'Python NLTK'
print(str[1])
print(str[-3])

 

首先,我們宣告一個新的 string 物件。然後可以直接訪問字串中的第二個字元(y)。這裡還有個小技巧:Python允許你在訪問任何串列物件時使用負索引,比如說-1意味著最後一個成員,-2是倒數第二個成員,依此類推。例如,在前面程式碼的str物件中,索引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()函式將一個字串變成了一個字串串列,並使用join()函式將一個字串串列變成了一個字串。接下來我們瞭解了有關字串的一些算術運運算元的用法。

需要註意的是,我們不能在字串中使用“-”(負號)和“/”(除法)運運算元。最後,我們瞭解瞭如何在任一字串中訪問單個字元,特別值得一提的是,我們可以在訪問字串時使用負索引。

 

本段實體非常簡單和直觀,主要是介紹Python允許的一些常見和不常見的字串操作。接下來,我們將在以上操作基礎上繼續學習一些字串操作。

 

 

02 深入實踐字串操作

 

接下來,我們將瞭解子字串、字串替換以及如何訪問一個字串的所有字元。

 

1. 如何實現

 

(1)建立一個新的Python檔案,命名為StringOps2.py並定義以下string物件:

 

str = 'NLTK Dolly Python'

 

(2)訪問str物件中以第四個字元作為結束的子串。

 

print('Substring ends at:',str[:4])

 

我們知道索引從零開始,因此將傳回由第0個到第3個字元組成的子串。執行程式碼,輸出如下:

 

Substring ends at: NLTK

 

(3)訪問str物件中從某個點開始直到末尾的子串:

 

print('Substring starts from:',str[11:] )

 

以上程式碼指示直譯器傳回str物件中從索引11到結束的一個子串。執行程式碼,得到以下輸出:

 

Substring starts from: Python

 

(4)從str物件中訪問包含Dolly的子串。新增以下行:

 

print('Substring :',str[5:10])

 

以上程式碼傳回從索引5到10的字元,不包括第10個字元。輸出是:

 

Substring : Dolly

 

(5)我們在前一段中已經瞭解了負索引在字串操作中的應用。現在我們試試看它在獲取子串中的作用:

 

print('Substring fancy:', str[-12:-7])
Run and check the output, it will be –
Substring fancy: Dolly

 

這裡得到的輸出與上一步完全相同!為了理解這個結果,我們做一些計算:-1表示最後一個字元,-2是倒數第二個字元,依此類推。你將會發現[5:10]和[-12:-7]在這個例子中得出的子串是相同的。

 

(6)瞭解in運運算元在if陳述句中的用法:

 

if 'NLTK' in str:
 print('found NLTK')

 

執行以上程式碼,程式的輸出如下所示:

 

found NLTK

 

如上所示,in運運算元會檢查左邊的字串是否屬於右邊字串的子串。

 

(7)瞭解str物件中replace函式的使用:

 

replaced = str.replace('Dolly''Dorothy')
print('Replaced String:', replaced)

 

replace函式只需要兩個引數。第一個是需要被替換的子字串,第二個是用來替換前面子字串的新子字串。replace函式傳回一個新的string物件,並且它不會修改呼叫它的字串,執行程式碼,有如下輸出:

 

Replaced String: NLTK Dorothy Python

 

(8)最後,迭代上面得到的replaced物件並訪問它的每一個字元:

 

print('Accessing each character:')
for s in replaced:
  print(s)

 

以上操作每次在新的一行輸出replaced物件的每個字元,最終輸出如下:

 

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. 工作原理

 

字串物件只是一個字串列。正如第一步所示,我們可以像訪問一個串列那樣用for陳述句來訪問字串中的每個字元。任何串列的方括號內的字元“:”表示我們想要的一個子串列。

方括號內,如果字元“:”之後是一個數字n,表示我們希望獲得一個從串列索引0開始到索引n-1結束的子串列。同樣地,一個數字m後跟著字元“:”,則表示我們想要一個從串列索引m開始到串列末尾的子串列。

 

 

03 在Python中讀取PDF檔案

 

這個實體是從Python中訪問PDF檔案。首先,你需要安裝PyPDF2庫。

 

1. 準備工作

 

假設你已經安裝了pip。然後,在Python2或Python3版本上用pip安裝PyPDF2庫,你只需要在命令列中執行以下命令:

 

pip install pypdf2

 

如果你成功安裝了PyPDF2庫,就完成了準備工作。與此同時,你需要透過以下連結下載一些我們將在本段用到的測試檔案:

https://www.dropbox.com/sh/bk18dizhsu1p534/AABEuJw4TArUbzJf4Aa8gp5Wa?dl=0

 

2. 如何實現

 

(1)建立一個新的Python檔案,命名為pdf.py並新增以下程式碼:

 

from PyPDF2 import PdfFileReader

 

這行程式碼會匯入PyPDF2庫中的PdfFileReader類。

 

(2)在上面建立的檔案中新增如下Python函式,它的功能是讀取一個PDF檔案並傳回其全文:

 

def getTextPDF(pdfFileName, password = '')

 

該函式需要兩個引數,一個是你要讀取的PDF檔案路徑,一個是這個PDF檔案的密碼(如果有的話)。可見,password 引數是可選的。

 

(3)現在我們來定義這個函式。在該函式下新增如下程式碼:

 

pdf_file = open(pdfFileName, 'rb')
read_pdf = PdfFileReader(pdf_file)

 

 

第一行程式碼會以讀取和反向查詢樣式開啟檔案。第一行本質是一個Python檔案開啟命令/函式,僅能開啟非文字的二進位制檔案。第二行將開啟的檔案傳遞給PdfFileReader類,用於處理PDF檔案。

 

(4)如果檔案設定了密碼保護,接下來是解密被密碼保護的PDF檔案:

 

if password != '':
read_pdf.decrypt(password)

 

如果在函式呼叫時設定了密碼,那麼我們在解密這個檔案時也同樣需要密碼。

 

(5)從PDF檔案中讀取文字:

 

text = []
for i in range(0,read_pdf.getNumPages()-1):
text.append(read_pdf.getPage(i).extractText())

 

建立一個字串串列,並將每一頁的文字都新增到這個串列中。

 

(6)傳回最終的輸出結果:

 

return '\n'.join(text)

 

將串列中所有的字串都連線起來,並且在每個字串之間都加一個換行符,傳回連線後的單一字串。

 

(7)在pdf.py目錄下建立另一個名為TestPDFs.py 的檔案,新增以下匯入陳述句:

 

import pdf

 

(8)現在我們列印輸出兩個檔案中的文字,其中一個是受密碼保護的,一個是未加密的:

 

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'))

 

輸出:本實體的前六步只是建立了一個Python函式,並不向控制檯輸出內容,第七和第八步會輸出以下內容:

 

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檔案內容的一個純Python庫。該庫有很多功能,可用於裁剪頁面、疊加影象數字簽名、建立新的PDF檔案等。但是,對NLP工程師需要實現的文字分析任務來說,該庫只用來讀取內容。

在第二步中,以反向查詢樣式開啟檔案很重要,因為當載入檔案內容時,PyPDF2模組試圖從尾部開始讀取檔案內容。此外,如果PDF檔案是受密碼保護的,而你沒有在訪問檔案前解密檔案,Python直譯器將丟擲一個PdfReadError錯誤。

 

 

04 在Python中讀取Word檔案

 

這裡,我們將學習如何載入和讀取Word/DOCX檔案。用於讀取Word/DOCX檔案的相關庫會更加全面,在這些庫中我們還可以處理段落邊界、文字樣式以及對所謂的run物件的操作。我們將會瞭解以上提到的所有內容,因為這些內容在文字分析任務中是至關重要的。

 

Tip: 如果你沒有安裝Microsoft Word軟體,你可以使用Liber Office和Open Office軟體的開源版本來建立和編輯“.docx”檔案。

 

1. 準備工作

 

假設你已經在你的機器上安裝了pip,我們將使用pip來安裝python-docx庫。不要將它與另一個名為docx的庫混淆,這是兩個完全不同的庫。我們將從python docx庫中匯入docx物件。在命令列中執行下麵的命令將安裝這個庫:

 

pip install python-docx

 

成功安裝了該庫後,繼續下一步,我們將在這個實體中使用一個測試檔案,如果你已經透過本文第一段提供的連結下載了所有檔案,你應該已具備相關檔案。如果沒有,請從以下連結下載sample-one-line.docx檔案。

https://www.dropbox.com/sh/bk18dizhsu1p534/AABEuJw4TArUbzJf4Aa8gp5Wa?dl=0

 

現在,準備工作就全部完成了。

 

2. 如何實現

 

(1)建立一個新的Python檔案,命名為word.py並新增以下匯入程式碼:

 

import docx

 

這裡只需匯入python-docx模組的docx物件。

 

(2)定義getTextWord函式:

 

def getTextWord(wordFileName):

 

該函式需要一個字串引數wordFileName,包含你要讀取的Word檔案的絕對路徑。

 

(3)初始化doc 物件:

 

doc = docx.Document(wordFileName)

 

此時doc物件載入了你要讀取的Word檔案。

 

(4)接下來我們要從已經載入檔案的doc物件中讀取文字,新增以下程式碼來實現:

 

fullText = []
for para in doc.paragraphs:
  fullText.append(para.text)

 

首先初始化一個字串串列fullText,然後採用for迴圈逐段從檔案中讀取文字,並把每段都放到fullText串列中去。

 

(5)然後,我們將所有的片段/段落連線為一個字串物件,並將其作為函式的輸出結果傳回:

 

return '\n'.join(fullText)

 

透過以上操作,我們將fullText陣列的所有元素用“\ n”分隔符連線起來,並傳回連線後的物件。最後儲存該Python檔案並退出。

 

(6)建立另一個Python檔案,命名為TestDocX.py,並新增以下匯入宣告:

 

import docx
import word

 

這裡只需匯入docx庫以及我們在前五步中實現的word.py檔案。

 

(7)現在我們將要讀取一個DOCX檔案並使用我們在word.py中實現的API列印輸出它的全部內容。新增以下兩行程式碼:

 

docName = 'sample-one-line.docx'
print('Document in full :\n',word.getTextWord(docName))

 

首先在第一行程式碼中初始化檔案的路徑,然後使用API列印輸出文件的全部內容。當你執行這部分程式碼時,得到以下輸出:

 

Document in full :

 

這是一個帶有一些粗體文字、一些斜體文字和一些下劃線文字的PDF示例檔案。我們還嵌入了一個標題,如下所示:

 

This is my TITLE.
This is my third paragraph.

 

(8)正如前面提到的,Word / DOCX檔案是一個更加豐富的資訊來源,除了提供文字內容外,還能提供很多資訊。現在我們來看有關段落的資訊。新增以下四行程式碼:

 

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)

 

以上程式碼的第二行打印出了給定檔案中段落的數量。第三行打印出了檔案中第二段的內容。而第四行將會打印出第二段的樣式,比如在這個例子中的樣式就是Title型別。當你執行以上程式碼後,輸出將如下所示:

 

Number of paragraphs : 3
Paragraph 2: This is my TITLE.
Paragraph 2 style: _ParagraphStyle('Title') id: 4374023248

 

(9)接下來,我們將瞭解什麼是run物件。新增以下程式碼:

 

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))

 

首先,我們獲得檔案第一段的全部內容。然後,我們獲得第一段中run物件的數目。最後,我們把每個run物件列印輸出。

 

(10)為了明確每個run物件的格式,新增以下程式碼:

 

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)

 

這段程式碼的各行分別在檢查相應run物件的下劃線樣式、粗體樣式以及斜體樣式。最終輸出如下:

 

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. 工作原理

 

首先,我們在word.py檔案中寫了一個函式,它將讀取給定的DOCX檔案並傳回一個包含檔案全部內容的字串物件。前面的輸出內容大都是不需要解釋的,我特別闡述了關於Paragraph和Run的輸出內容。DOCX檔案的結構可以用python-docx庫的三個資料型別來表示,其中最高一級是Document物件。

 

每個檔案都包含多個段落。檔案中出現新的一行或一個回車,就表示開始一個新的段落。每個段落用多個Run物件表示段落內格式的變化,這裡的格式包含有字型、尺寸、顏色和其他樣式元素(如粗體、斜體、下劃線等等)。這些元素每次發生變化時,都會建立一個新的Run物件。

 

 

05 使用PDF、DOCX和純文字檔案,建立使用者自定義的語料庫

 

現在我們要建立自己的語料庫,而不是使用從網際網路上得到的語料庫。

 

1. 準備工作

 

在準備方面,我們將使用本文第一個實體中提到的Dropbox檔案夾中的幾個檔案。如果你已經從那個檔案夾中下載了全部的檔案,那麼你已經完成了準備工作。否則,請從

https://www.dropbox.com/sh/bk18dizhsu1p534/AABEuJw4TArUbzJf4Aa8gp5Wa?dl=0

下載如下檔案:

 

  • sample_feed.txt

  • sample-pdf.pdf

  • sample-one-line.docx

 

如果你沒有按照本文的順序來完成實體,那麼你需要先回頭看看本文的前兩個實體。我們將用到本文前兩個實體中完成的兩個模組 word.py和pdf.py。本段實體更多是關於本文前兩個實體所做工作的應用以及語料庫概念的應用。下麵我們來看實際的程式碼。

 

2. 如何實現

 

(1)建立一個新的Python檔案,命名為createCorpus.py並新增以下程式碼:

 

import os
import word, pdf
from nltk.corpus.reader.plaintext import PlaintextCorpusReader

 

我們匯入os庫用於與檔案有關的操作,word庫和pdf庫是本文前兩段完成的庫,最後匯入的PlaintextCorpusReader是為了完成語料庫建立這一最終標的。

 

(2)編寫一個簡單的函式,用來開啟並讀取一個純文字檔案,並將其全部內容作為string物件傳回。新增以下程式碼:

 

def getText(txtFileName):
  file = open(txtFileName, 'r')
  return file.read()

 

第一行程式碼定義了函式及其輸入引數。第二行程式碼以只讀方式開啟檔案(open函式的第二個引數r表示以只讀方式開啟)。第三行程式碼讀取開啟檔案的內容並將其作為string物件傳回。

 

(3)在磁碟或檔案系統中建立一個新檔案夾corpus。新增以下三行程式碼:

 

newCorpusDir = 'mycorpus/'
if not os.path.isdir(newCorpusDir):
    os.mkdir(newCorpusDir)

 

第一行定義的string物件包含了新檔案夾名,第二行檢查該檔案夾在磁碟或檔案系統中是否存在,第三行則透過執行os.mkdir()函式在磁碟上建立一個給定名字的檔案夾。以上程式碼執行後將在你的Python檔案所在的工作目錄下建立一個名為mycorpus的新檔案夾。

 

(4)然後,逐個讀取前面提到的三個檔案。首先從純文字檔案開始,新增以下程式碼:

 

txt1 = getText('sample_feed.txt')

 

呼叫之前完成的getText函式,它將讀取Sample_feed.txt檔案並將輸出結果存入名為txt1的字串物件中。

 

(5)現在,新增以下程式碼來讀取PDF檔案:

 

txt2 = pdf.getTextPDF('sample-pdf.pdf')

 

這裡使用了PDF.py模組的getTextPDF()函式,它將讀取sample-pdf.pdf檔案並將檔案內容存入名為txt2的字串物件中。

 

(6)最後,透過以下程式碼讀取DOCX檔案:

 

txt3 = word.getTextWord('sample-one-line.docx')

 

這裡使用了word.py模組的getTexWord()函式,它將讀取sample-one-line.docx檔案並將檔案內容存入名為txt3的字串物件中。

 

(7)接下來,將上面讀到的三個字串物件寫到磁碟檔案中。新增以下程式碼:

 

files = [txt1,txt2,txt3]
for idx, f in enumerate(files):
    with open(newCorpusDir+str(idx)+'.txt''w'as fout:
        fout.write(f)

 

  • 第一行:建立一個包含以上三個字串物件的陣列

  • 第二行:使用for迴圈來遍歷files陣列

  • 第三行:以只寫樣式開啟一個新檔案(採用w選項呼叫open函式)

  • 第四行:將當前字串內容寫到檔案中

 

(8)在mycorpus目錄下,也就是我們之前存放檔案的目錄下新建一個PlainTextCorpus物件:

 

newCorpus = PlaintextCorpusReader(newCorpusDir, '.*')

 

以上一行程式碼看似簡單,但是它在內部做了很多的文字處理,如識別段落、句子、單詞等等。該函式的兩個引數分別是語料庫目錄的路徑以及要處理的檔案名樣式(這裡我們已經設定corpus reader可以處理該目錄下所有的檔案)。透過以上步驟,我們建立了一個使用者自定義的語料庫。

 

(9)接下來,我們來看PlainTextCorpusReader是否載入正常。新增以下程式碼來進行測試:

 

print(newCorpus.words())
print(newCorpus.sents(newCorpus.fileids()[1]))
print(newCorpus.paras(newCorpus.fileids()[0]))

 

第一行程式碼將列印輸出語料庫包含的所有單詞陣列(部分)。第二行程式碼將列印輸出檔案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. 工作原理

 

該實體最後一步的輸出很簡單直接,展示了各個物件不同的特徵。輸出內容的第一行是新語料庫的單詞串列,它與句子、段落、檔案等更高階的結構沒有關係。

第二行是1.txt檔案中所有句子組成的串列,其中每個句子都是由該句子中單片語成的串列。

第三行是0.txt檔案中所有段落組成的串列,其中每個段落物件又是由該段落中的句子組成的串列。從中可以發現,這些段落和句子保留了很多原有的結構。

 

 

06 讀取RSS資訊源的內容

 

豐富網站摘要(Rich Site Summary,RSS)資訊源(feed)是一種計算機可讀格式,用於傳送網際網路上定期更新的內容。大多數提供通知資訊的網站以這種格式提供更新,例如新聞文章、線上出版物等。訂閱者可以透過規範化格式定期訪問其更新資訊。

 

1. 準備工作

 

本段實體的標的是讀取一個RSS資訊源並訪問其中的一條內容。為此,我們將使用全球之聲(Mashable)提供的RSS資訊源。全球之聲是一個數字媒體網站。簡而言之,它是一個科技和社交媒體的部落格串列。該網站的RSS資訊源網址(URL)是:

http://feeds.mashable.com/Mashable

另外,我們需要用feedparser庫來讀取RSS資訊源。開啟終端並執行以下命令即可在你的計算機上安裝這個庫:

 

pip install feedparser

 

安裝好feedparser庫後,我們就可以開始實現第一個讀取RSS資訊源的Python程式。

 

2. 如何實現

 

(1)建立一個新的Python檔案,命名為rssReader.py,並新增以下程式碼:

 

import feedparser

 

(2)將全球之聲資訊源(Mashable feed)載入記憶體中,新增以下程式碼:

 

myFeed = feedparser.parse("http://feeds.mashable.com/Mashable")

 

myFeed物件包含全球之聲資訊源的第一頁,透過feedparser自動下載和解析該資訊源並填充到合適的位置。myFeed物件的條目串列將包含每個帖子(post)。

 

(3)檢查當前資訊源的標題並計算帖子數目:

 

print('Feed Title :', myFeed['feed']['title'])
print('Number of posts :', len(myFeed.entries))

 

在第一行程式碼中,我們透過myFeed物件獲取到了資訊源的標題。在第二行程式碼中,我們計算了myFeed物件中entries物件的長度。如前所述,entries物件是一個包含解析後資訊源中所有帖子的串列。執行程式碼,輸出如下所示:

 

Feed Title: Mashable
Number of posts : 30

 

標題是Mashable,當前,Mashable每次最多存放30個帖子到資訊源。

 

(4)從entries串列中獲取第一個post,並列印輸出其標題:

 

post = myFeed.entries[0]
print('Post Title :',post.title)

 

在第一行程式碼中,我們獲取了entries串列中的第一個元素並將其載入到post物件中。在第二行程式碼中,我們列印輸出了post物件的標題。執行程式碼,輸出應該與以下內容相似:

 

Post Title: The moon literally blocked the sun on Twitter

 

這裡提到輸出內容應該與其相似而不是完全一樣,是因為資訊源在不斷自我更新。

 

(5)訪問post的原始HTML內容,並將其列印輸出:

 

content = post.content[0].value
print('Raw content :\n',content)

 

首先,我們訪問post的內容物件並獲取其具體值,列印輸出如下:

 

Output: Feed Title: Mashable
Number of posts : 30
Post Title: The moon literally blocked the sun on Twitter
Raw content :
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" />

width: 50px;”>href=”http://twitter.com/share?via=Mashable&text;=The+moon+literally
+blocked+the+sun+on+Twitter&url;=http%3A%2F%2Fmashable.com%2F2017%2F
08%2F21%2Fmoon-blocks-sun-eclipse-2017-
twitter%2F%3Futm_campaign%3DMash-Prod-RSS-Feedburner-All-
Partial%26utm_cid%3DMash-Prod-RSS-Feedburner-All-Partial”
style=”margin: 10px;”>

The national space agency threw shade the best way it knows how:
by blocking the sun. Yep, you read that right.

 

 

HA HA HA I’ve blocked the Sun! Make way for the Moonhref=”https://twitter.com/hashtag/SolarEclipse2017?src=hash”>#Solar
Eclipse2017

 

 href=”https://t.co/nZCoqBlSTe”>pic.twitter.com/nZCoqBlSTe

— NASA Moon (@NASAMoon) href=”https://twitter.com/NASAMoon/status/899681358737539073″>Augus
t 21, 2017

 

 

3. 工作原理

 

網際網路上大多數的RSS資訊源都以時間順序排列,將最新的帖子放到最上面。因此,在該實體中我們每次訪問的都是資訊源提供的最新內容。資訊源本身是不斷更新的。所以,每次執行程式時,輸出的格式保持不變,但是輸出的內容卻可能發生改變,這取決於資訊源更新的速度。

另外,我們在控制檯直接輸出原始的HTML文字而不是其文字內容。接下來,我們將解析HTML並從頁面獲取我們需要的資訊。最後,本實體可以附加以下內容:讀取你想要的任何資訊源,將資訊源中所有帖子的資訊儲存到磁碟,並利用它建立一個純文字的語料庫。當然,你可以從上一個和下一個實體中獲得啟發。

 

 

07 使用BeautifulSoup解析HTML

 

大多數情況下,你需要處理的網上資料都以HTML頁面的形式存在。因此,我們認為有必要向你介紹Python的HTML解析方法。有很多Python模組可以用來解析HTML,在接下來的實體中,我們將使用BeautifulSoup4庫來解析HTML。

 

1. 準備工作

 

BeautifulSoup4包適用於Python2和Python3。在使用這個包之前,我們需要提前下載並將它安裝在直譯器上。和之前一樣,我們將使用pip來安裝這個包。在命令列執行以下命令:

 

pip install beautifulsoup4

 

另外,你還需要本文Dropbox檔案夾中的sample-html.html檔案。如果你還沒有下載該檔案,請從以下連結下載:

https://www.dropbox.com/sh/bk18dizhsu1p534/AABEuJw4TArUbzJf4Aa8gp5Wa?dl=0

 

2. 如何實現

 

(1)完成所有準備工作後,從匯入以下宣告開始:

 

from bs4 import BeautifulSoup

 

從bs4模組中匯入BeautifulSoup類,它將用於解析HTML。

 

(2)將一個HTML檔案載入到BeautifulSoup物件中:

 

html_doc = open('sample-html.html''r').read()
soup = BeautifulSoup(html_doc, 'html.parser')

 

在第一行程式碼中,我們將sample-html.html檔案的內容載入到str物件html_doc中。然後,建立了一個BeautifulSoup物件,需要解析的HTML檔案作為第一個引數,html.parser作為第二個引數。透過以上操作,BeautifulSoup物件使用html解析器來解析檔案。它將檔案內容載入到soup物件中進行解析以備使用。

 

(3)soup物件最主要、最簡單且最有用的功能就是去除所有的HTML標簽並獲取文字內容。新增以下程式碼:

 

print('\n\nFull text HTML Stripped:')
print(soup.get_text())

 

在soup物件上呼叫的get_text()方法將傳回HTML標簽去除後的檔案內容。執行以上程式碼,將得到以下輸出:

 

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)有時不僅需要去除HTML標簽,可能還需要獲取特定標簽的內容。訪問其中的一個標簽:

 

print('Accessing the , end=' ')
print(soup.title)

 

soup.title將傳回檔案中的第一個標題(title)標簽。以上程式碼的輸出如下所示:

 

Accessing the 

 

(5)現在,我們需要某個HTML標簽的文字內容。透過以下程式碼獲取

標簽的內容:

 

 

print('Accessing the text of 

 tag :’

 

, end=' ')
print(soup.h1.string)

 

soup.h1.string命令將傳回以

標簽開頭的文字。以上程式碼的輸出如下所示:

 

 

Accessing the text of 

 tag : Main heading

 

 

(6)訪問標簽的屬性。這裡,我們將訪問img標簽的alt屬性。新增以下程式碼行:

 

print('Accessing property of  tag :', end=' ')
print(soup.img['alt'])

 

透過仔細觀察,你會發現訪問標簽屬性的語法和訪問標簽文字的語法是不同的。執行以上程式碼,得到以下輸出:

 

Accessing property of  tag : A Great HTML Resource

 

(7)最後,一個HTML檔案中同一型別的標簽可能多次出現。使用“.”語法僅能獲取檔案中第一次出現的標簽。為了獲取所有的標簽,我們將使用find_all()函式,如下所示:

 

print('\nAccessing all occurences of the 

tag :’

 

)
for p in soup.find_all('p'):
    print(p.string)

 

在BeautifulSoup物件上呼叫find_all()函式,引數是標簽名,它將搜尋整個HTML樹並傳回符合條件的標簽串列。我們使用for迴圈來遍歷該串列,並將BeautifulSoup物件中所有

標簽的內容/文字列印並輸出:

 

 

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 
Accessing the text of 

 tag : Main heading
Accessing property of  tag : A Great HTML Resource
Accessing all occurences of the

tag :
This is a very simple HTML document
Improve your image by including an image.
None

 

 

3. 工作原理

 

BeautifulSoup4是一個很方便的庫,可以用於解析任何HTML和XML內容。它支援Python內建的HTML解析器,但是你也可以使用其他第三方的解析器,例如,lxml解析器和純Python的html5lib解析器。

這裡,我們使用Python內建的HTML解析器。如果你瞭解了HTML並會編寫簡單的HTML程式碼的話,輸出結果是非常容易理解的。

 

關於作者:克裡希納·巴夫薩(KrishnaBhavsar)花了大約10年時間在各行業領域如酒店業、銀行業、醫療行業等進行自然語言處理、社交媒體分析和文字挖掘方面的研究。他致力於用不同的NLP語料庫如StanfordCoreNLP、IBM的 SystemText和BigInsights、GATE和NLTK來解決與文字分析有關的行業問題。

納雷什·庫馬爾(NareshKumar)曾為財富500強企業設計、實施和執行超大型因特網應用程式,在這方面他擁有超過十年的專業經驗。他是一位全棧架構師,在電子商務、網路託管、醫療、大資料及分析、資料流、廣告和資料庫等領域擁有豐富的實踐經驗。

本文摘編自《自然語言處理Python進階》,經出版方授權釋出。

延伸閱讀《自然語言處理Python進階

點選上圖瞭解及購買

轉載請聯絡微信:togo-maruko

推薦語:本書包含的實體可以讓你學會使用NLTK(處理NLP任務的主要Python平臺)完成自然語言處理的各種任務,涵蓋了自然語言理解、自然語言處理和句法分析等。 

贊(0)

分享創造快樂