#34;VBA信息獲取與處理"教程中第八個專題"VBA與HTML文檔"的第七節"HTML DOM的對象事件及關聯"太枯燥了,希望想掌握這方面知識的朋友能參考我的教程學習。我們今天 開始第九個專題的學習"利用IE抓取網絡數據"。
我們的網抓部分在講解了XMLHTTP方法后,利用兩個專題的進度進行了一些和VBA關系不是很大的有關網絡知識的講解,這兩個專題對于我們重新認識網抓數據有著非常重要的意義,雖然我的講解還不能面面俱到,但對于我經常倡導的VBA定位來說,是足夠的,再者,學習是個不斷積累前進的過程,要掌握的是一些基本的理論,然后把這些應用到自己的實際中去,這才是關鍵。從這個專題開始我們繼續網抓的學習。這個專題是利用IE抓取網絡數據。其實就是利用控件來完成我們的工作。
為了獲取網頁的數據,我們可以通過創建IE控件或webbrowser控件,結合htmlfile對象的方法和屬性,模擬瀏覽器操作,獲取瀏覽器頁面的數據。
這種方法可以模擬大部分的瀏覽器操作。瀏覽器能看到的數據就能用代碼獲取,但是有個致命的缺點:除去各種彈窗相當煩人外,兼容性也確實是個很傷腦筋的問題。在我自己的實踐中感覺這種方法不是很穩定(僅僅是感覺)。
我們在實際工作中遇到網站和網頁相關問題,例如:如何下載網頁數據?網頁之間的通訊是怎么實現的、它們能不能被控制等等。如果你是用VB/VBA/腳本或其它支持自動化對象(AUTOMATION)的語言編程,有一個值得了解的方法是掌握對象模型:將網頁視為對象來控制,這個方法需要了解的是IE的自動化對象(InternetExplorer.Application)或IE控件(Microsoft Internet Controls),以及標準的文檔對象模型(Document)。相關的知識我在前兩個專題中做了大量的講解,這里就不再詳細的說明了。
我給出下面的代碼:
Set ie = CreateObject("InternetExplorer.Application") '創建對象
ie.Visible = True '使IE頁面可見,做完這一步,在VBA之外可以看到一個新的IE
ie.navigate "about:blank" '建立一個空白頁
上面這幾行代碼的作用是創建一個IE應用程序對象,并打開一個空白的網頁。這個網頁獨立于VBA的應用程序(WORD或EXCEL)之外,事實上,你必須自已關掉它,或者用ie.Quit下令退出——注意一下,單純的關閉VBA或SET ie=nothing是不會退出這個網頁的。我們經常用的是將第3行的字符串替換成一個網站的名字,或者替換成一個你主機中的文檔名,也可以是一個圖片名,都是可以的。和你在IE地址欄輸入名稱瀏覽這些文檔是一樣效果。
如果僅僅是創建了一個空的模型是沒有任何利用的價值的,我們需要真正的網頁,這時就需要我們在VBA的應用程序外打開一個完整的網頁了,直到網頁完全加載我們的操作才能向下進行。
我們修正一下上面的那段打開空網頁的代碼:
Sub mynz()
Set ie = CreateObject("InternetExplorer.Application") '創建對象
ie.Visible = True '使IE頁面可見,做完這一步,在VBA之外可以看到一個新的IE
ie.navigate " https://baijiahao.baidu.com" '建立一個空白頁
Do Until .ReadyState = 4 '檢查網頁是否加載完畢(4表示完全加載)
DoEvents '循環中交回工作權限給系統,以免"軟死機"
Loop
End sub
在上面的代碼中增加了幾行:
Do Until .ReadyState = 4 '檢查網頁是否加載完畢(4表示完全加載)
DoEvents '循環中交回工作權限給系統,以免"軟死機"
Loop
這幾行代碼可以保證網頁的加載完成,這是根據ie.ReadyState的返回值來判斷的。
readyState一共有5中狀態:
狀態 含義 說明
0 未初始化 對象已建立,但是尚未初始化(尚未調用open方法)
1 初始化 對象已建立,尚未調用send方法
2 發送數據 send()方法已調用,但是當前的狀態及http頭未知
3 數據傳送中 已接收部分數據,因為響應及http頭不全,這時通過responseBody和responseText獲取部分數據會出現錯誤
4 數據接收完畢 此時可以通過通過responseBody和responseText獲取完整的回應數據
通過以上的分析,我們可以看出,只用當.ReadyState = 4時網頁的數據才是有效的數據。
當網頁加載完畢,剩下的工作就是從網頁中抓取數據了,數據的抓取主要是利用控件對象的屬性和方法。
1)用Set doc = ie.Document 取得網頁的文檔對象
從文檔對象(Document)以下展開的對象模型,它代表網頁的內容,和前面那個IE的應用程序不是同一個體系.
Documnet(文檔)是文檔對象模型,相當于OFFICE對象中的APPLICATION,取得Document之后,不論修改網頁還是讀寫網頁,還是觸發事件,一切都好說,每個URL都對應有一個Documnet(這是假如定成功導航Navigate到那個URL完成,因此之前要求確定IE對象READSTATE,以確定對應URL的Document打開了)
2) 在Documnet之下可以取得documentElement和body兩個節點。
可以用下面的語句:
set xbody=doc.Body '取得body對象
set xDoc=doc. documentElement '取得根節點
body前面已經說過,相當于標記的對象,根節點相當于網頁中的標記元素的對象,MHTML的類型庫定義里,它們都屬于HTMLHtmlElement類型的對象,下面我把這種類型的對象稱為一個"節點",不過要注意的是文檔對象不是節點對象,它是HTMLDocument類型。根節點和body節點不同的是根節點包括整個網頁,在HTML的文檔對象模型中,這類對象有幾種屬性可以取得其中的內容:
對象.innerHtml '對象內部的HTML文本
對象.OuterHtml '對象中的HTML文本,包括對象本身的HTML標記在內
對象.innerText '對象內部的TEXT,不包括HTML標記
對象.OuterText '同上,包括對象本身的文本
所以,如果我們要抓取某個網站的所有HTML內容,代碼可以這樣寫:
set doc=ie.Document
set xDoc=doc. documentElement '取得根節點
strX=xDoc.OuterHtml '取得所有的HTML內容
3) 每一個標記節點對象之下都有一個名為ChildNodes的集合,它包含了"直屬于本節點下的標記",就象是文件目錄,根目錄下的子目錄.
我們可以看到:HTML標記是文檔的根節點,是Document的Childnodes集合中的一個成員(Document不是節點,是另一種類型對象,上一級文檔,但它可以有下級節點集合,正如磁盤可以有下級目錄,但它本身不是目錄),BODY是根節點的ChildNodes集合中的一個成員,而DIV和P兩個節點則是BODY的ChildNodes集合中的兩個成員,同樣也有自已的Childnoes集合。
我們要注意:文檔對象模型中,集合與OFFICE的集合有所不同,集合是從0開始計數的,計數屬性是Length而不是Count。
4)除了ChildNodes集合,大家在網頁文檔對象中還常見到的就是很大氣的一種集合:All集合,這是"最糊涂"的一種集合,文檔和各級節點都帶有這個集合,正如這個名字所示,它是不分層次的,但用起來也很方便:
Set doc=ie.Document
Set xCols=doc.All '取得文檔中的所有節點集合
Set xbCols=doc.body.All '取得body節點下所有的節點集合
雖然任何標記節點都有ALL集合,但我們還是喜歡用DOCUMENT的ALL,原因無它,文檔最大,一鍋燴的ALL找起來也最合適。ALL查找是有條件的:如果這個標記沒有ID,你無法查到它的名字。
不過,ALL集合有一個很方便的特性:ID可以掛到ALL集合之下:
strX=doc.All.mytag.innerhtml
5)獲得文檔對象的getElementsByName集合,可以利用下面的方法:
set mydivs=doc. getElementsByName("div") '取得所有DIV標記,注意還是集合
6) 文檔對象的FORMS集合,因為大部分網頁的數據提交都是通過FORM標記提交的:
Set myForms=doc.Forms '取得所有的FORM標記
Set frmX=myForms.item(0) '第1個FORM
FORM標記節點代表的對象是很多朋友關心的內容——在網頁對象中,它可以發送數據到服務器,使服務器刷新網頁(實際上是服務器按某個格式約定發回數據),我們可以把網頁的FORM看成是一個遠程的函數調用接口,FORM標記中的ACTION指向的URL地址就是函數入口,而FORM標記內的各個INPUT標記節點就是函數的參數,當發出FORM.Submit方法時,就是遠程調用函數了,在服務器端,諸如ASP,PHP就是老老實實找FORM的參數,不管你是用GET還是POST:
frmX.submit '相當于用戶在頁面上按下FORM的發送按鍵
上面我羅列了獲取網頁數據的一般的方法,并沒有什么特別的使用要求,大家可以根據自己的習慣來利用,這個專題之后的內容就是靈活運用這些知識點來解決實際問題了。
本節知識點回向:
如何提交表單?如何下載圖片的地址?如何獲得表的數據?
在我的系列書籍中一直在強調"搭積木"的編程思路,這也是學習利用VBA的主要方法,特別是職場人員,更是要采用這種方案。其主要的內涵:
1 代碼不要自己全部的錄入。你要做的是把積木放在合適的位置然后去修正代碼,一定要拷貝,從你的積木庫中去拷貝,然后修正代碼,把時間利用到高效的思考上。
2 建立自己的"積木庫"。平時在學習過程中,把自己認為有用的代碼放在一起,多積累,在用到的時候,可以隨時拿來。你的積木庫資料越多,你做程序的思路就會越廣。
VBA是利用Office實現個人小型辦公自動化的有效手段(工具)。這是我對VBA的應用界定。在取代OFFICE新的辦公軟件沒有到來之前,誰能在數據處理方面做到極致,誰就是王者。其中登峰至極的技能非VBA莫屬!
我記得20年前自己初學VBA時,那時的資料甚少,只能看源碼自己琢磨,真的很難。20年過去了,為了不讓學習VBA的朋友重復我之前的經歷,我根據自己多年VBA實際利用經驗,推出了六部VBA專門教程:
第一套:VBA代碼解決方案 是VBA中各個知識點的講解,教程共147講,覆蓋絕大多數的VBA知識點,初學必備;
第二套:VBA數據庫解決方案 數據庫是數據處理的專業利器,教程中詳細介紹了利用ADO連接ACCDB和EXCEL的方法和實例操作,適合中級人員的學習。
第三套:VBA數組與字典解決方案 數組和字典是VBA的精華,字典是VBA代碼水平提高的有效手段,值得深入的學習,是初級及中級人員代碼精進的手段。
第四套:VBA代碼解決方案之視頻 是專門面向初學者的視頻講解,可以快速入門,更快的掌握這門技能。這套教程是第一套教程的視頻講解,聽元音更易接受。
第五套:VBA中類的解讀和利用 這是一部高級教程,講解類的虛無與肉身的度化,類的利用雖然較少,但仔細的學習可以促進自己VBA理論的提高。這套教程的領會主要是讀者的領悟了,領悟一種佛學的哲理。
第六套教程:《VBA信息獲取與處理》,這是一部高級教程,涉及范圍更廣,實用性更強,面向中高級人員。教程共二十個專題,包括:跨應用程序信息獲得、隨機信息的利用、電子郵件的發送、VBA互聯網數據抓取、VBA延時操作,剪切板應用、Split函數擴展、工作表信息與其他應用交互,FSO對象的利用、工作表及文件夾信息的獲取、圖形信息的獲取以及定制工作表信息函數等等內容。
大家可以根據以上資料1→3→2→6→5或者是4→3→2→6→5的順序逐漸深入的逐漸學習。教程提供講解的同時提供了大量的積木,如需要可以WeChat: NZ9668
如太白詩云:眾鳥高飛盡,孤云獨去閑。相看兩不厭,只有敬亭山。學習的過程也是修心的過程,修一個平靜的心。在代碼的世界中,心平靜了,心情好了,身體自然而然就好。心靜則正,內心里沒有那么多邪知邪見,也就沒有那么多妄想。利人就是利己。這些教程也是為幫助大家起航,助上我自己之力,我的上述教程是我多的經驗的傳遞,
"水善利萬物而不爭",綿綿密密,微則無聲,巨則洶涌。學習亦如此,知道什么是自己所需要的,不要蜷縮在一小塊自認為天堂的世界里,待到暮年時再去做自欺欺人的言論。要努力提高自己,用一顆充滿生機的心靈,把握現在,這才是進取。越是有意義的事情,困難會越多。愿力決定始終,智慧決定成敗。不管遇到什么,都是風景。看淡紛爭,看輕得失。茶,滿也好,少也好,不要計較;濃也好,淡也好,其中自有值得品的味道。去感悟真實的時間,靜下心,多學習,積累福報。而不是天天混日子,也不是天天熬日子。在后疫情更加嚴峻的存量殘殺世界中,為自己的生存進行知識的儲備,特別是新知識的儲備。學習時微而無聲,利用時則巨則洶涌。
每一分收獲都是成長的記錄,怎無憑,正是這種執著,成就了朝霞的燦爛。最后將一闕詞送給致力于VBA學習的朋友,讓大家感受一下學習過程的枯燥與執著:
浮云掠過,暗語無聲,
唯有清風,驚了夢中啼鶯。
望星,疏移北斗,
奈將往事雁同行。
阡陌人,昏燈明暗,
忍顧長亭。
多少VBA人,
暗夜中,悄聲尋夢,盼卻天明。
怎無憑!
回向學習利用VBA的歷歷往事,不勝感慨,謹以這些文字給大家,分享我多年工作實際經驗的成果,隨喜這些有用的東西,給確實需要利用VBA的同路人。
分享成果,隨喜正能量
要使用sed、awk、grep等工具進行嘗試(這會導致不可預期的結果)。在許多情況下,你最好選擇使用支持XML數據的編程語言進行處理。如果必須使用shell腳本,有一些專門用于解析HTML和XML文件的工具可供使用。
你可能知道Lynx是一個帶有極限限制的終端模式Web瀏覽器。確實如此,但它也是一個可編程的HTML解析器。它特別擅長從文檔中提取鏈接并將其打印出來:
如果你想要包括圖像鏈接,請添加-image_links選項。現在,根據你的需求過濾鏈接應該相對簡單,因為每個鏈接都在單獨的一行上,沒有HTML標簽的干擾。
$ lynx -dump -listonly -nonumbers http://mywiki.wooledge.org/
http://mywiki.wooledge.org/EnglishFrontPage?action=rss_rc&unique=1&ddiffs=1
http://mywiki.wooledge.org/EnglishFrontPage?action=edit
http://mywiki.wooledge.org/EnglishFrontPage
http://mywiki.wooledge.org/EnglishFrontPage?action=raw
http://mywiki.wooledge.org/EnglishFrontPage?action=print
http://mywiki.wooledge.org/EnglishFrontPage?action=AttachFile&do=view&target=Greg's-wiki.zip
[...]
你可能會認為wget在這方面也很好用,對吧?我的意思是,它有遞歸鏡像模式,所以顯然內部做了這種操作。祝你好運,試圖找到一種方法讓wget將URL打印出來而不是下載全部文件。
我試著嘗試了一下,找到了一種方法。沒有經過充分測試。我們可以使用--rejected-log和始終匹配的--reject-regex參數。我們使用--spider選項以不保存文件的方式執行。
$ wget -q --spider -r --rejected-log=rejected --reject-regex=^ http://mywiki.wooledge.org/
$ cat rejected
REASON U_URL U_SCHEME U_HOST U_PORT U_PATH U_PARAMS U_QUERY U_FRAGMENT P_URL P_SCHEME P_HOST P_PORT P_PATH P_PARAMS P_QUERY P_FRAGMENT
REGEX http%3A//mywiki.wooledge.org/moin_static198/common/js/common.js SCHEME_HTTP mywiki.wooledge.org 80 moin_static198/common/js/common.js http%3A//mywiki.wooledge.org/ SCHEME_HTTP mywiki.wooledge.org 80
REGEX http%3A//mywiki.wooledge.org/moin_static198/modernized/css/common.css SCHEME_HTTP mywiki.wooledge.org 80 moin_static198/modernized/css/common.css http%3A//mywiki.wooledge.org/ SCHEME_HTTP mywiki.wooledge.org 80
REGEX http%3A//mywiki.wooledge.org/moin_static198/modernized/css/screen.css SCHEME_HTTP mywiki.wooledge.org 80 moin_static198/modernized/css/screen.css http%3A//mywiki.wooledge.org/ SCHEME_HTTP mywiki.wooledge.org 80
REGEX http%3A//mywiki.wooledge.org/moin_static198/modernized/css/print.css SCHEME_HTTP mywiki.wooledge.org 80 moin_static198/modernized/css/print.css http%3A//mywiki.wooledge.org/ SCHEME_HTTP mywiki.wooledge.org 80
REGEX http%3A//mywiki.wooledge.org/moin_static198/modernized/css/projection.css SCHEME_HTTP mywiki.wooledge.org 80 moin_static198/modernized/css/projection.css http%3A//mywiki.wooledge.org/ SCHEME_HTTP mywiki.wooledge.org 80
[...]
要將鏈接提取到標準輸出中:
$ wget -q --spider -r --rejected-log=/dev/stdout --reject-regex=^ http://mywiki.wooledge.org/ | tail -n +2 | cut -f 2
http%3A//mywiki.wooledge.org/moin_static198/common/js/common.js
http%3A//mywiki.wooledge.org/moin_static198/modernized/css/common.css
http%3A//mywiki.wooledge.org/moin_static198/modernized/css/screen.css
http%3A//mywiki.wooledge.org/moin_static198/modernized/css/print.css
http%3A//mywiki.wooledge.org/moin_static198/modernized/css/projection.css
[...]
xmllint是處理大多數XML的最佳選擇。不幸的是,使用它需要學習XPath,而我并不知道任何合理的XPath入門教程。以下是一些簡單的技巧。它們是使用以下輸入文件演示的:
<staff>
<person name="bob"><salary>70000</salary></person>
<person name="sue"><salary>90000</salary></person>
</staff>
請注意,xmllint在輸出中不添加換行符。如果你用CommandSubstitution進行捕獲,這不是問題。但如果你在交互式shell中測試,這將很快變得很煩人。你可以考慮編寫一個包裝函數,例如:
xmllint() { command xmllint "$@"; echo; }
簡單技巧:
$ xmllint --xpath 'string(//salary)' foo.xml
70000
$ xmllint --xpath '//salary/text()' foo.xml
7000090000
$ xmllint --xpath 'count(//person)' foo.xml
2
$ xmllint --xpath '//person[1]/salary/text()' foo.xml
70000
$ xmllint --xpath '//person[2]/salary/text()' foo.xml
90000
$ xmllint --xpath '//person[@name="bob"]/salary/text()' foo.xml
70000
$ xmllint --xpath 'string(//person[2]/@name)' foo.xml
sue
上述示例顯示,當你擁有一個不錯的XML解析器時,解析XML是相當容易的,但這違背了XML的目的,即讓每個人都感到痛苦。因此,一些聰明人引入了XML命名空間。
一個典型的maven構建文件(稱為pom.xml)就是這樣的例子,大致如下:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.codehaus.mojo</groupId>
<artifactId>my-project</artifactId>
<version>1.0-SNAPSHOT</version>
</project>
通常還會有幾百行用于依賴項,但我們來保持簡潔。
根據前一章的示例,我們知道從該文件中提取版本只需使用xpath /project/version/text():
$ xmllint --xpath '/project/version/text()' pom.xml
XPath set is empty
嗯,不是這樣的,因為作者聰明地為這個xmlns="http://maven.apache.org/POM/4.0.0"添加了一個默認命名空間,所以現在你首先必須指定確切的URL,然后才能指明要獲取的版本元素內部的文本。
xmllint的--xpath選項沒有辦法指定命名空間,所以它現在無法使用(除非你編輯文件并刪除命名空間聲明)。但其shell功能確實允許設置命名空間。
xmllint --shell pom.xml << EOF
setns ns=http://maven.apache.org/POM/4.0.0
cat /ns:project/ns:version/text()
EOF
/ > / > -------
1.0-SNAPSHOT
/ >
耶!我們得到了版本號...外加一些來自xmllint shell的提示和廢話,之后必須將其刪除。
xmlstarlet對于這個任務來說稍微容易一些
$ xmlstarlet sel -N ns=http://maven.apache.org/POM/4.0.0 -t -v /ns:project/ns:version -n pom.xml
1.0-SNAPSHOT
Python也附帶了一個XML解析器,通常比xmllint和xmlstarlet更常用。它也可以以一種笨拙的方式處理命名空間。
$ python -c 'import xml.etree.ElementTree as ET;print(ET.parse("pom.xml").find("{http://maven.apache.org/POM/4.0.0}version").text)'
1.0-SNAPSHOT
xsltproc恰好在大多數Linux系統上安裝。例如提取播客的標題和URL:
xslt() {
cat << 'EOX'
<?xml version="1.0"?>
<x:stylesheet version="1.0" xmlns:x="http://www.w3.org/1999/XSL/Transform">
<x:output method="text" />
<x:template match="/">
<x:for-each select="//item">
<x:text># </x:text>
<x:value-of select="./title/text()" /><x:text>
<!-- newline --></x:text>
<x:value-of select="enclosure/@url" /><x:text>
</x:text>
</x:for-each>
</x:template>
</x:stylesheet>
EOX
}
curl -s http://podcasts.files.bbci.co.uk/p02nq0lx.rss | xsltproc <(xslt) -
如果你想學習如何編寫更加健壯和可靠的 Shell 腳本,減少生產環境中的錯誤和故障,那么關注我吧!我會分享 Shell 編程的最佳實踐和建議,幫助你提高 Shell 腳本的魯棒性和可維護性。如果你想深入了解 Shell 編程的實際應用和技巧,可以關注我的《Shell 腳本編程最佳實踐》專欄,里面有我在一線互聯網大廠的實際生產經驗和最佳實踐,幫助你高效完成各種自動化任務。
讀:本文的目標是介紹一些Python庫,幫助你從類似于PDF和Word DOCX 這樣的二進制文件中提取數據。我們也將了解和學習如何從網絡信息源(web feeds)(如RSS)中獲取數據,以及利用一個庫幫助解析HTML文本并從文檔中提取原始文本。
我們還將學習如何從不同來源提取原始文本,對其進行規范化,并基于它創建一個用戶定義的語料庫。
在本文中,你將學習7個不同的實例。我們將學習從PDF文件、Word文檔和Web中獲取數據。PDF和Word文檔是二進制文件,通過Web,你將獲得HTML格式的數據,因此,我們也會對數據執行規范化和原始文本轉換任務。
作者:克里希納·巴夫薩、納雷什·庫馬爾、普拉塔普·丹蒂
如需轉載請聯系大數據(ID:hzdashuju)
作為一名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對象,并返回連接后的對象。運行這兩行代碼后,你得到的輸出如下:
<class 'str'> : Tuffy;Ali;Nysha;Tim
(4)接下來,我們來看split方法的功能:
wordList = sentence.split(' ') print((type(wordList)), ':', wordList)
當split函數調用一個字符串時,它會將其內容分割為多個str對象,創建一個包含這些字符串對象的列表,并返回該列表。該函數接受單個str對象作為參數,表示分隔符。運行代碼,得到如下輸出:
<class 'list'> : ['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允許的一些常見和不常見的字符串操作。接下來,我們將在以上操作基礎上繼續學習一些字符串操作。
接下來,我們將了解子字符串、字符串替換以及如何訪問一個字符串的所有字符。
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開始到列表末尾的子列表。
這個實例是從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錯誤。
這里,我們將學習如何加載和讀取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對象。
現在我們要創建自己的語料庫,而不是使用從互聯網上得到的語料庫。
1. 準備工作
在準備方面,我們將使用本文第一個實例中提到的Dropbox文件夾中的幾個文件。如果你已經從那個文件夾中下載了全部的文件,那么你已經完成了準備工作。否則,請從
https://www.dropbox.com/sh/bk18dizhsu1p534/AABEuJw4TArUbzJf4Aa8gp5Wa?dl=0
下載如下文件:
如果你沒有按照本文的順序來完成實例,那么你需要先回頭看看本文的前兩個實例。我們將用到本文前兩個實例中完成的兩個模塊 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)
(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文件中所有段落組成的列表,其中每個段落對象又是由該段落中的句子組成的列表。從中可以發現,這些段落和句子保留了很多原有的結構。
豐富網站摘要(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 : <img alt="" src="http://www.jungjaehyung.com/uploadfile/2024/0806/20240806104718722.jpg" /><div style="float: right; width: 50px;"><a 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;"> <p>The national space agency threw shade the best way it knows how: by blocking the sun. Yep, you read that right. </p> <div><div><blockquote> <p>HA HA HA I've blocked the Sun! Make way for the Moon<a >#Solar Eclipse2017</a> <a >pic.twitter.com/nZCoqBlSTe</a></p> <p>— NASA Moon (@NASAMoon) <a >Augus t 21, 2017</a></p> </blockquote></div></div>
3. 工作原理
互聯網上大多數的RSS信息源都以時間順序排列,將最新的帖子放到最上面。因此,在該實例中我們每次訪問的都是信息源提供的最新內容。信息源本身是不斷更新的。所以,每次運行程序時,輸出的格式保持不變,但是輸出的內容卻可能發生改變,這取決于信息源更新的速度。
另外,我們在控制臺直接輸出原始的HTML文本而不是其文本內容。接下來,我們將解析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 <title> tag :', end=' ') print(soup.title)
soup.title將返回文件中的第一個標題(title)標簽。以上代碼的輸出如下所示:
Accessing the <title> tag : <title>Sample Web Page</title>
(5)現在,我們需要某個HTML標簽的文本內容。通過以下代碼獲取<h1>標簽的內容:
print('Accessing the text of <H1> tag :', end=' ') print(soup.h1.string)
soup.h1.string命令將返回以<h1>標簽開頭的文本。以上代碼的輸出如下所示:
Accessing the text of <H1> tag : Main heading
(6)訪問標簽的屬性。這里,我們將訪問img標簽的alt屬性。添加以下代碼行:
print('Accessing property of <img> tag :', end=' ') print(soup.img['alt'])
通過仔細觀察,你會發現訪問標簽屬性的語法和訪問標簽文本的語法是不同的。運行以上代碼,得到以下輸出:
Accessing property of <img> tag : A Great HTML Resource
(7)最后,一個HTML文件中同一類型的標簽可能多次出現。使用“.”語法僅能獲取文件中第一次出現的標簽。為了獲取所有的標簽,我們將使用find_all()函數,如下所示:
print('\nAccessing all occurences of the <p> tag :') for p in soup.find_all('p'): print(p.string)
在BeautifulSoup對象上調用find_all()函數,參數是標簽名,它將搜索整個HTML樹并返回符合條件的標簽列表。我們使用for循環來遍歷該列表,并將BeautifulSoup對象中所有<p>標簽的內容/文本打印并輸出:
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是一個很方便的庫,可以用于解析任何HTML和XML內容。它支持Python內置的HTML解析器,但是你也可以使用其他第三方的解析器,例如,lxml解析器和純Python的html5lib解析器。
這里,我們使用Python內置的HTML解析器。如果你了解了HTML并會編寫簡單的HTML代碼的話,輸出結果是非常容易理解的。
關于作者:克里希納·巴夫薩(KrishnaBhavsar)花了大約10年時間在各行業領域如酒店業、銀行業、醫療行業等進行自然語言處理、社交媒體分析和文本挖掘方面的研究。他致力于用不同的NLP語料庫如StanfordCoreNLP、IBM的 SystemText和BigInsights、GATE和NLTK來解決與文本分析有關的行業問題。納雷什·庫馬爾(NareshKumar)曾為財富500強企業設計、實施和運行超大型因特網應用程序,在這方面他擁有超過十年的專業經驗。他是一位全棧架構師,在電子商務、網絡托管、醫療、大數據及分析、數據流、廣告和數據庫等領域擁有豐富的實踐經驗。
本文摘編自《自然語言處理Python進階》,經出版方授權發布。
延伸閱讀《自然語言處理Python進階》
推薦語:本書包含的實例可以讓你學會使用NLTK(處理NLP任務的主要Python平臺)完成自然語言處理的各種任務,涵蓋了自然語言理解、自然語言處理和句法分析等。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。