這一篇文章接在上一篇 基礎(chǔ)學(xué)習(xí)——BeautifulSoup篇(1) 之后把敢,今天來繼續(xù)學(xué)習(xí)BeautifulSoup
歡迎關(guān)注公眾號(hào):老白和他的爬蟲
4.遍歷文檔樹
4.7父節(jié)點(diǎn)和兄弟節(jié)點(diǎn)
父節(jié)點(diǎn)可以通過.parent
和.parents
操作得倒
from bs4 import BeautifulSoup
if __name__ == "__main__":
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,'lxml')
head_tag = soup.head
title_tag = head_tag.contents[0]
print(title_tag.parent) #打印title_tag的父節(jié)點(diǎn)
link = soup.a
for parent in link.parents: #循環(huán)打印a標(biāo)簽的父節(jié)點(diǎn)
if parent is None:
print(parent)
else:
print(parent.name)
兄弟節(jié)點(diǎn)些微有點(diǎn)不同品嚣,一個(gè)節(jié)點(diǎn)可以通過.next_sibling
和 .previous_sibling
得到它之前和之后的兄弟節(jié)點(diǎn)嫉你,同樣,也可以通過.next_siblings
和 .previous_siblings
遍歷操作得倒所有的兄弟節(jié)點(diǎn)思灌。
4.8回退和縮進(jìn)
上一個(gè)內(nèi)容講的.next_sibling
和 .previous_sibling
其實(shí)就已經(jīng)有了縮進(jìn)和回退的味道了沛豌,但是他們是不同的链峭。我們使用解析器把html文檔解析成了一個(gè)又一個(gè)事件或者說是標(biāo)簽,兄弟節(jié)點(diǎn)只能在這一級(jí)進(jìn)行前后操作谐算,然而要對(duì)整個(gè)文檔進(jìn)行操作熟尉,我們就必須使用到.next_element
和 .previous_element
。我們用上面的文檔樹來舉一個(gè)例子
last_a_tag = soup.find("a", id="link2")
print(last_a_tag.next_sibling)
print(last_a_tag.next_element)
print(last_a_tag.next_sibling)
的輸出結(jié)果是and
因?yàn)榈诙€(gè)<a>
下一個(gè)兄弟節(jié)點(diǎn)是and
氯夷,但是print(last_a_tag.next_element)
的輸出結(jié)果是Lacie
臣樱,因?yàn)榈诙€(gè)<a>
下一個(gè)元素是比它低一級(jí)的字符串Lacie
。這段代碼理解的畫腮考,這兩個(gè)操作也很好理解了雇毫,同理它還有.next_elements
和 .previous_elements
這兩個(gè)操作,具體怎么用不用我說了吧踩蔚,類比一下就會(huì)了棚放。
4.9. find_all()
find_all(name , attrs , text , keyword )
使用.find_all()
操作可以設(shè)置這些常用參數(shù)
4.9.1 name參數(shù)
.find_all()
可以直接查找tag的name來找到對(duì)應(yīng)的標(biāo)簽
soup.find_all('b') #用來查找所有的<b>標(biāo)簽
4.9.2 keyword參數(shù).find_all()``.find_all()
print(soup.find_all(id='link2')) #用來查找id為link2的標(biāo)簽
.find_all()
操作可以與正則表達(dá)式搭配,個(gè)人認(rèn)為這一步在查找一些特定標(biāo)簽時(shí)十分有用
import re
#找到所有標(biāo)簽中以b開頭的標(biāo)簽
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
#提取所有a標(biāo)簽中包含字符串example的鏈接
for x in soup.find_all('a',href = re.compile('example')):
print(x.get('href'))
這里記住一點(diǎn)馅闽,.find_all()
內(nèi)部的多個(gè)參數(shù)是可以同時(shí)寫的飘蚯,上面這段代碼我這樣寫也可以
for x in soup.find_all(class_ = 'sister' ,href = re.compile('example')):
print(x.get('href'))
class
應(yīng)該是python的關(guān)鍵字馍迄,所以我們這里需要用class_
來表示class
4.9.3 attrs參數(shù)
可以通過 find_all()
方法的 attrs 參數(shù)定義一個(gè)字典參數(shù)來搜索包含特殊屬性的tag
data_soup = BeautifulSoup('<div data-foo="value">foo!</div>','lxml')
print(data_soup.find_all(attrs={"data-foo": "value"}))
4.9.4 text參數(shù)
print(soup.find_all(text="Elsie")) #輸出文本為Elsie的字符串
print(soup.find_all(text=["Tillie", "Elsie", "Lacie"])) #輸出文本為列表中所包含的字符串
print(soup.find_all(text=re.compile("Dormouse"))) #輸出文本包含Dormouse的字符串
4.9.5 limit參數(shù)
limit參數(shù)可以限制返回節(jié)點(diǎn)的數(shù)量
print(soup.find_all('a',limit = 2)) #本身可以返回三個(gè)a標(biāo)簽,但是由于limit限制只返回兩個(gè)
4.10 find()
.find()
其實(shí)就是.find_all()
加上了limit = 1
的操作局骤,區(qū)別于.find()
返回的是結(jié)果攀圈,.find_all()
返回的是集合
.find()
和.find_all()
還有其他的一些操作,這里就不一一舉例了峦甩,避免這個(gè)教程太過繁瑣赘来,只要熟練的掌握.find()
和.find_all()
,就已經(jīng)能解決很多的問題凯傲。其他的一些操作包括
find_parents(),find_parent(),find_next_siblings(),find_next_sibling(),find_previous_siblings(),find_previous_sibling(),find_all_next(),find_next(),find_all_previous(),find_previous()
4.11 CSS選擇器
這一個(gè)功能我不打算在這里說犬辰,因?yàn)檫@里能實(shí)現(xiàn)的功能在前面我們都已經(jīng)實(shí)現(xiàn)了,只不過更熟悉css的人可以選擇這種方法冰单。
5.修改文檔樹
給tag的 .string
屬性賦值,就相當(dāng)于用當(dāng)前的內(nèi)容替代了原來的內(nèi)容:
markup = '<a >I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup,'lxml')
tag = soup.a
tag.string = "New link text."
print(tag)
使用.append()
方法可以像標(biāo)簽添加內(nèi)容
markup = '<a >I linked to </a>'
soup = BeautifulSoup(markup,'lxml')
tag = soup.a
print(tag)
tag.append("haha")
print(tag)
如果想要?jiǎng)?chuàng)建一段注釋
from bs4 import Comment
new_comment = soup.new_string("Nice to see you.", Comment)
tag.append(new_comment)
print(tag)
如果想要?jiǎng)?chuàng)建一個(gè)新的tag
soup = BeautifulSoup("<b></b>",'lxml')
original_tag = soup.b
new_tag = soup.new_tag("a", )
original_tag.append(new_tag)
print(original_tag)
new_tag.string = "Link text."
print(original_tag)
使用'.insert()'插入具體的內(nèi)容
markup = '<a >I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup,'lxml')
tag = soup.a
tag.insert(1, "but did not endorse ") #參數(shù)1控制插入字符串的位置
print(tag)
移除當(dāng)前tag的內(nèi)容
tag.clear()
print(tag)
移除當(dāng)前的tag節(jié)點(diǎn)
a_tag = soup.a
i_tag = soup.i.extract()
print(a_tag)
print(i_tag)
使用decompose()
完全銷毀當(dāng)前tag節(jié)點(diǎn)
markup = '<a >I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup,'lxml')
tag = soup.a
a_tag = soup.a
soup.i.decompose()
print(a_tag)
使用replace_with()
替換節(jié)點(diǎn)
markup = '<a >I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup,'lxml')
tag = soup.a
a_tag = soup.a
new_tag = soup.new_tag("b")
new_tag.string = "example.net"
a_tag.i.replace_with(new_tag)
print(tag)
6.輸出
.prettify()
方法將BeautifulSoup的文檔樹格式化后以Unicode編碼輸出,每個(gè)XML/HTML標(biāo)簽都獨(dú)占一行
markup = '<a >I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup,'lxml')
print(soup.prettify())
如果不想格式化輸出幌缝,可以選擇壓縮輸出
print(str(soup))
如果只想得到標(biāo)簽中的文本內(nèi)容
markup = '<a >\nI linked to <i>example.com</i>\n</a>'
soup = BeautifulSoup(markup,'lxml')
print(soup.get_text())
print(soup.get_text("|")) #指定文本分隔符
print(soup.get_text("|", strip=True)) #去除文本內(nèi)容前后空白
好了,BeautifulSoup的基礎(chǔ)知識(shí)我們已經(jīng)學(xué)習(xí)完畢了诫欠,你可以跟著這兩篇文章來學(xué)習(xí)掌握BeautifulSoup涵卵,也可以選擇把這兩篇當(dāng)作字典,當(dāng)你在寫爬蟲時(shí)來翻閱