前言
我們將利用 Beautiful Soup 模塊的搜索功能,根據(jù)標簽名稱、標簽屬性、文檔文本和正則表達式來搜索。
搜索方法
Beautiful Soup 內(nèi)建的搜索方法如下:
- 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 文件用來做測試。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
< 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 > </ div > </ body > </ html > |
我們可以通過 find()
方法來獲得 <ul> 標簽,默認情況下會得到第一個出現(xiàn)的。接著再獲取 <li> 標簽,默認情況下還是會得到第一個出現(xiàn)的,接著獲得 <div> 標簽,通過輸出內(nèi)容來驗證是否獲取了第一個出現(xiàn)的標簽。
1
2
3
4
5
|
with open ( 'search.html' , 'r' ) as filename: soup = BeautifulSoup(filename, 'lxml' ) first_ul_entries = soup.find( 'ul' ) print first_ul_entries.li.div.string |
find() 方法具體如下:
1
|
find(name,attrs,recursive,text, * * kwargs) |
正如上代碼所示,find()
方法接受五個參數(shù):name、attrs、recursive、text 和 **kwargs 。name 、attrs 和 text 參數(shù)都可以在 find()
方法充當過濾器,提高匹配結(jié)果的精確度。
搜索標簽
除了上面代碼的搜索 <ul> 標簽外,我們還可以搜索 <li> 標簽,返回結(jié)果也是返回出現(xiàn)的第一個匹配內(nèi)容。
1
2
3
4
|
tag_li = soup.find( 'li' ) # tag_li = soup.find(name = "li") print type (tag_li) print tag_li.div.string |
搜索文本
如果我們只想根據(jù)文本內(nèi)容來搜索的話,我們可以只傳入文本參數(shù) :
1
2
3
|
search_for_text = soup.find(text = 'plants' ) print type (search_for_text) < class 'bs4.element.NavigableString' > |
返回的結(jié)果也是 NavigableString 對象 。
根據(jù)正則表達式搜索
如下的一段 HTML 文本內(nèi)容
1
2
3
4
|
<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> |
可以看到 abc@example 郵件地址并沒有包括在任何標簽內(nèi),這樣就不能根據(jù)標簽來找到郵件地址了。這個時候,我們可以使用正則表達式來進行匹配。
1
2
3
4
5
6
7
8
9
10
11
12
|
email_id_example = """ <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> """ email_soup = BeautifulSoup(email_id_example, 'lxml' ) print email_soup # pattern = "\w+@\w+\.\w+" emailid_regexp = re. compile ( "\w+@\w+\.\w+" ) first_email_id = email_soup.find(text = emailid_regexp) print first_email_id |
在使用正則表達式進行匹配時,如果有多個匹配項,也是先返回第一個。
根據(jù)標簽屬性值搜索
可以通過標簽的屬性值來搜索:
1
2
|
search_for_attribute = soup.find( id = 'primaryconsumers' ) print search_for_attribute.li.div.string |
根據(jù)標簽屬性值來搜索對大多數(shù)屬性都是可用的,例如:id、style 和 title 。
但是對以下兩種情況會有不同:
- 自定義屬性
- 類 ( class ) 屬性
我們不能再直接使用屬性值來搜索了,而是得使用 attrs 參數(shù)來傳遞給 find()
函數(shù)。
根據(jù)自定義屬性來搜索
在 HTML5 中是可以給標簽添加自定義屬性的,例如給標簽添加 屬性。
如下代碼所示,如果我們再像搜索 id 那樣進行操作的話,會報錯的,Python 的變量不能包括 - 符號。
1
2
3
4
5
6
|
customattr = """ <p data-custom="custom">custom attribute example</p> """ customsoup = BeautifulSoup(customattr, 'lxml' ) customsoup.find(data - custom = "custom" ) # SyntaxError: keyword can't be an expression |
這個時候使用 attrs 屬性值來傳遞一個字典類型作為參數(shù)進行搜索:
1
2
|
using_attrs = customsoup.find(attrs = { 'data-custom' : 'custom' }) print using_attrs |
基于 CSS 中的 類 進行搜索
對于 CSS 的類屬性,由于在 Python 中 class 是個關(guān)鍵字,所以是不能當做標簽屬性參數(shù)傳遞的,這種情況下,就和自定義屬性一樣進行搜索。也是使用 attrs 屬性,傳遞一個字典進行匹配 。
除了使用 attrs 屬性之外,還可以使用 class_ 屬性進行傳遞,這樣與 class 區(qū)別開了,也不會導(dǎo)致錯誤。
1
2
3
4
|
css_class = soup.find(attrs = { 'class' : 'producerlist' }) css_class2 = soup.find( class_ = "producerlist" ) print css_class print css_class2 |
使用自定義的函數(shù)搜索
可以給 find()
方法傳遞一個函數(shù),這樣就會根據(jù)函數(shù)定義的條件進行搜索。
函數(shù)應(yīng)該返回 true 或者是 false 值。
1
2
3
4
|
def is_producers(tag): return tag.has_attr( 'id' ) and tag.get( 'id' ) = = 'producers' tag_producers = soup.find(is_producers) print tag_producers.li.div.string |
代碼中定義了一個 is_producers 函數(shù),它將檢查標簽是否具體 id 屬性以及屬性值是否等于 producers,如果符合條件則返回 true ,否則返回 false 。
聯(lián)合使用各種搜索方法
Beautiful Soup 提供了各種搜索方法,同樣,我們也可以聯(lián)合使用這些方法來進行匹配,提高搜索的準確度。
1
2
3
4
5
6
7
8
9
10
11
|
combine_html = """ <p class="identical"> Example of p tag with class identical </p> <div class="identical"> Example of div tag with class identical <div> """ combine_soup = BeautifulSoup(combine_html, 'lxml' ) identical_div = combine_soup.find( "div" , class_ = "identical" ) print identical_div |
使用 find_all() 方法搜索
使用 find()
方法會從搜索結(jié)果中返回第一個匹配的內(nèi)容,而 find_all()
方法則會返回所有匹配的項。
在 find()
方法中用到的過濾項,同樣可以用在 find_all()
方法中。事實上,它們可以用到任何搜索方法中,例如:find_parents()
和 find_siblings()
中 。
1
2
3
4
5
|
# 搜索所有 class 屬性等于 tertiaryconsumerlist 的標簽。 all_tertiaryconsumers = soup.find_all( class_ = 'tertiaryconsumerlist' ) print type (all_tertiaryconsumers) for tertiaryconsumers in all_tertiaryconsumers: print tertiaryconsumers.div.string |
find_all()
方法為 :
1
|
find_all(name,attrs,recursive,text,limit, * * kwargs) |
它的參數(shù)和 find()
方法有些類似,多個了 limit 參數(shù)。limit 參數(shù)是用來限制結(jié)果數(shù)量的。而 find()
方法的 limit 就是 1 了。
同時,我們也能傳遞一個字符串列表的參數(shù)來搜索標簽、標簽屬性值、自定義屬性值和 CSS 類。
1
2
3
4
5
6
7
8
|
# 搜索所有的 div 和 li 標簽 div_li_tags = soup.find_all([ "div" , "li" ]) print div_li_tags print # 搜索所有類屬性是 producerlist 和 primaryconsumerlist 的標簽 all_css_class = soup.find_all( class_ = [ "producerlist" , "primaryconsumerlist" ]) print all_css_class print |
搜索相關(guān)標簽
一般情況下,我們可以使用 find()
和 find_all()
方法來搜索指定的標簽,同時也能搜索其他與這些標簽相關(guān)的感興趣的標簽。
搜索父標簽
可以使用 find_parent()
或者 find_parents()
方法來搜索標簽的父標簽。
find_parent()
方法將返回第一個匹配的內(nèi)容,而 find_parents()
將返回所有匹配的內(nèi)容,這一點與 find()
和 find_all()
方法類似。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 搜索 父標簽 primaryconsumers = soup.find_all( class_ = 'primaryconsumerlist' ) print len (primaryconsumers) # 取父標簽的第一個 primaryconsumer = primaryconsumers[ 0 ] # 搜索所有 ul 的父標簽 parent_ul = primaryconsumer.find_parents( 'ul' ) print len (parent_ul) # 結(jié)果將包含父標簽的所有內(nèi)容 print parent_ul print # 搜索,取第一個出現(xiàn)的父標簽.有兩種操作 immediateprimary_consumer_parent = primaryconsumer.find_parent() # immediateprimary_consumer_parent = primaryconsumer.find_parent('ul') print immediateprimary_consumer_parent |
搜索同級標簽
Beautiful Soup 還提供了搜索同級標簽的功能。
使用函數(shù) find_next_siblings()
函數(shù)能夠搜索同一級的下一個所有標簽,而 find_next_sibling()
函數(shù)能夠搜索同一級的下一個標簽。
1
2
3
|
producers = soup.find( id = 'producers' ) next_siblings = producers.find_next_siblings() print next_siblings |
同樣,也可以使用 find_previous_siblings()
和 find_previous_sibling()
方法來搜索上一個同級的標簽。
搜索下一個標簽
使用 find_next()
方法將搜索下一個標簽中第一個出現(xiàn)的,而 find_next_all()
將會返回所有下級的標簽項。
1
2
3
4
|
# 搜索下一級標簽 first_div = soup.div all_li_tags = first_div.find_all_next( "li" ) print all_li_tags |
搜索上一個標簽
與搜索下一個標簽類似,使用 find_previous()
和 find_all_previous()
方法來搜索上一個標簽。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家學(xué)習(xí)或者使用python能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對服務(wù)器之家的支持。
原文鏈接:http://www.glumes.com/python-beautifulsoup-search-data/