两万字教会你解析库之Beautiful Soup
目錄
1.簡介
2.準備工作
3.解析器
4.基本用法
5.節點選擇器
5.1選擇元素?
5.2提取信息
5.3嵌套選擇
5.4關聯選擇
6.方法選擇器
7. css 選擇器
7.1?嵌套選擇
7.2?獲取屬性
7.3?獲取文本
總結
1.簡介
????????簡單來說,Beautiful Soup就是Python的一個HTML或XML的解析庫,可以用它來方便地從網 頁中提取數據。官方解釋如下:
????????Beautiful Soup提供一些簡單的、Python式的函數來處理導航、搜索、修改分析樹等功能。 它是一個工具箱,通過解析文檔為用戶提供需要抓取的數據,因為簡單,所以不需要多少代 碼就可以寫出一個完整的應用程序。
Beautiful Soup自動將輸入文檔轉換為Unicode編碼,輸出文檔轉換為UTF-8編碼。你不 需要考慮編碼方式,除非文檔沒有指定一個編碼方式,這時你僅僅需要說明一下原始編碼方 式就可以了。
????????Beautiful Soup已成為和lxml、html61ib 一樣出色的Python解釋器,為用戶靈活地提供不 同的解析策略或強勁的速度。 所以說,利用它可以省去很多煩瑣的提取工作,提高了解析效率。
所以說, 利用它可以省去很多煩瑣的提取工作,提高了解析效率。
2.準備工作
在開始之前,請確保已經正確安裝好了 Beautiful Soup和lxml ,如果沒有安裝 ,可以參考。3.解析器
Beautiful Soup 在解析時實際上依賴解析器,它除了支持 Python 標準庫中的 HTML 解析器外,還
支持一些第三方解析器(比如 lxml)。通過以上對比可以看出,lxml解析器有解析HTML和XML的功能,而且速度快,容錯能力強, 所以推薦使用它。
?如果使用lxml,那么在初始化Beautiful Soup時,可以把第二個參數改為lxml即可:
from bs4 import BeautifulSoup soup = BeautifulSoup('<p>Hello</p>', 'lxml') print(soup.p.string)返回:
4.基本用法
下面首先用實例來看看Beautiful Soup的基本用法:
html =''' <html><head><title>The Dormouse's story</title></head> <body> <p class="title" name="dromouse"xb>The Dormouse's story</bx/p> <p class="story">Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="linkl"><!-- Elsie --></a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" 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,它是一個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屬性就可以得到里面的文本了,所以我們可以通過 簡單調用幾個屬性完成文本提取。
5.節點選擇器
????????直接調用節點的名稱就可以選擇節點元素,再調用string屬性就可以得到節點內的文本了,這種選擇方式速度非常快。如果單個節點結構層次非常清晰,可以選用這種方式來解析。
5.1選擇元素?
下面再用一個例子詳細說明選擇元素的方法:?
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 href="http://example.com/elsie" class="sister" id="linkl"><!-- Elsie --></a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" 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)返回:
????????這里依然選用剛才的HTML代碼,首先打印輸出title節點的選擇結果,輸出結果正是title節 點加里面的文字內容。接下來,輸出它的類型,是bs4.element.Tag類型,這是Beautiful Soup中一個 重要的數據結構。經過選擇器選擇后,選擇結果都是這種Tag類型。Tag具有一些屬性,比如string 屬性,調用該屬性,可以得到節點的文本內容,所以接下來的輸出結果正是節點的文本內容。
????????接下來,我們又嘗試選擇了 head節點,結果也是節點加其內部的所有內容。最后,選擇了 p節點。 不過這次情況比較特殊,我們發現結果是第一個p節點的內容,后面的幾個p節點并沒有選到。也就 是說,當有多個節點時,這種選擇方式只會選擇到第一個匹配的節點,其他的后面節點都會忽略。
5.2提取信息
????????上面演示了調用string屬性來獲取文本的值,那么如何獲取節點屬性的值呢?如何獲取節點名 呢?下面我們來統一梳理一下信息的提取方式。
(1)獲取名稱
????????可以利用name屬性獲取節點的名稱。這里還是以上面的文本為例,選取title節點,然后調用 name屬性就可以得到節點名稱:
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 href="http://example.com/elsie" class="sister" id="linkl"><!-- Elsie --></a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" 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.name)返回:
(2) 獲取屬性
????????每個節點可能有多個屬性,比如id和class等,選擇這個節點元素后,可以調用attrs獲取所有 屬性:
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 href="http://example.com/elsie" class="sister" id="linkl"><!-- Elsie --></a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" 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.p.attrs) print(soup.p.attrs['name'])返回:
????????可以看到,attrs的返回結果是字典形式,它把選擇的節點的所有屬性和屬性值組合成一個字典, 接下來,如果要獲取name屬性,就相當于從字典中獲取某個鍵值,只需要用中括號加屬性名就可以 To比如,要獲取name屬性,就可以通過attrs['name']來得到
????????其實這樣有點煩瑣,還有一種更簡單的獲取方式:可以不用寫attrs,直接在節點元素后面加中 括號,傳人屬性名就可以獲取屬性值了。樣例如下:
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 href="http://example.com/elsie" class="sister" id="linkl"><!-- Elsie --></a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" 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.p['name']) print(soup.p['class'])返回:
????????這里需要注意的是,有的返回結果是字符串,有的返回結果是字符串組成的列表。比如,name屬 性的值是唯一的,返回的結果就是單個字符串。而對于class, 一個節點元素可能有多個class,所以 返回的是列表。在實際處理過程中,我們要注意判斷類型。
?(3 )獲取內容
????????可以利用string屬性獲取節點元素包含的文本內容,比如要獲取第一個p節點的文本:
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 href="http://example.com/elsie" class="sister" id="linkl"><!-- Elsie --></a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" 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.p.string)返回:
?再次注意一下,這里選擇到的p節點是第一個p節點,獲取的文本也是第一個p節點里面的文本。
5.3嵌套選擇
????????在上面的例子中,我們知道每一個返回結果都是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)返回:
????????第一行結果是調用head之后再次調用title而選擇的title節點元素。然后打印輸出了它的類型, 可以看到,它仍然是bs4.element.Tag類型。也就是說,我們在Tag類型的基礎上再次選擇得到的依 然還是Tag類型,每次返回的結果都相同,所以這樣就可以做嵌套選擇了。
????????最后,輸出它的string屬性,也就是節點里的文本內容。
5.4 關聯選擇
????????在做選擇的時候,有時候不能做到一步就選到想要的節點元素,需要先選中某一個節點元素,然 后以它為基準再選擇它的子節點、父節點、兄弟節點等,這里就來介紹如何選擇這些節點元素。
(1)子節點和子孫節點
????????選取節點元素之后,如果想要獲取它的直接子節點,可以調用contents屬性,示例如下:
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 href="http://example.com/elsie" class="sister" id="linkl"> <span>Elsie</span> </a> <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" 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.p.contents)返回:
????????可以看到,返回結果是列表形式。p節點里既包含文本,又包含節點,最后會將它們以列表形式統一返回。
????????需要注意的是,列表中的每個元素都是p節點的直接子節點。比如第一個a節點里面包含一層span 節點,這相當于孫子節點了,但是返回結果并沒有單獨把span節點選出來。所以說,contents屬性得到的結果是直接子節點的列表。
????????同樣,我們可以調用children屬性得到相應的結果:
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 href="http://example.com/elsie" class="sister" id="linkl"> <span>Elsie</span> </a> <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" 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.p.children) for i, child in enumerate(soup.p.children): print(i, child)返回:
????????還是同樣的HTML文本,這里調用了children屬性來選擇,返回結果是生成器類型。接下來, 我們用for循環輸出相應的內容。
如果要得到所有的子孫節點的話,可以調用descendants屬性:
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 href="http://example.com/elsie" class="sister" id="linkl"> <span>Elsie</span> </a> <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" 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') for i, child in enumerate(soup.p.descendants): print(i, child)返回:
????????此時返回結果還是生成器。遍歷輸出一下可以看到,這次的輸出結果就包含了 span節點。descendants 會遞歸查詢所有子節點,得到所有的子孫節點。
(2)父節點和祖先節點
如果要獲取某個節點元素的父節點,可以調用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 href="http://example.com/elsie" class="sister" id="linkl"> <span>Elsie</span> </a> <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" 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.a.parent)返回:
????????這里我們選擇的是第一個a節點的父節點元素。很明顯,它的父節點是p節點,輸出結果便是p 節點及其內部的內容。
????????需要注意的是,這里輸出的僅僅是a節點的直接父節點,而沒有再向外尋找父節點的祖先節點。 如果想獲取所有的祖先節點,可以調用parents屬性:
html =''' <html> <body> <p class="story"> <a href="http://example.com/elsie" class="sister" id="linkl"> <span>Elsie</span> </a> ''' from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(type(soup.a.parents)) print(list(enumerate(soup.a.parents)))返回:
????????可以發現,返回結果是生成器類型。這里用列表輸出了它的索引和內容,而列表中的元素就是a 節點的祖先節點。
(3)兄弟節點
????????上面說明了子節點和父節點的獲取方式,如果要獲取同級的節點(也就是兄弟節點),應該怎么 辦呢?示例如下:
html =''' <html> <body> <p class="story"> Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="linkl"> <span>Elsie</span> </a> Hello <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a> and they lived at the bottom of a well. ''' 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)))返回:
????????可以看到,這里調用了 4個屬性,其中next_sibling和previous_sibling分另U獲取節點的下一個 和上一個兄弟元素,next_siblings和previous_siblings則分別返回所有前面和后面的兄弟節點的生成器。
(4)提取信息
????????前面講解了關聯元素節點的選擇方法,如果想要獲取它們的一些信息,比如文本、屬性等,也用 同樣的方法,示例如下:
html =''' <html> <body> <p class="story"> Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="linkl">Bob</a><a href="http://example.com/lacie" 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'])返回:
????????如果返回結果是單個節點,那么可以直接調用string, attrs等屬性獲得其文本和屬性;如果返 回結果是多個節點的生成器,則可以轉為列表后取出某個元素,然后再調用string, attrs等屬性獲 取其對應節點的文本和屬性。
6.方法選擇器
????????前面所講的選擇方法都是通過屬性來選擇的,這種方法非常快,但是如果進行比較復雜的選擇的 話,它就比較煩瑣,不夠靈活了。幸好,Beautiful Soup還為我們提供了一些查詢方法,比如find_all() 和find()等,調用它們,然后傳人相應的參數,就可以靈活查詢了。
????????? find_all()
????????find_all,顧名思義,就是查詢所有符合條件的元素。給它傳人一些屬性或文本,就可以得到符 合條件的元素,它的功能十分強大。
????????它的API如下:
find_all(name , attrs , recursive , text , **kwargs) (l) name 我們可以根據節點名來查詢元素,示例如下: html =''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </div> <div class="panel-body"> <ul class="list" id="list-l"> <li class="element">Foo</li> <li class="element">Bar</li> <li class="element">]ay</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]))返回:
????????這里我們調用了 find_all()方法,傳人name參數,其參數值為ul。也就是說,我們想要查詢所 有ul節點,返回結果是列表類型,長度為2,每個元素依然都是bs4.element.Tag類型。
html =''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </div> <div class="panel-body"> <ul class="list" id="list-l"> <li class="element">Foo</li> <li class="element">Bar</li> <li class="element">]ay</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') for ul in soup.find_all(name='ul'): print(ul.find_all(name='li'))?返回:
返回結果是列表類型,列表中的每個元素依然還是Tag類型。
接下來,就可以遍歷每個li,獲取它的文本了:
html =''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </div> <div class="panel-body"> <ul class="list" id="list-l"> <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') 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)返回:
(2)attrs
除了根據節點名査詢,我們也可以傳人一些屬性來查詢,示例如下:
html =''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </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'}))返回:
????????這里查詢的時候傳人的是attrs參數,參數的類型是字典類型。比如,要查詢id為list-1的節 點,可以傳入attrs={'id': * list-1'}的查詢條件,得到的結果是列表形式,包含的內容就是符合id 為list-1的所有節點。在上面的例子中,符合條件的元素個數是1,所以結果是長度為1的列表。
????????對于一些常用的屬性,比如id和class等,我們可以不用attrs來傳遞。比如,要查詢id為list-1 的節點,可以直接傳人id這個參數。還是上面的文本,我們換一種方式來查詢:
html =''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </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(id='list-1')) print(soup.find_all(class_='element'))返回:
????????這里直接傳人id='list-r,就可以查詢id為list-l的節點元素了。而對于class來說,由于class 在Python里是一個關鍵字,所以后面需要加一個下劃線,即class,^element*,返回的結果依然還是 Tag組成的列表。
(3) text 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')))?返回:
????????這里有兩個a節點,其內部包含文本信息。這里在find_all()方法中傳人text參數,該參數為正 則表達式對象,結果返回所有匹配正則表達式的節點文本組成的列表。
????????? find()
????????除了 find_all()方法,還有find()方法,只不過后者返回的是單個元素,也就是第一個匹配的元 素,而前者返回的是所有匹配的元素組成的列表。示例如下:
html =''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </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(name='ul')) print(type(soup.find(name='ul'))) print(soup.find(class_='list'))返回:
????????這里的返回結果不再是列表形式,而是第一個匹配的節點元素,類型依然是Tag類型。
????????另外,還有許多查詢方法,其用法與前面介紹的find_all()、find()方法完全相同,只不過查詢 范圍不同,這里簡單說明一下。
- find_parents()和find_parent():前者返回所有祖先節點,后者返回直接父節點。
- find_next_siblings()和行11(1_/16乂1:__5:11)1:1|^():前者返回后面所有的兄弟節點,后者返回后面 第一兄i節點。
- find_previous_siblings()和find_previous_sibling():前者返回前面所有的兄弟節點,后者 返回前面第一個兄弟節點。
- find_all_next()和find_next():前者返回節點后所有符合條件的節點,后者返回第一個符合 條件的節點。
- find_all_previous()和find_previous():前者返回節點后所有符合條件的節點,后者返回第 一個符合條件的節點。
7. css 選擇器
????????Beautiful Soup還提供了另外一種選擇器,那就是CSS選擇器。如果對Web開發熟悉的話,那么對 CSS選擇器肯定也不陌生。如果不熟悉的話,可以參考CSS 選擇器參考手冊了解。
使用CSS選擇器時,只需要調用select()方法,傳人相應的CSS選擇器即可,示例如下:
html =''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </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.select('.panel .panel-heading')) print(soup.select('ul li')) print(soup.select('#list-2 .element')) print(type(soup.select('ul')[0]))返回:
????????這里我們用了 3次CSS選擇器,返回的結果均是符合CSS選擇器的節點組成的列表。例如, select('ul li')則是選擇所有ul節點下面的所有li節點,結果便是所有的li節點組成的列表。
最后一句打印輸出了列表中元素的類型。可以看到,類型依然是Tag類型。
7.1?嵌套選擇
????????select()方法同樣支持嵌套選擇。例如,先選擇所有ul節點,再遍歷每個ul節點,選擇其li節點,樣例如下:
html =''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </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') for ul in soup.select('ul'): print(ul.select('li'))返回:
可以看到,這里正常輸出了所有ul節點下所有li節點組成的列表。
7.2?獲取屬性
????????我們知道節點類型是Tag類型,所以獲取屬性還可以用原來的方法。仍然是上面的HTML文本, 這里嘗試獲取每個ul節點的id屬性:
html =''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </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') for ul in soup.select('ul'): print(ul['id']) print(ul.attrs['id'])返回:
可以看到,直接傳人中括號和屬性名,以及通過attrs屬性獲取屬性值,都可以成功。
7.3?獲取文本
要獲取文本,當然也可以用前面所講的string屬性。此外,還有一個方法,那就是get_text(), 示例如下:
html =''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </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') for li in soup.select('li'): print('Get Text:', li.get_text()) print('String:', li.string)返回:
?可以看到,二者的效果完全一致。
到此,Beautiful Soup的用法基本就介紹完了,最后做一下簡單的總結。
總結
總結
以上是生活随笔為你收集整理的两万字教会你解析库之Beautiful Soup的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql数据库(4): 创建并选择数据
- 下一篇: 关闭线程 C语言,如何用C语言实现多线程