Python網路爬蟲與資訊提取-Day9-資訊標記與提取方法
一、資訊標記的三種形式
我們需要對資訊進行表記,使得我們能夠理解資訊所反饋的真實含義。
標記後的資訊可形成資訊組織結構,增加了資訊維度
標記的結構與資訊一樣具有重要價值
標記後的資訊可用於通訊、儲存或展示
標記後的資訊更利於程式理解和運用,也利於人對資訊的深入理解與運用
HTML的資訊標記
HTML是WWW(World Wide Web)的資訊組織方式
它能夠將聲音、影象、視訊等超文字資訊嵌入到文字中
HTML通過預定義的<>…</>標籤形式組織不同型別的資訊
現在國際公認的資訊標記格式有三種,分別是XML,JSON和YAML
XML(eXtensible Markup Language
<img src=“china.jpg” size=“10”> … </img>
它有名稱 Name和屬性Attribute
如果標籤中沒有內容,我們可以用相關的縮寫形式,用一個尖括號來表示一個標籤。
<img src=“china.jpg” size=“10” />空元素的縮寫形式
在XML中也可以嵌入註釋,它以<!開頭,並且以>結尾
<!‐‐ This is a comment, very useful ‐‐>註釋書寫形式
可以說XML是HTML
JSON(JavsScript Object Notation),它是JavaScript語言中面向物件的一種語言形式,簡單講JSON是一種有型別的鍵值對構建的資訊表達方式。鍵值對是key:value的一個組合,也就是給出一個資訊,並且對資訊內容做一個定義。其中對資訊型別的定義叫“鍵”,對資訊值的描述叫value。
要注意,無論是鍵還是值,它都通過增加雙引號來表示它是字串。說明它是一個有資料型別的鍵值對。
如果一個鍵對應多個值的時候,我們使用方括號加逗號[,]的形式來組織
鍵值對可以巢狀使用,也就是一個鍵值對放在另一個鍵值對的值的部分,在巢狀使用時,我們用大括號來表示
總結:JSON用有型別的鍵值把資訊組織起來
“key” : “value”
“key” : [“value1”, “value2”]
“key” : {“subkey” : “subvalue”}
JSON語言使用有型別的鍵值對,一個很大好處就是對於JavaScript等程式語言來說可以直接將JSON格式變為程式的一部分,使得編寫程式大大地簡化
YAML(YAML Ain’t Markup Language),它在命名的時候使用一種遞迴的定義。它也使用鍵值對,不過是無型別鍵值對key:value。可以用縮排來表達所屬的關係,用減號表達並列關係,用豎線表達整塊資料,用#表示註釋
key : value
key : #Comment
‐value1
‐value2
key :
subkey : subvalue
三種資訊標記形式的比較
XML例項:
<person>
<firstName>Tian</firstName>
<lastName>Song</lastName>
<address>
<streetAddr>中關村南大街5號</streetAddr>
<city>北京市</city>
<zipcode>100081</zipcode>
</address>
<prof>Computer System</prof><prof>Security</prof>
</person>
每一個資訊域定義相關的標籤,並且用巢狀的形式組織起來
在整個文字中,有效資訊所佔的比例並不高,大多數資訊被標籤佔用
JSON例項:
{
“firstName” :“Tian” ,
“lastName” :“Song” ,
“address” : {
“streetAddr” :“中關村南大街5號” ,
“city” :“北京市” ,
“zipcode” :“100081”
} ,
“prof” : [ “Computer System” ,“Security” ]
}
JSON使用鍵值對的形式組織資訊,但是無論標籤還是後面的值,鍵值都要用雙引號來表達它們的型別
YAML例項:
firstName : Tian
lastName : Song
address :
streetAddr : 中關村南大街5號
city : 北京市
zipcode : 100081
prof :
‐Computer System
‐Security
用無型別的鍵值對來表示,很簡潔的關聯
XML:最早的通用資訊標記語言,可擴充套件性好,但繁瑣
JSON:資訊有型別,適合程式處理(js),較XML簡潔
YAML:資訊無型別,文字資訊比例最高,可讀性好
實際使用中:
XML:Internet上的資訊互動與傳遞
JSON:移動應用雲端和節點的資訊通訊,無註釋
YAML:各類系統的配置檔案,有註釋易讀
二、資訊提取的一般方式
資訊提取指,從標記後的資訊中提取所關注的內容。之前的XML,JSON,YAML的三種形式,無論哪種形式,在資訊提取中,包含標記,和資訊兩部分,我們關心的是所要提取出的內容
·方法一:完整解析資訊的標記形式,再提取關鍵資訊
用標記解析器去解析XML JSON YAML格式,然後將其中所需要的資訊提取出來
例如:bs4庫的標籤樹遍歷
優點:資訊解析準確
缺點:提取過程繁瑣,速度慢
·方法二:無視標記形式,直接搜尋關鍵資訊
對資訊的文字查詢函式即可
優點:提取過程簡潔,速度較快
缺點:提取結果準確性與資訊內容相關
·融合方法:結合形式解析與搜尋方法,提取關鍵資訊
XML JSON YAML 搜尋
需要標記解析器及文字查詢函式
例項:
提取HTML中所有URL連結
思路: 1) 搜尋到所有<a>標籤
2) 解析<a>標籤格式,提取href後的連結內容
import requests
r = requests.get("http://python123.io/ws/demo.html")
demo = r.text
from bs4 import BeautifulSoup
soup = BeautifulSoup(demo,"html.parser")
for link in soup.find_all('a'):
print(link.get('href'))
http://www.icourse163.org/course/BIT-268001
http://www.icourse163.org/course/BIT-1001870001
三、基於bs4庫的HTML內容查詢方法
import requests
r = requests.get(“http://python123.io/ws/demo.html”)
demo = r.text
<>.find_all(name, attrs, recursive, string, **kwargs)
find_all方法可以在soup的變數中查詢裡面的資訊
它能夠返回一個列表型別,儲存查詢的結果
第一個引數name:對標籤名稱的檢索字串
from bs4 import BeautifulSoup
soup = BeautifulSoup(demo,"html.parser")
print(soup.find_all("a"))
[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>, <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>]
如果想要同時得到a和b,則用一個方括號
print(soup.find_all(["a","b"]))
[<b>The demo python introduces several python courses.</b>, <a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>, <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>]
如果給出的標籤名稱是True,則顯示當前標籤的所有資訊
for tag in soup.find_all(True):
print(tag.name)
html
head
title
body
p
b
p
a
a
我們看到這個文件中的所有標籤名稱被列印了出來
希望只顯示其中以b開頭的標籤,包括b和body標籤,就需要使用一個新的第三方庫,叫做“正則表示式庫”
首先引入這個庫
正則表示式反饋的結果是以b開頭的所有表達的資訊
import re
for tag in soup.find_all(re.compile('b')):
print(tag.name)
body
b
attrs: 對標籤屬性值的檢索字串,可標註屬性檢索
我們查詢p標籤中中包含course字串的資訊
print(soup.find_all('p','course'))
[<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a> and <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>.</p>]
我們也可以對屬性值作約定
print(soup.find_all(id='link1'))
[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>]
print(soup.find_all(id='link'))
[]
所以我們對屬性賦值要做精確的賦值
如果我們需要查詢包含link的屬性,我們就需要引入正則表示式庫
print(soup.find_all(id=re.compile('link')))
[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>, <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>]
正則表示式就像平常搜尋一樣搜尋詞的一部分,如果不使用正則表示式就需要完整準確地給出詞的資訊,不多也不少
recursive: 是否對子孫全部檢索,預設True
如果我們只需要搜尋兒子這一層面的資訊,我們就把recursive設為False
print(soup.find_all('a',recursive=False))
[]
string: <>…</>中字串區域的檢索字串
print(soup.find_all(string='Basic Python'))
['Basic Python']
print(soup.find_all(string=re.compile('python')))
['This is a python demo page', 'The demo python introduces several python courses.']
<tag>(..) 等價於 <tag>.find_all(..)
soup(..) 等價於 soup.find_all(..)
拓展方法
方法 |
說明 |
<>.find() |
搜尋且只返回一個結果,同.find_all()引數 |
<>.find_parents() |
在先輩節點中搜索,返回列表型別,同.find_all()引數 |
<>.find_parent() |
在先輩節點中返回一個結果,同.find()引數 |
<>.find_next_siblings() |
在後續平行節點中搜索,返回列表型別,同.find_all()引數 |
<>.find_next_sibling() |
在後續平行節點中返回一個結果,同.find()引數 |
<>.find_previous_siblings() |
在前序平行節點中搜索,返回列表型別,同.find_all()引數 |
<>.find_previous_sibling() |
在前序平行節點中返回一個結果,同.find()引數 |
區別僅在於查詢區域的不同以及檢索返回的結果個數不同