Learn Beautiful Soup(3)——使用Beautiful Soup進行查找

            網頁中有用的信息一般存在於網頁中的文本或各類不一樣標籤的屬性值,爲了得到這些網頁信息,有必要有一些查找方法能夠獲取這些文本值或標籤屬性。而Beautiful Soup中內置了一些查找方式:css

  •            find()
  •            find_all()
  •            find_parent()
  •            find_parents()
  •            find_next_sibling()
  •            find_next_siblings()
  •            find_previous_sibling()
  •            find_previous_siblings()
  •            find_previous()
  •            find_all_previous()
  •            find_next()
  •            find_all_next()

        使用find()查找

如下這段HTML是例程要用到的參考網頁html

<html>
	<body>
		<div class="ecopyramid">
		<ul id="producers">
			<li class="producerlist">
				<div class="name">plants</div>
				<div class="number">100000</div>
			</li>
			<li class="producerlist">
				<div class="name">algae</div>
				<div class="number">100000</div>
			</li>
		</ul>
		<ul id="primaryconsumers">
			<li class="primaryconsumerlist">
				<div class="name">deer</div>
				<div class="number">1000</div>
			</li>
			<li class="primaryconsumerlist">
				<div class="name">rabbit</div>
				<div class="number">2000</div>
			</li>
		<ul>
		<ul id="secondaryconsumers">
			<li class="secondaryconsumerlist">
				<div class="name">fox</div>
				<div class="number">100</div>
			</li>
			<li class="secondaryconsumerlist">
				<div class="name">bear</div>
				<div class="number">100</div>
			</li>
		</ul>
		<ul id="tertiaryconsumers">
			<li class="tertiaryconsumerlist">
				<div class="name">lion</div>
				<div class="number">80</div>
			</li>
			<li class="tertiaryconsumerlist">
				<div class="name">tiger</div>
				<div class="number">50</div>
			</li>
		</ul>
	</body>
</html>


以上代碼是一個生態金字塔的簡單展現,爲了找到其中的第一輩子產者,第一消費者或第二消費者,咱們可使用Beautiful Soup的查找方法。通常來講,爲了找到BeautifulSoup對象內任何第一個標籤入口,咱們可使用find()方法。python

找到第一輩子產者

能夠明顯看到,生產者在第一個<ul>標籤裏,由於生產者是在整個HTML文檔中第一個<ul>標籤中出現,因此能夠簡單的使用find()方法找到第一輩子產者。下圖HTML樹表明了第一個生產者所在位置。正則表達式

而後在ecologicalpyramid.py中寫入下面一段代碼,使用ecologicalpyramid.html文件建立BeautifulSoup對象。函數

from bs4 import BeautifulSoup
with open("ecologicalpyramid.html","r") as ecological_pyramid:
soup = BeautifulSoup(ecological_pyramid)
producer_entries = soup.find("ul")
print(producer_entries.li.div.string)


 輸出獲得:plantsspa


find()說明

find()函數以下:code

find(name,attrs,recursive,text,**wargs)regexp

這些參數至關於過濾器同樣能夠進行篩選處理。orm

不一樣的參數過濾能夠應用到如下狀況:xml

  • 查找標籤,基於name參數
  • 查找文本,基於text參數
  • 基於正則表達式的查找
  • 查找標籤的屬性,基於attrs參數
  • 基於函數的查找

 經過標籤查找

咱們能夠傳遞任何標籤的名字來查找到它第一次出現的地方。找到後,find函數返回一個BeautifulSoup的標籤對象。

from bs4 import BeautifulSoup

with open("ecologicalpyramid.html", "r") as ecological_pyramid:
	soup = BeautifulSoup(ecological_pyramid,"html")
producer_entries = soup.find("ul")
print(type(producer_entries))

輸出的獲得 <class 'bs4.element.Tag'>

經過文本查找

直接字符串的話,查找的是標籤。若是想要查找文本的話,則須要用到text參數。以下所示:

from bs4 import BeautifulSoup

with open("ecologicalpyramid.html", "r") as ecological_pyramid:
	soup = BeautifulSoup(ecological_pyramid,"html")
plants_string = soup.find(text="plants")
print(plants_string)

輸出:plants

經過正則表達式查找

有如下HTML代碼:

<br/>
<div>The below HTML has the information that has email ids.</div> 
abc@example.com
<div>xyz@example.com</div>
<span>foo@example.com</span>

若是想找出第一個郵箱地址,可是因爲第一個郵箱地址沒有標籤包含,因此經過其餘方式很難找到。可是咱們能夠把郵箱地址進行正則表達式處理,這樣就容易多了。

參考以下代碼:

import re
from bs4 import BeautifulSoup

email_id_example = """<br/>
<div>The below HTML has the information that has email ids.</div> 
abc@example.com
<div>xyz@example.com</div>
<span>foo@example.com</span>
"""

soup = BeautifulSoup(email_id_example)
emailid_regexp = re.compile("\w+@\w+\.\w+")
first_email_id = soup.find(text=emailid_regexp)
print(first_email_id)

輸出:abc@example.com

經過標籤屬性進行查找

觀看例程HTML代碼,其中第一消費者在ul標籤裏面且id屬性爲priaryconsumers.

由於第一消費者出現的ul不是文檔中第一個ul,因此經過前面查找標籤的辦法就行不通了。如今經過標籤屬性進行查找,參考代碼以下:

from bs4 import BeautifulSoup

with open("ecologicalpyramid.html", "r") as ecological_pyramid:
	soup = BeautifulSoup(ecological_pyramid,"html")
primary_consumer = soup.find(id="primaryconsumers")
print(primary_consumer.li.div.string)

輸出:deer

經過標籤屬性查找的方式適用於大多數標籤屬性,包括id,style,title,可是有一組標籤屬性例外。

  • Custom attrbutes
  • Class
此時,咱們須要藉助attrs參數來進行傳遞。

基於定製屬性的查找


好比咱們HTML5標籤中的data-custom屬性,若是咱們這樣
customattr = ""'<p data-custom="custom">custom attribute 
example</p>"""
customsoup = BeautifulSoup(customattr,'lxml')
customSoup.find(data-custom="custom")

那麼則會報錯。緣由是在Python中變量不能呢含有-這個字符,而咱們傳遞的data-custom有-這個字符。
解決的辦法是在attrs屬性用字典進行傳遞參數。
using_attrs = customsoup.find(attrs={'data-custom':'custom'})
print(using_attrs)

基於CSS類的查找


由於class是Python的保留關鍵字,因此沒法使用class這個關鍵字。因此解決辦法相似上面。
css_class = soup.find(attrs={'class':'primaryconsumerlist'})
print(css_class)

還有另外一個辦法。BeautifulSoup有一個特別的關鍵字參數class_。示例:
方法1:
css_class = soup.find(class_ = "primaryconsumers" )

方法2:
css_class = soup.find(attrs={'class':'primaryconsumers'})

基於定義的函數進行查找

能夠傳遞函數到find()來基於函數定義的條件進行查找。函數值必須返回true或者false。
例子:
def is_secondary_consumers(tag):
return tag.has_attr('id') and tag.get('id') == 
'secondaryconsumers'
secondary_consumer = soup.find(is_secondary_consumers)
print(secondary_consumer.li.div.string)

輸出:fox

把方法進行組合後進行查找


能夠用其中任何方法進行組合來進行查找,好比同時基於標籤名和id號。

使用find_all查找

find()用來查找第一個匹配結果出現的地方,而find_all()正如名字所示,將會找到全部匹配結果出現的地方。應用到find()中的不一樣過濾參數同理能夠用到find_all()中,實際上,過濾參數能夠用於任何查找函數,如find_parents()或和find_siblings()。

查找全部三級消費者

all_tertiaryconsumers = 
soup.find_all(class_="tertiaryconsumerslist")

其all_tertiaryconsumers的類型是列表。
因此咱們對其列表進行迭代,循環輸出三級消費者的名字。
for tertiaryconsumer in all_tertiaryconsumers:
print(tertiaryconsumer.div.string)

輸出:
lion
tiger

理解用於find_all()的參數


相比find(),find_all()有個額外的參數limit,以下所示:
find_all(name,attrs,recursive,text,limit,**kwargs)
limit參數能夠限制咱們想要獲得結果的數目。參照前面的郵件地址例子,咱們能夠獲得全部右鍵地址經過:
email_ids = soup.find_all(text=emailid_regexp)
print(email_ids)

輸出:[u'abc@example.com',u'xyz@example.com',u'foo@example.com']

當咱們使用limit參數,效果以下:
email_ids_limited = soup.find_all(text=emailid_regexp,limit=2)
print(email_ids_limited)

限制獲得兩個結果,因此輸出爲:
[u'abc@example.com',u'xyz@example.com']

說白了,find()也就是當limit=1時的find_all()。

能夠向find函數傳遞True或False參數,若是咱們傳遞True給find_all(),則返回全部soup對象的標籤。對於find()來講,則返回第一個標籤。
舉例查找文本,傳遞True將會返回全部文本。
all_texts = soup.find_all(text=True)
print(all_texts)

輸出:
[u'\n', u'\n', u'\n', u'\n', u'\n', u'plants', u'\n', u'100000', 
u'\n', u'\n', u'\n', u'algae', u'\n', u'100000', u'\n', u'\n', 
u'\n', u'\n', u'\n', u'deer', u'\n', u'1000', u'\n', u'\n', 
u'\n', u'rabbit', u'\n', u'2000', u'\n', u'\n', u'\n', 
u'\n', u'\n', u'fox', u'\n', u'100', u'\n', u'\n', u'\n', 
u'bear', u'\n', u'100', u'\n', u'\n', u'\n', u'\n', 
u'\n', u'lion', u'\n', u'80', u'\n', u'\n', u'\n', 
u'tiger', u'\n', u'50', u'\n', u'\n', u'\n', u'\n', 
u'\n'] 

一樣的,咱們能夠在傳遞text參數時傳遞一個字符串列表,那麼find_all()會找到誒個在列表中定義過的字符串。
all_texts_in_list = soup.find_all(text=["plants","algae"])
print(all_texts_in_list)

輸出:
[u'plants', u'algae']

這個一樣適用於查找標籤,標籤屬性,定製屬性和CSS類。如:
div_li_tags = soup.find_all(["div","li"])

find()和find_all()都會查找一個對象全部後輩們,不過咱們能夠控制它經過recursive參數。若是recursive=False,那麼超找只會找到該對象的最近後代。

經過標籤之間的關係進行查找

咱們能夠經過find()和find_all()來查找到想要內容。但有時候,咱們須要查看的與以內容相關先前的標籤或者後面的標籤來獲取額外的信息。好比方法find_parents()和find_next_siblings()等等。通常的,在find()和find_all()方法後使用上述方法,由於find()和find_all()能夠找到特殊的一個標籤,而後咱們能夠經過這個特殊的標籤找到其餘的想要的與之有關係的標籤。

查找父標籤

經過find_parents()或find_parent()。它們之間的不一樣就相似於find()和find_all()的區別。find_parents()返回所有的相匹配的父標籤,而find_paret()返回最近的一個父標籤。適用於find()的方法一樣也使用於這兩個方法。

在前面的第一消費者例子中,咱們能夠找到離Primaryconsumer最近的ul父標籤。
primaryconsumers = soup.find_all(class_="primaryconsumerlist")
primaryconsumer = primaryconsumers[0]
parent_ul = primaryconsumer.find_parents('ul')
print(parent_ul)

一個簡單的找到一個標籤的父標籤的方法就是使用find_parent()卻不帶任何參數。
immediateprimary_consumer_parent = primary_consumer.find_parent()

查找同胞


若是標籤在同一個等級的話,咱們能夠說這些標籤是同胞的關係,好比參照上面金字塔例子,全部ul標籤就是同胞的關係。


上圖ul標籤下的producers,primaryconsumers,secondaryconsumers,teriaryconsumers就是同胞關係。
再看下面這個圖:


div下的plants和algae不是同胞關係,可是plants和臨近的number是同胞關係。
Beautiful Soup自帶有查找同胞的方法。
好比find_next_siblings()和find_next_sibling()查找對象下面的同胞。舉例:
producers= soup.find(id='producers')
next_siblings = producers.find_next_siblings()
print(next_siblings)

將會輸出與之臨近的下面的全部同胞HTML代碼。

查找下一個

對每個標籤來講,下一個元素可能會是定位字符串,標籤對象或者其餘BeautifulSoup對象。咱們定義下一個元素爲與當前元素最靠近的元素。這個不一樣於同胞定義。咱們有方法能夠找到咱們想要標籤的下一個其餘元素對象。find_all_next()找到與當前元素靠近的全部對象。而find_next()找到離當前元素最接近的對象。

好比,找到在第一個div標籤後的全部li標籤
first_div = soup.div
all_li_tags = first_div.find_all_next("li")

輸出「:
[<li class="producerlist">
<div class="name">plants</div>
<div class="number">100000</div>
</li>, <li class="producerlist">
<div class="name">algae</div>
<div class="number">100000</div>
</li>, <li class="primaryconsumerlist">
<div class="name">deer</div>
<div class="number">1000</div>
</li>, <li class="primaryconsumerlist">
<div class="name">rabbit</div>
<div class="number">2000</div>
</li>, <li class="secondaryconsumerlist">
<div class="name">fox</div>
<div class="number">100</div>
</li>, <li class="secondaryconsumerlist">
<div class="name">bear</div>
<div class="number">100</div>
</li>, <li class="tertiaryconsumerlist">
<div class="name">lion</div>
<div class="number">80</div>
</li>, <li class="tertiaryconsumerlist">
<div class="name">tiger</div>
<div class="number">50</div>
</li>]

查找上一個

與查找下一個相反的是查找前一個。同理用於find_all_previous()和find_all_previous()
相關文章
相關標籤/搜索