那么我們現(xiàn)在就來講講第一篇老是提到的遍歷文檔樹以及搜索文檔樹
我們就不拿其他例子了,直接用文檔中的例子
from bs4 import BeautifulSoup
html_doc="""
<html><head><title>The Dormouse's story</title></head>
<p class = "title"><b>The Dormouse's story</b></p>
<p class = "story">Once upon a time there?were three little sisters; and their names were
<a class="sister" id="link1">Elsie</a>,
<a class="sister" id="link2">Lacie</a> and
<a class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">....</p>
"""
soup = BeautifulSoup(html_doc)
一個(gè)Tag中可能包含多個(gè)字符串或者其他的Tag,這些都是這個(gè)Tag的子節(jié)點(diǎn)。BeautifulSoup提供了許多操縱和遍歷子節(jié)點(diǎn)的屬性(Beautiful Soup中字符串節(jié)點(diǎn)不支持這些屬性,因?yàn)樽址疀]有子節(jié)點(diǎn))
想要操縱文檔書最簡單的方法就是直接告訴它你要的tag的name例如你想要其中的<head>標(biāo)簽
那么就可以直接soup.head
你也可以多次調(diào)用這個(gè)方法例如
但是通過這個(gè)方法只能獲得當(dāng)前名字的第一個(gè)也就是說只能獲得class = "title"的p標(biāo)簽而不是其他的p標(biāo)簽。如果想要所有的標(biāo)簽?zāi)敲茨憧梢允褂胒ind_all()這個(gè)標(biāo)簽
可以看到返回的是一個(gè)list
tag的.contents屬性可以將tag的子節(jié)點(diǎn)以列表的方式輸出
BeautifulSoup對象一定會有一個(gè)子節(jié)點(diǎn),<html>就是其一個(gè)子節(jié)點(diǎn)。
但是字符串沒有.contents屬性因?yàn)樗鼪]有子節(jié)點(diǎn)。我們也可以通過tag的.children生成器對tag的子節(jié)點(diǎn)進(jìn)行循環(huán)
contents和children屬性僅包含tag的直接子節(jié)點(diǎn)就像<body>直接子節(jié)點(diǎn)<p>而不包括<b>但是<p>節(jié)點(diǎn)又包含<b>,<b>節(jié)點(diǎn)又包含字符串節(jié)點(diǎn),這種情況下就出現(xiàn)了子孫節(jié)點(diǎn)就同上例中我們就可以用.descendants屬性來遍歷子孫節(jié)點(diǎn)
我們再來看一下明顯的區(qū)別
如果tag只有一個(gè)NavigableString類型的子節(jié)點(diǎn)或者只有一個(gè)子節(jié)點(diǎn)那么tag可以使用.string的方法來得到子節(jié)點(diǎn),兩種情況輸出的內(nèi)容相同
但是如果tag中包含多個(gè)子節(jié)點(diǎn),tag就沒有辦法確定.string就不知道要調(diào)用哪個(gè)所以輸出的結(jié)果是None
如果tag中有多個(gè)字符串那么可以用.strings來循環(huán)獲取
可以用.stripped_strings除去多余空格的內(nèi)容,全部是空格的行會被忽略掉,段首和段末的空白會被刪除
說回文檔樹,每一個(gè)tag或者字符串都會有父節(jié)點(diǎn),啥子事父節(jié)點(diǎn)嘞,父節(jié)點(diǎn)簡單理解就是這個(gè)元素上面的一個(gè)標(biāo)簽就這個(gè)例子來說<title>的父標(biāo)簽是<head>,這個(gè)The Dormouse's story字符串的父節(jié)點(diǎn)是<title>,文檔的頂層節(jié)點(diǎn)比如的父節(jié)點(diǎn)是?BeautifulSoup?對象,而BeautifulSoup對象的父節(jié)點(diǎn)是None。而.parent可以獲得一個(gè)父節(jié)點(diǎn),而parents可以獲得所有父節(jié)點(diǎn)。
????說完父節(jié)點(diǎn)怎么能不說兄弟節(jié)點(diǎn)呢,按父節(jié)點(diǎn)的來理解兄弟節(jié)點(diǎn)那么兄弟節(jié)點(diǎn)就表示是同級的標(biāo)簽,也就是同屬于一個(gè)父節(jié)點(diǎn)的標(biāo)簽在文檔樹中可以用.next_sibling和.previous_sibling來獲取兄弟標(biāo)簽。很好理解.previous_sibling可以獲得前一個(gè)兄弟標(biāo)簽,而.next_sibling可以獲得后一個(gè)兄弟標(biāo)簽。如果已經(jīng)是第一個(gè)標(biāo)簽?zāi)敲?previous_sibling將會返回None,.next_sibling同理。但是要記住父節(jié)點(diǎn)不同那么兩個(gè)標(biāo)簽就不是兄弟標(biāo)簽,還有一點(diǎn)要注意這個(gè)例子中又這么一段:
第一個(gè)a標(biāo)簽的.next_sibling并不是第二個(gè)a標(biāo)簽而是逗號和換行符,仔細(xì)看第一個(gè)標(biāo)簽的最后是一個(gè)逗號和換行,所以不難理解咯。而第二個(gè)a標(biāo)簽是逗號換行符的.next_sibling。
.next_sibling或.previous_sibling只能的到前一個(gè)或者后一個(gè)標(biāo)簽,而.next_siblings或.previous_siblings可以得到所有的前標(biāo)簽或者后標(biāo)簽
再來說說,next_element和.previous_element
這倆玩意看著和之前講的那個(gè)很像功能也有點(diǎn)像。先來說說HTML解析器,HTML解析器就是按照順序依次帶或者關(guān)閉標(biāo)簽。而.next_element屬性是指向解析過程中下一個(gè)被解析對象,當(dāng)然結(jié)果可能會和.next_sibling一樣但是大部分時(shí)候還是不一樣。
就以下例子來說
從這里就可以看出區(qū)別。那么.next_elements和.previous_elements就不多說了,同上