Python 提供了強大的工具和函式庫,方便我們處理網路和本地端的文字資料。從檔案讀取、網路爬蟲到 HTML 解析,都能夠有效率地完成。利用 NLTK 可以進一步進行分詞、去除標記等文字預處理工作,為後續的自然語言處理任務奠定基礎。同時,文章也提供處理 RSS 饋流以及 PDF、MSWord 等二進位格式檔案的實用技巧,讓開發者能更彈性地應對不同資料來源的挑戰。對於常見的檔案處理問題,例如檔案路徑錯誤、編碼問題等,也提供對應的解決方案,讓讀者能更順利地進行文字資料的處理與分析。
存取原始文字的技術與應用
隨著網路的普及,網路已成為最重要且豐富的文字來源。雖然我們可以利用現有的語料函式庫進行研究,但大多數情況下,我們仍需要學習如何存取自己的文字來源。本章將著重於回答以下幾個關鍵問題:
- 如何編寫程式以存取本地檔案和網路上的文字,從而取得無限的語言材料?
- 如何將檔案分解為單個詞彙和標點符號,以便進行與前幾章中對文字語料函式庫相同的分析?
- 如何編寫程式以產生格式化的輸出並將其儲存到檔案中?
存取本地檔案與網路文字
在處理原始文字之前,我們首先需要了解如何存取本地檔案和網路上的文字。Python 提供了多種方法來實作這一點。
存取本地檔案
Python 的內建函式 open()
可以用來開啟本地檔案。例如:
with open('example.txt', 'r', encoding='utf-8') as file:
text = file.read()
內容解密:
此段程式碼開啟了一個名為 example.txt
的檔案,並以讀取模式 ('r'
) 和 UTF-8 編碼方式讀取其內容。with
陳述式確保檔案在使用後正確關閉。
存取網路文字
要存取網路上的文字,我們可以使用 requests
函式庫。例如:
import requests
response = requests.get('http://example.com')
text = response.text
內容解密:
此段程式碼使用 requests.get()
方法向指定的 URL 傳送 GET 請求,並將伺服器的回應儲存在 response
物件中。然後,我們可以透過 response.text
屬性存取文字內容。
文字預處理
在存取文字之後,我們通常需要對其進行預處理,包括分詞(tokenization)和去除標記(markup)等步驟。
分詞(Tokenization)
分詞是將文字分解為單個詞彙或標點符號的過程。NLTK 提供了多種分詞工具,例如:
import nltk
from nltk.tokenize import word_tokenize
text = "This is an example sentence."
tokens = word_tokenize(text)
print(tokens)
內容解密:
此段程式碼使用 NLTK 的 word_tokenize()
函式將輸入的文字分解為單個詞彙和標點符號,並將結果儲存在 tokens
列表中。
格式化輸出與檔案儲存
最後,我們需要了解如何產生格式化的輸出並將其儲存到檔案中。Python 提供了多種方法來實作這一點,包括使用 print()
函式和 open()
函式。例如:
with open('output.txt', 'w', encoding='utf-8') as file:
file.write('This is an example output.\n')
內容解密:
此段程式碼開啟了一個名為 output.txt
的檔案,並以寫入模式 ('w'
) 和 UTF-8 編碼方式寫入指定的文字內容。
練習與討論
- 試著使用不同的分詞工具對相同的文字進行分詞,並比較結果。
- 編寫一個程式,從指定的 URL 下載文字,並將其儲存到本地檔案中。
- 試著對下載的文字進行預處理,包括分詞和去除標記等步驟。
隨著 NLP 技術的不斷發展,我們可以預見未來會有更多高效、準確的文字處理工具出現。同時,如何更好地應用這些技術於實際場景,將是我們需要持續探索的方向。
章節練習解答與解析
練習 17:找出文字中出現頻率最高的 50 個非停用詞
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from collections import Counter
def find_top_words(text, n=50):
stop_words = set(stopwords.words('english'))
tokens = word_tokenize(text.lower())
tokens = [token for token in tokens if token.isalpha() and token not in stop_words]
return Counter(tokens).most_common(n)
# 使用範例
text = "Your text here."
top_words = find_top_words(text)
print(top_words)
內容解密:
此函式首先將輸入的文字轉換為小寫並進行分詞,然後過濾掉非字母字元和停用詞。最後,使用 Counter
物件統計每個詞彙的出現頻率,並傳回出現頻率最高的 n
個詞彙。
練習 23:驗證 Zipf 定律
import nltk
from nltk.tokenize import word_tokenize
from collections import Counter
import matplotlib.pyplot as plt
def plot_zipf(text):
tokens = word_tokenize(text.lower())
tokens = [token for token in tokens if token.isalpha()]
freqs = Counter(tokens)
freqs = sorted(freqs.values(), reverse=True)
ranks = list(range(1, len(freqs) + 1))
plt.loglog(ranks, freqs)
plt.xlabel('Rank')
plt.ylabel('Frequency')
plt.title('Zipf\'s Law')
plt.show()
# 使用範例
text = "Your large text here."
plot_zipf(text)
內容解密:
此函式首先對輸入的文字進行分詞和頻率統計,然後將頻率按照降序排序。接著,繪製頻率與排名之間的雙對數圖,以驗證 Zipf 定律。
從網路和磁碟存取文字
電子書籍
NLTK語料函式庫收錄了Project Gutenberg的部分文字。然而,你可能對分析其他Project Gutenberg的文字感興趣。你可以瀏覽http://www.gutenberg.org/catalog/上的25,000本免費線上書籍目錄,並獲得ASCII文字檔的URL。雖然Project Gutenberg中90%的文字是英文,但它包含了超過50種其他語言的材料,包括加泰羅尼亞語、中文、荷蘭語、芬蘭語、法語、德語、義大利語、葡萄牙語和西班牙語(每種語言都有超過100個文字)。
存取特定電子書的範例
以《罪與罰》的英文翻譯(編號2554)為例,我們可以按照以下方式存取它:
>>> from urllib.request import urlopen
>>> url = "http://www.gutenberg.org/files/2554/2554-0.txt"
>>> raw = urlopen(url).read().decode('utf-8')
>>> type(raw)
<class 'str'>
>>> len(raw)
1176831
>>> raw[:75]
'The Project Gutenberg EBook of Crime and Punishment, by Fyodor Dostoevsky\r\n'
內容解密:
上述程式碼展示瞭如何從Project Gutenberg下載《罪與罰》的文字。首先,我們使用urlopen
函式開啟指定的URL並讀取內容。讀取的內容儲存在raw
變數中,它是一個包含1,176,831個字元的字串。我們可以看到這個字串包含了書的原始內容,包括不必要的細節,如空白字元、換行符和空行。
處理下載的文字
下載的文字需要經過**分詞(tokenization)**處理,將字串分解成單詞和標點符號。
>>> tokens = nltk.word_tokenize(raw)
>>> type(tokens)
<class 'list'>
>>> len(tokens)
255809
>>> tokens[:10]
['The', 'Project', 'Gutenberg', 'EBook', 'of', 'Crime', 'and', 'Punishment', ',', 'by']
內容解密:
這段程式碼使用NLTK函式庫的word_tokenize
函式對raw
字串進行分詞處理,生成一個包含單詞和標點符號的列表。這個列表儲存在tokens
變數中,總計有255,809個元素。
建立NLTK文字物件
對tokens
列表進行進一步處理,建立NLTK的Text
物件,可以進行各種語言處理操作。
>>> text = nltk.Text(tokens)
>>> type(text)
<class 'nltk.text.Text'>
>>> text[1020:1060]
['CHAPTER', 'I', 'On', 'an', 'exceptionally', 'hot', 'evening', 'early', 'in',
'July', 'a', 'young', 'man', 'came', 'out', 'of', 'the', 'garret', 'in',
'which', 'he', 'lodged', 'in', 'S', '.', 'Place', 'and', 'walked', 'slowly',
',', 'as', 'though', 'in', 'hesitation', ',', 'towards', 'K', '.', 'bridge', '.']
>>> text.collocations()
Katerina Ivanovna; Pulcheria Alexandrovna; Avdotya Romanovna; Pyotr
Petrovitch; Project Gutenberg; Marfa Petrovna; Rodion Romanovitch;
Sofya Semyonovna; Nikodim Fomitch; did not; Hay Market; Andrey
Semyonovitch; old woman; Literary Archive; Dmitri Prokofitch; great
deal; United States; Praskovya Pavlovna; Porfiry Petrovitch; ear rings
內容解密:
建立Text
物件後,我們可以對文字進行各種分析,如切片操作和搭配詞分析。搭配詞分析結果顯示了一些常見的片語,如人名、地名等。
清理不必要的內容
下載的文字通常包含不必要的頁首、頁尾和其他資訊,需要手動檢查並清理。
>>> raw.find("PART I")
5303
>>> raw.rfind("End of Project Gutenberg's Crime")
1157681
>>> raw = raw[5303:1157681]
>>> raw.find("PART I")
0
內容解密:
這段程式碼使用find
和rfind
方法找到文字中實際內容的起始和結束位置,並對raw
進行切片操作,保留需要的部分。這樣可以去除不必要的頁首和頁尾資訊。
處理HTML內容
許多網頁內容是以HTML格式存在的,可以使用Python直接讀取和處理。
使用NLTK清理HTML內容
>>> url = "http://news.bbc.co.uk/2/hi/health/2284783.stm"
>>> html = urlopen(url).read().decode('utf-8')
>>> raw = nltk.clean_html(html)
>>> tokens = nltk.word_tokenize(raw)
>>> tokens = tokens[96:399]
>>> text = nltk.Text(tokens)
>>> text.concordance('gene')
they say too few people now carry the gene for blondes to last beyond the next tw
t blonde hair is caused by a recessive gene . In order for a child to have blonde
to have blonde hair , it must have the gene on both sides of the family in the gra
there is a disadvantage of having that gene or by chance . They don ' t disappear
ondes would disappear is if having the gene was a disadvantage and I do not think
內容解密:
這段程式碼首先讀取一個BBC的新聞網頁,然後使用NLTK的clean_html
函式清理HTML標籤,得到純文字內容。接著對文字進行分詞處理,並建立NLTK的Text
物件,最後進行關鍵字的上下文分析。
更複雜的HTML處理
對於更複雜的HTML處理,可以使用Beautiful Soup套件,網址為http://www.crummy.com/software/BeautifulSoup/。
處理搜尋引擎結果
網頁可以視為一個巨大的未註解語料函式庫。搜尋引擎提供了一個高效的方式來搜尋相關的語言範例。使用搜尋引擎的主要優勢是其龐大的資料量,能夠找到更多的語言模式例項。此外,搜尋引擎非常容易使用,因此是快速驗證理論是否合理的便捷工具。具體範例如表3-1所示。
搜尋引擎的使用優勢:
- 資料量龐大,能夠找到更多的語言模式例項。
- 使用非常方便,是快速驗證理論的便捷工具。
從網路與本機存取文字資料
網路文字資料的存取挑戰
現代自然語言處理(NLP)工作經常需要從網路上取得大量文字資料。然而,使用搜尋引擎取得片語統計資料存在諸多限制。
使用搜尋引擎的限制
- 搜尋模式受限:無法像在本機語料函式庫那樣使用程式搜尋複雜模式
- 結果不一致:不同時間或地區的搜尋結果可能大不相同
- 重複內容影響:重複釋出的內容可能誇大搜尋結果
- 結果標記變化:搜尋引擎傳回結果的標記可能不可預測地變化
# 搜尋引擎結果範例(模擬資料)
collocations = {
"absolutely": {"adore": 289000, "love": 905000, "like": 16200, "prefer": 644},
"definitely": {"adore": 1460, "love": 51000, "like": 158000, "prefer": 62600}
}
ratio = {
"absolutely": {"adore": 198, "love": 18, "like": 0.1, "prefer": 0.01},
"definitely": {"adore": 1, "love": 1, "like": 10, "prefer": 97}
}
分析搜尋結果
透過分析「absolutely」和「definitely」與不同動詞的搭配比率,我們可以觀察到有趣的語言現象。例如:「absolutely adore」的比例遠高於「definitely adore」。
處理RSS饋流資料
使用Universal Feed Parser函式庫
透過第三方Python函式庫Universal Feed Parser,我們可以輕鬆存取部落格內容。
import feedparser
# 解析Language Log的RSS饋流
llog = feedparser.parse("http://languagelog.ldc.upenn.edu/nll/?feed=atom")
print(llog['feed']['title']) # 輸出:Language Log
print(len(llog.entries)) # 輸出:15
# 處理單篇文章
post = llog.entries[2]
content = post.content[0].value
clean_content = nltk.word_tokenize(nltk.html_clean(content))
print(clean_content[:10]) # 輸出前10個詞元
內容解讀:
- 使用
feedparser.parse()
解析RSS饋流 llog['feed']['title']
取得饋流標題len(llog.entries)
取得文章數量- 使用
nltk.html_clean()
清理HTML標籤 - 使用
nltk.word_tokenize()
進行詞元切分
讀取本機檔案
基本檔案讀取操作
Python內建的open()
函式用於開啟本機檔案。
# 開啟檔案
f = open('document.txt', 'rU')
raw = f.read()
print(raw) # 輸出檔案內容
# 按行讀取檔案
for line in f:
print(line.strip()) # 輸出每一行內容
常見問題與解決方案
檔案未找到錯誤:檢查當前工作目錄或使用絕對路徑
import os print(os.listdir('.')) # 列出當前目錄下的檔案
換行符號問題:使用
'rU'
模式開啟檔案以相容不同作業系統的換行符號
從二進位格式中擷取文字
處理PDF和MSWord檔案
對於PDF和MSWord等二進位格式,需要使用專門的函式庫如pypdf
和pywin32
。
實用轉換方法
- 使用應用程式開啟檔案並另存為純文字格式
- 將檔案的URL輸入Google搜尋框,通常可以找到HTML版本
捕捉使用者輸入
使用raw_input()
函式
可以捕捉使用者在程式執行時的輸入內容。
s = raw_input("請輸入一些文字:")
print("您輸入了", len(nltk.word_tokenize(s)), "個詞元。")
內容解讀:
- 使用
raw_input()
提示使用者輸入文字 - 使用
nltk.word_tokenize()
對輸入文字進行詞元切分 - 輸出詞元數量