您好,登錄后才能下訂單哦!
前面我們介紹了正則表達式的相關用法,但是一旦正則寫的有問題,可能得到的就不是我們想要的結果了,而且對于一個網頁來說,都有一定的特殊的結構和層級關系,而且很多節點都有id或class來對作區分,所以我們借助于它們的結構和屬性來提取不也是可以的嗎?
所以,這一節我們就介紹一個強大的解析工具,叫做 BeautiSoup,它就是借助網頁的結構和屬性等特性來解析網頁的工具,有了它我們不用再去寫一些復雜的正則,只需要簡單的幾條語句就可以完成網頁中某個元素的提取。
廢話不多說,接下來我們就來感受一下 BeautifulSoup 的強大之處吧。
簡單來說,BeautifulSoup 就是 Python 的一個 HTML 或 XML 的解析庫,我們可以用它來方便地從網頁中提取數據,官方的解釋如下:
BeautifulSoup提供一些簡單的、Python式的函數用來處理導航、搜索、修改分析樹等功能。它是一個工具箱,通過解析文檔為用戶提供需要抓取的數據,因為簡單,所以不需要多少代碼就可以寫出一個完整的應用程序。 BeautifulSoup 自動將輸入文檔轉換為 Unicode 編碼,輸出文檔轉換為 utf-8 編碼。你不需要考慮編碼方式,除非文檔沒有指定一個編碼方式,這時你僅僅需要說明一下原始編碼方式就可以了。 BeautifulSoup 已成為和 lxml、html6lib 一樣出色的 Python 解釋器,為用戶靈活地提供不同的解析策略或強勁的速度。
所以說,利用它我們可以省去很多繁瑣的提取工作,提高解析效率。
在開始之前請確保已經正確安裝好了 BeautifulSoup 和 LXML,如沒有安裝可以參考第一章的安裝過程。
BeautifulSoup 在解析的時候實際上是依賴于解析器的,它除了支持 Python 標準庫中的 HTML 解析器,還支持一些第三方的解析器比如 LXML,下面我們對 BeautifulSoup 支持的解析器及它們的一些優缺點做一個簡單的對比。
解析器 | 使用方法 | 優勢 | 劣勢 |
---|---|---|---|
Python標準庫 | BeautifulSoup(markup, "html.parser") | Python的內置標準庫、執行速度適中 、文檔容錯能力強 | Python 2.7.3 or 3.2.2)前的版本中 中文容錯能力差 |
LXML HTML 解析器 | BeautifulSoup(markup, "lxml") | 速度快、文檔容錯能力強 | 需要安裝C語言庫 |
LXML XML 解析器 | BeautifulSoup(markup, "xml") | 速度快、唯一支持XML的解析器 | 需要安裝C語言庫 |
html5lib | BeautifulSoup(markup, "html5lib") | 最好的容錯性、以瀏覽器的方式解析文檔、生成 HTML5 格式的文檔 | 速度慢、不依賴外部擴展 |
所以通過以上對比可以看出,LXML 這個解析器有解析 HTML 和 XML 的功能,而且速度快,容錯能力強,所以推薦使用這個解析器來進行解析。
使用 LXML 這個解析器,在初始化 BeautifulSoup 的時候我們可以把第二個參數改為 lxml 即可,如下:
from bs4 import BeautifulSoup
soup = BeautifulSoup('<p>Hello</p>', 'lxml')
print(soup.p.string)
Python資源分享qun 784758214 ,內有安裝包,PDF,學習視頻,這里是Python學習者的聚集地,零基礎,進階,都歡迎
后面 BeautifulSoup 的用法實例也統一用這個解析器來演示。
4# . 基本使用
下面我們首先用一個實例來感受一下 BeautifulSoup 的基本使用:
html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.prettify())
print(soup.title.string)
運行結果:
<html>
<head>
<title>
The Dormouse's story
</title>
</head>
<body>
<p class="title" name="dromouse">
<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>
</body>
</html>
The Dormouse's story
首先我們聲明了一個變量 html,它是一個 HTML 字符串,但是注意到,它并不是一個完整的 HTML 字符串,body 和 html 節點都沒有閉合,但是我們將它當作第一個參數傳給 BeautifulSoup 對象,第二個參數傳入的是解析器的類型,在這里我們使用 lxml,這樣就完成了 BeaufulSoup 對象的初始化,將它賦值給 soup 這個變量。
那么接下來我們就可以通過調用 soup 的各個方法和屬性對這串 HTML代碼解析了。
我們首先調用了 prettify() 方法,這個方法可以把要解析的字符串以標準的縮進格式輸出,在這里注意到輸出結果里面包含了 body 和 html 節點,也就是說對于不標準的 HTML 字符串 BeautifulSoup 可以自動更正格式,這一步實際上不是由 prettify() 方法做的,這個更正實際上在初始化 BeautifulSoup 時就完成了。
然后我們調用了 soup.title.string ,這個實際上是輸出了 HTML 中 title 節點的文本內容。所以 soup.title 就可以選擇出 HTML 中的 title 節點,再調用 string 屬性就可以得到里面的文本了,所以我們就可以通過簡單地調用幾個屬性就可以完成文本的提取了,是不是非常方便?
剛才我們選擇元素的時候直接通過調用節點的名稱就可以選擇節點元素了,然后再調用 string 屬性就可以得到節點內的文本了,這種選擇方式速度非常快,如果單個節點結構話層次非常清晰,可以選用這種方式來解析。
下面我們再用一個例子詳細說明一下它的選擇方法:
html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.title)
print(type(soup.title))
print(soup.title.string)
print(soup.head)
print(soup.p)
運行結果:
<title>The Dormouse's story</title>
<class 'bs4.element.Tag'>
The Dormouse's story
<head><title>The Dormouse's story</title></head>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
在這里我們依然選用了剛才的 HTML 代碼,我們首先打印輸出了 title 節點的選擇結果,輸出結果正是 title 節點加里面的文字內容。接下來輸出了它的類型,是 bs4.element.Tag 類型,這是 BeautifulSoup 中的一個重要的數據結構,經過選擇器選擇之后,選擇結果都是這種 Tag 類型,它具有一些屬性比如 string 屬性,調用 Tag 的 string 屬性,就可以得到節點的文本內容了,所以接下來的輸出結果正是節點的文本內容。
接下來我們又嘗試選擇了 head 節點,結果也是節點加其內部的所有內容,再接下來選擇了 p 節點,不過這次情況比較特殊,我們發現結果是第一個 p 節點的內容,后面的幾個 p 節點并沒有選擇到,也就是說,當有多個節點時,這種選擇方式只會選擇到第一個匹配的節點,其他的后面的節點都會忽略。
在上面我們演示了調用 string 屬性來獲取文本的值,那我們要獲取節點屬性值怎么辦呢?獲取節點名怎么辦呢?下面我們來統一梳理一下信息的提取方式
可以利用 name 屬性來獲取節點的名稱。還是以上面的文本為例,我們選取 title 節點,然后調用 name 屬性就可以得到節點名稱。
print(soup.title.name)
運行結果:
title
每個節點可能有多個屬性,比如 id,class 等等,我們選擇到這個節點元素之后,可以調用 attrs 獲取所有屬性。
print(soup.p.attrs)
print(soup.p.attrs['name'])
運行結果:
{'class': ['title'], 'name': 'dromouse'}
dromouse
可以看到 attrs 的返回結果是字典形式,把選擇的節點的所有屬性和屬性值組合成一個字典,接下來如果要獲取 name 屬性,就相當于從字典中獲取某個鍵值,只需要用中括號加屬性名稱就可以得到結果了,比如獲取 name 屬性就可以通過 attrs['name'] 得到相應的屬性值。
其實這樣的寫法還有點繁瑣,還有一種更簡單的獲取方式,我們可以不用寫 attrs,直接節點元素后面加中括號,傳入屬性名就可以達到屬性值了,樣例如下:
print(soup.p['name'])
print(soup.p['class'])
運行結果:
dromouse
['title']
在這里注意到有的返回結果是字符串,有的返回結果是字符串組成的列表。比如 name 屬性的值是唯一的,返回的結果就是單個字符串,而對于 class,一個節點元素可能由多個 class,所以返回的是列表,所以在實際處理過程中要注意判斷類型。
可以利用 string 屬性獲取節點元素包含的文本內容,比如上面的文本我們獲取第一個 p 節點的文本:
print(soup.p.string)
運行結果:
The Dormouse's story
再次注意一下這里選擇到的 p 節點是第一個 p 節點,獲取的文本也就是第一個 p 節點里面的文本。
在上面的例子中我們知道每一個返回結果都是 bs4.element.Tag 類型,它同樣可以繼續調用節點進行下一步的選擇,比如我們獲取了 head 節點元素,我們可以繼續調用 head 來選取其內部的 head 節點元素。
html = """
<html><head><title>The Dormouse's story</title></head>
<body>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.head.title)
print(type(soup.head.title))
print(soup.head.title.string)
運行結果:
<title>The Dormouse's story</title>
<class 'bs4.element.Tag'>
The Dormouse's story
第一行結果是我們調用了 head 之后再次調用了 title 來選擇的 title 節點元素,然后我們緊接著打印輸出了它的類型,可以看到它仍然是 bs4.element.Tag 類型,也就是說我們在 Tag 類型的基礎上再次選擇得到的依然還是 Tag 類型,每次返回的結果都相同,所以這樣我們就可以這樣做嵌套的選擇了。
最后輸出了一下它的 string 屬性,也就是節點里的文本內容。
我們在做選擇的時候有時候不能做到一步就可以選擇到想要的節點元素,有時候在選擇的時候需要先選中某一個節點元素,然后以它為基準再選擇它的子節點、父節點、兄弟節點等等。所以在這里我們就介紹下如何來選擇這些節點元素。
選取到了一個節點元素之后,如果想要獲取它的直接子節點可以調用 contents 屬性,我們用一個實例來感受一下:
print(soup.p.contents)
運行結果:
[<b>The Dormouse's story</b>]
contents 屬性得到的結果是直接子節點的列表。
同樣地我們可以調用 children 屬性,得到相應的結果:
print(soup.p.children)
for i,child in enumerate(soup.p.children):
print(child)
運行結果:
<list_iterator object at 0x10529eef0>
<b>The Dormouse's story</b>
還是同樣的 HTML 文本,在這里我們調用了 children 屬性來進行選擇,返回結果可以看到是生成器類型,所以接下來我們用 for 循環輸出了一下相應的內容,內容其實是一樣的,只不過 children 返回的是生成器類型,而 contents 返回的是列表類型。
如果我們要得到所有的子孫節點的話可以調用 descendants 屬性:
print(soup.p.descendants)
for i,child in enumerate(soup.p.descendants):
print(child)
運行結果:
<generator object Tag.descendants at 0x103fa5a20>
<b>The Dormouse's story</b>
The Dormouse's story
返回結果還是生成器,遍歷輸出一下可以看到descendants 會遞歸地查詢所有子節點,得到的是所有的子孫節點。
如果要獲取某個節點元素的父節點,可以調用 parent 屬性:
html = """
<html>
<head>
<title>The Dormouse's story</title>
</head>
<body>
<p class="story">
Once upon a time there were three little sisters; and their names were
<a class="sister" id="link1">
<span>Elsie</span>
</a>
</p>
<p class="story">...</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.a.parent)
運行結果:
<p class="story">
Once upon a time there were three little sisters; and their names were
<a class="sister" id="link1">
<span>Elsie</span>
</a>
</p>
在這里我們選擇的是第一個 a 節點的父節點元素,很明顯它的父節點是 p 節點,輸出結果便是 p 節點及其內部的內容。
注意到這里輸出的僅僅是 a 節點的直接父節點,而沒有再向外尋找父節點的祖先節點,如果我們要想獲取所有的祖先節點,可以調用 parents 屬性:
html = """
<html>
<body>
<p class="story">
<a class="sister" id="link1">
<span>Elsie</span>
</a>
</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(type(soup.a.parents))
print(list(enumerate(soup.a.parents)))
運行結果:
<class 'generator'>
[(0, <p class="story">
<a class="sister" id="link1">
<span>Elsie</span>
</a>
</p>), (1, <body>
<p class="story">
<a class="sister" id="link1">
<span>Elsie</span>
</a>
</p>
</body>), (2, <html>
<body>
<p class="story">
<a class="sister" id="link1">
<span>Elsie</span>
</a>
</p>
</body></html>), (3, <html>
<body>
<p class="story">
<a class="sister" id="link1">
<span>Elsie</span>
</a>
</p>
</body></html>)]
返回結果是一個生成器類型,我們在這里用列表輸出了它的索引和內容,可以發現列表中的元素就是 a 節點的祖先節點。
上面說明了子節點和父節點的獲取方式,如果要獲取同級的節點也就是兄弟節點應該怎么辦?我們先用一個實例來感受一下:
html = """
<html>
<body>
<p class="story">
Once upon a time there were three little sisters; and their names were
<a class="sister" id="link1">
<span>Elsie</span>
</a>
Hello
<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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print('Next Sibling', soup.a.next_sibling)
print('Prev Sibling', soup.a.previous_sibling)
print('Next Siblings', list(enumerate(soup.a.next_siblings)))
print('Prev Siblings', list(enumerate(soup.a.previous_siblings)))
運行結果:
Next Sibling
Hello
Prev Sibling
Once upon a time there were three little sisters; and their names were
Next Siblings [(0, '\n Hello\n '), (1, <a class="sister" id="link2">Lacie</a>), (2, ' \n and\n '), (3, <a class="sister" id="link3">Tillie</a>), (4, '\n and they lived at the bottom of a well.\n ')]
Prev Siblings [(0, '\n Once upon a time there were three little sisters; and their names were\n ')]
可以看到在這里我們調用了四個不同的屬性,next_sibling 和 previous_sibling 分別可以獲取節點的下一個和上一個兄弟元素,next_siblings 和 previous_siblings 則分別返回所有前面和后面的兄弟節點的生成器。
在上面我們講解了關聯元素節點的選擇方法,如果我們想要獲取它們的一些信息,比如文本、屬性等等也是同樣的方法。
html = """
<html>
<body>
<p class="story">
Once upon a time there were three little sisters; and their names were
<a class="sister" id="link1">Bob</a><a class="sister" id="link2">Lacie</a>
</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print('Next Sibling:')
print(type(soup.a.next_sibling))
print(soup.a.next_sibling)
print(soup.a.next_sibling.string)
print('Parent:')
print(type(soup.a.parents))
print(list(soup.a.parents)[0])
print(list(soup.a.parents)[0].attrs['class'])
運行結果:
Next Sibling:
<class 'bs4.element.Tag'>
<a class="sister" id="link2">Lacie</a>
Lacie
Parent:
<class 'generator'>
<p class="story">
Once upon a time there were three little sisters; and their names were
<a class="sister" id="link1">Bob</a><a class="sister" id="link2">Lacie</a>
</p>
['story']
如果返回結果是單個節點,那么可以直接調用 string、attrs 等屬性來獲得其文本和屬性,如果返回結果是多個節點的生成器,則可以轉為列表后取出某個元素,然后再調用 string、attrs 等屬性來獲取其對應節點等文本和屬性。
前面我們所講的選擇方法都是通過屬性來選擇元素的,這種選擇方法非常快,但是如果要進行比較復雜的選擇的話則會比較繁瑣,不夠靈活。所以 BeautifulSoup 還為我們提供了一些查詢的方法,比如 find_all()、find() 等方法,我們可以調用方法然后傳入相應等參數就可以靈活地進行查詢了。
最常用的查詢方法莫過于 find_all() 和 find() 了,下面我們對它們的用法進行詳細的介紹。
find_all,顧名思義,就是查詢所有符合條件的元素,可以給它傳入一些屬性或文本來得到符合條件的元素,功能十分強大。
它的API如下:
find_all(name?, attrs , recursive , text , **kwargs)
我們可以根據節點名來查詢元素,下面我們用一個實例來感受一下:
html='''
<div class="panel">
<div class="panel-heading">
<h5>Hello</h5>
</div>
<div class="panel-body">
<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>
</div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(name='ul'))
print(type(soup.find_all(name='ul')[0]))
運行結果:
[<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>, <ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>]
<class 'bs4.element.Tag'>
Python資源分享qun 784758214 ,內有安裝包,PDF,學習視頻,這里是Python學習者的聚集地,零基礎,進階,都歡迎
在這里我們調用了 find_all() 方法,傳入了一個 name 參數,參數值為 ul,也就是說我們想要查詢所有 ul 節點,返回結果是列表類型,長度為 2,每個元素依然都是 bs4.element.Tag 類型。
因為都是 Tag 類型,所以我們依然可以進行嵌套查詢,還是同樣的文本,在這里我們查詢出所有 ul 節點后再繼續查詢其內部的 li 節點。
for ul in soup.find_all(name='ul'):
print(ul.find_all(name='li'))
運行結果:
[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
[<li class="element">Foo</li>, <li class="element">Bar</li>]
返回結果是列表類型,列表中的每個元素依然還是 Tag 類型。
接下來我們就可以遍歷每個 li 獲取它的文本了。
for ul in soup.find_all(name='ul'):
print(ul.find_all(name='li'))
for li in ul.find_all(name='li'):
print(li.string)
運行結果:
[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
Foo
Bar
Jay
[<li class="element">Foo</li>, <li class="element">Bar</li>]
Foo
Bar
除了根據節點名查詢,我們也可以傳入一些屬性來進行查詢,我們用一個實例感受一下:
html='''
<div class="panel">
<div class="panel-heading">
<h5>Hello</h5>
</div>
<div class="panel-body">
<ul class="list" id="list-1" name="elements">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>
</div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(attrs={'id': 'list-1'}))
print(soup.find_all(attrs={'name': 'elements'}))
運行結果:
[<ul class="list" id="list-1" name="elements">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]
[<ul class="list" id="list-1" name="elements">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]
在這里我們查詢的時候傳入的是 attrs 參數,參數的類型是字典類型,比如我們要查詢 id 為 list-1 的節點,那就可以傳入attrs={'id': 'list-1'} 的查詢條件,得到的結果是列表形式,包含的內容就是符合 id 為 list-1 的所有節點,上面的例子中符合條件的元素個數是 1,所以結果是長度為 1 的列表。
對于一些常用的屬性比如 id、class 等,我們可以不用 attrs 來傳遞,比如我們要查詢 id 為 list-1 的節點,我們可以直接傳入 id 這個參數,還是上面的文本,我們換一種方式來查詢。
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(id='list-1'))
print(soup.find_all(class_='element'))
運行結果:
[<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]
[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>, <li class="element">Foo</li>, <li class="element">Bar</li>]
在這里我們直接傳入 id='list-1' 就可以查詢 id 為 list-1 的節點元素了。而對于 class 來說,由于 class 在 python 里是一個關鍵字,所以在這里后面需要加一個下劃線,class_='element',返回的結果依然還是 Tag 組成的列表。
text 參數可以用來匹配節點的文本,傳入的形式可以是字符串,可以是正則表達式對象,我們用一個實例來感受一下:
import re
html='''
<div class="panel">
<div class="panel-body">
<a>Hello, this is a link</a>
<a>Hello, this is a link, too</a>
</div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(text=re.compile('link')))
運行結果:
['Hello, this is a link', 'Hello, this is a link, too']
在這里有兩個 a 節點,其內部包含有文本信息,在這里我們調用 find_all() 方法傳入 text 參數,參數為正則表達式對象,結果會返回所有匹配正則表達式的節點文本組成的列表。
除了 find_all() 方法,還有 find() 方法,只不過 find() 方法返回的是單個元素,也就是第一個匹配的元素,而 find_all() 返回的是所有匹配的元素組成的列表。
html='''
<div class="panel">
<div class="panel-heading">
<h5>Hello</h5>
</div>
<div class="panel-body">
<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>
</div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find(name='ul'))
print(type(soup.find(name='ul')))
print(soup.find(class_='list'))
運行結果:
<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<class 'bs4.element.Tag'>
<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
返回結果不再是列表形式,而是第一個匹配的節點元素,類型依然是 Tag 類型。
另外還有許多的查詢方法,用法與前面介紹的 find_all()、find() 方法完全相同,只不過查詢范圍不同,在此做一下簡單的說明。
find_parents() 返回所有祖先節點,find_parent() 返回直接父節點。
find_previous_siblings() 返回前面所有兄弟節點,find_previous_sibling() 返回前面第一個兄弟節點。
find_all_next() 返回節點后所有符合條件的節點, find_next() 返回第一個符合條件的節點。
find_all_previous() 返回節點后所有符合條件的節點, find_previous() 返回第一個符合條件的節點
BeautifulSoup 還提供了另外一種選擇器,那就是 CSS 選擇器,如果對 Web 開發熟悉對話,CSS 選擇器肯定也不陌生,如果不熟悉的話,可以看一下:http://www.w3school.com.cn/cs...。
使用 CSS 選擇器,只需要調用 select() 方法,傳入相應的 CSS 選擇器即可,我們用一個實例來感受一下:
html='''
<div class="panel">
<div class="panel-heading">
<h5>Hello</h5>
</div>
<div class="panel-body">
<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>
</div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.select('.panel .panel-heading'))
print(soup.select('ul li'))
print(soup.select('#list-2 .element'))
print(type(soup.select('ul')[0]))
運行結果:
[<div class="panel-heading">
<h5>Hello</h5>
</div>]
[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>, <li class="element">Foo</li>, <li class="element">Bar</li>]
[<li class="element">Foo</li>, <li class="element">Bar</li>]
<class 'bs4.element.Tag'>
在這里我們用了三次 CSS 選擇器,返回的結果均是符合 CSS 選擇器的節點組成的列表。例如 select('ul li') 則是選擇所有 ul 節點下面的所有 li 節點,結果便是所有的 li 節點組成的列表。
最后一句我們打印輸出了列表中元素的類型,可以看到類型依然是 Tag 類型。
select() 方法同樣支持嵌套選擇,例如我們先選擇所有 ul 節點,再遍歷每個 ul 節點選擇其 li 節點,樣例如下:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
for ul in soup.select('ul'):
print(ul.select('li'))
運行結果:
[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
[<li class="element">Foo</li>, <li class="element">Bar</li>]
可以看到正常輸出了遍歷每個 ul 節點之后,其下的所有 li 節點組成的列表。
我們知道節點類型是 Tag 類型,所以獲取屬性還是可以用原來的方法獲取,仍然是上面的 HTML 文本,我們在這里嘗試獲取每個 ul 節點的 id 屬性。
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
for ul in soup.select('ul'):
print(ul['id'])
print(ul.attrs['id'])
運行結果:
list-1
list-1
list-2
list-2
可以看到直接傳入中括號和屬性名和通過 attrs 屬性獲取屬性值都是可以成功的。
那么獲取文本當然也可以用前面所講的 string 屬性,還有一個方法那就是 get_text(),同樣可以獲取文本值。
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
for li in soup.select('li'):
print('Get Text:', li.get_text())
print('String:', li.string)
運行結果:
Get Text: Foo
String: Foo
Get Text: Bar
String: Bar
Get Text: Jay
String: Jay
Get Text: Foo
String: Foo
Get Text: Bar
String: Bar
Python資源分享qun 784758214 ,內有安裝包,PDF,學習視頻,這里是Python學習者的聚集地,零基礎,進階,都歡迎
二者的效果是完全一致的,都可以獲取到節點的文本值。
到此 BeautifulSoup 的使用介紹基本就結束了,最后做一下簡單的總結:
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。