Beautiful Soup 是一個HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 數據。
一、安裝
sudo pip3 install beautifulsoup4
二、使用
-
導入模塊
from bs4 import BeautifulSoup
-
創建BeautifulSoup對象
In [1]: from bs4 import BeautifulSoup In [2]: text = ''' ...: <div> ...: <ul> ...: <li class="item-0" id="first"><a href="link1.html">first item</a></li> ...: <li class="item-1"><a href="link2.html">second item</a></li> ...: <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> ...: <li class="item-1"><a href="link4.html">fourth item</a></li> ...: <li class="item-0"><a href="link5.html">fifth item</a></li> ...: </ul> ...: </div> ...: ''' In [3]: bs = BeautifulSoup(text)#創建BeautifulSoup對象,可以直接傳入字符串
In [4]: bs1 = BeautifulSoup(open('./test.html'))#也可以傳入文件對象
In [5]: bs Out[5]: <html><body><div> <ul> <li class="item-0" id="first"><a href="link1.html">first item</a></li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div> </body></html>創建Beautiful Soup對象時,既可以傳入字符串,也可以傳入文件對象。它將復雜HTML文檔轉換成一個復雜的樹形結構,並且會自動修正文檔,像上述例子中補齊了html和body節點,每個節點都是Python對象
-
獲取Tag對象
In [6]: bs.ul #獲取ul標簽內容 Out[6]: <ul> <li class="item-0" id="first"><a href="link1.html">first item</a></li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> In [7]: type(bs.ul) Out[7]: bs4.element.Tag In [8]: bs.li #獲取li標簽內容,注意返回的是第一個符合要求的標簽 Out[8]: <li class="item-0" id="first"><a href="link1.html">first item</a></li> In [12]: bs.ul.li.a #可疊加查找標簽 Out[12]: <a href="link1.html">first item</a>
通過Beautiful Soup對象后面接上‘.標簽名’來獲取需要查找的標簽,可疊加
-
Tag對象常用屬性
-
name-----顯示標簽名
In [13]: bs.name #大部分時候,可以把BeautifulSoup當作Tag對象,是一個特殊的 Tag Out[13]: '[document]' In [14]: bs.li.name Out[14]: 'li
BeautifulSoup 對象表示的是一個文檔的內容。大部分時候,可以把它當作 Tag 對象
-
attrs----以字典的方式顯示該標簽所有屬性
In [15]: bs.attrs Out[15]: {} In [16]: bs.li.attrs #以字典的形式顯示所有屬性 Out[16]: {'class': ['item-0'], 'id': 'first'} In [17]: bs.li.attrs['id'] #獲取具體的某個屬性方法1 Out[17]: 'first' In [18]: bs.li['id'] #獲取具體屬性方法2,'.attrs'可省略 Out[18]: 'first' In [19]: bs.li.get('id')#獲取具體 屬性方法3,利用get方法 Out[19]: 'first'
-
text----獲取標簽里面的內容
In [20]: bs.li.text #獲取第一個li標簽里面的內容,由於li標簽里面只有唯一的a標簽了,會返回最里面a標簽的內容 Out[20]: 'first item' In [21]: bs.li.a.text #返回a標簽的內容 Out[21]: 'first item'
注意:如果標簽內容是一個注釋,則注釋符號會被去掉,比如“<!-- 這是一個注釋 -->”,則返回"這是一個注釋"
-
contents----將直接子節點以列表的形式輸出,同時也包含換行符'\n'
In [22]: bs.ul.contents Out[22]: ['\n', <li class="item-0" id="first"><a href="link1.html">first item</a></li>, '\n', <li class="item-1"><a href="link2.html">second item</a></li>, '\n', <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>, '\n', <li class="item-1"><a href="link4.html">fourth item</a></li>, '\n', <li class="item-0"><a href="link5.html">fifth item</a></li>, '\n']
-
chilldren----將直接子節點以列表生成器的形式輸出,也包括換行符‘\n
In [28]: bs.ul.children #返回的是列表生成器對象 Out[28]: <list_iterator at 0x7f2d9e90ea30> In [29]: for child in bs.ul.children: ...: print(child) ...: <li class="item-0" id="first"><a href="link1.html">first item</a></li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li>
-
descendants----返回的是一個生成器對象,進行迭代取值的時候,會遞歸循環的顯示所有子孫節點
In [30]: bs.ul.descendants #返回的是一個生成器對象,進行迭代取值的時候,會遞歸循環的顯示所有子孫節點 Out[30]: <generator object Tag.descendants at 0x7f2d9e79fc80> In [31]: for d in bs.ul.descendants: ...: print(d) ...: <li class="item-0" id="first"><a href="link1.html">first item</a></li> <a href="link1.html">first item</a> first item <li class="item-1"><a href="link2.html">second item</a></li> <a href="link2.html">second item</a> second item <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> <a href="link3.html"><span class="bold">third item</span></a> <span class="bold">third item</span> third item <li class="item-1"><a href="link4.html">fourth item</a></li> <a href="link4.html">fourth item</a> fourth item <li class="item-0"><a href="link5.html">fifth item</a></li> <a href="link5.html">fifth item</a> fifth item
-
-
Tag對象常用方法
-
find(self, name=None, attrs={}, recursive=True, text=None,**kwargs)----------只返回第一個匹配的對象
-
name參數----過濾標簽名,可以傳入字符串、正則以及列表3種形式
In [32]: bs.find('li') #查找第一個匹配的li標簽 Out[32]: <li class="item-0" id="first"><a href="link1.html">first item</a></li> In [33]: bs.find(['li','a']) #查找第一個匹配的li標簽或者a標簽 Out[33]: <li class="item-0" id="first"><a href="link1.html">first item</a></li> In [34]: import re In [35]: bs.find(re.compile(r'^l')) #查找第一個以l開頭的標簽,li標簽匹配上 Out[35]: <li class="item-0" id="first"><a href="link1.html">first item</a></li> In [36]: bs.find(re.compile(r'l$')) #查找第一個以l結尾的標簽,html標簽符合 Out[36]: <html><body><div> <ul> <li class="item-0" id="first"><a href="link1.html">first item</a></li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div> </body></html>
-
attrs參數----過濾屬性,dict類型
In [37]: bs.find(attrs={'class':'item-1'}) #查找class屬性為item-1的第一個標簽 Out[37]: <li class="item-1"><a href="link2.html">second item</a></li>
-
recursive參數----如果為True,表示是否遞歸地從子孫節點中去查找匹配對象。否則只從直接子節點中進行查找
In [38]: bs.find('li',recursive=True) #遞歸查找,能夠匹配到li對象 Out[38]: <li class="item-0" id="first"><a href="link1.html">first item</a></li> In [39]: bs.find('li',recursive=False) #從直接子節點(即html)中無法找到li標簽 In [40]: bs.ul.find('li',recursive=False) #ul的直接子節點為li標簽,所以能夠匹配到 Out[40]: <li class="item-0" id="first"><a href="link1.html">first item</a></li>
-
text參數----可以搜索文檔中匹配的內容,和name參數一樣,有字符串、正則、列表這3種形式
In [41]: bs.find(text='first item') #查找字符串,需要傳入完整內容,否則無法匹配 Out[41]: 'first item' In [42]: bs.find(text=re.compile(r'item'))#查找第一個包含item的內容 Out[42]: 'first item' In [43]: bs.find(text=re.compile(r'ir'))#查找第一個包含ir的內容 Out[43]: 'first item' In [44]: bs.find(text=['second item','third item']) #查找內容為second item或third item的第一個內容 Out[44]: 'second item'
-
其它關鍵字參數----關鍵字為屬性名,但是注意不能直接傳入和python關鍵字重名的class屬性,需要在class后面加上下划線,即修改為"class_"
In [45]: bs.find(id='first') #id屬性作為關鍵字參數進行查找 Out[45]: <li class="item-0" id="first"><a href="link1.html">first item</a></li> In [43]: bs.find(href='link4.html') #href屬性作為關鍵字參數進行查找 Out[43]: <a href="link4.html">fourth item</a> In [44]: bs.find(class='item-inactive') #和python關鍵字class重名的class屬性則會報錯 File "<ipython-input-42-a9ab4a3f6cee>", line 1 bs.find(class='item-inactive') ^ SyntaxError: invalid syntax
-
-
find_all(self, name=None, attrs={}, recursive=True, text=None,**kwargs)----以列表的形式返回所有能夠匹配到的對象,所有參數用法同find()方法
In [45]: bs.find_all('li') #查找所有的li標簽 Out[45]: [<li class="item-0" id="first"><a href="link1.html">first item</a></li>, <li class="item-1"><a href="link2.html">second item</a></li>, <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>, <li class="item-1"><a href="link4.html">fourth item</a></li>, <li class="item-0"><a href="link5.html">fifth item</a></li>] In [46]: bs.find_all('li',attrs={"class":"item-1"}) #查找所有的li標簽,並且class屬性為item-1 Out[46]: [<li class="item-1"><a href="link2.html">second item</a></li>, <li class="item-1"><a href="link4.html">fourth item</a></li>]
-
get()方法----獲取對象的特定屬性
In [47]: bs.li.get('class') #class屬性因為可以有多個,所以返回的是列表形式 Out[47]: ['item-0'] In [48]: bs.find(attrs={"class":"item-0"}).get('id') #以字符串的形式返回id屬性值 Out[48]: 'first' In [49]: bs.find_all('a')[1].get('href') Out[49]: 'link2.html'
-
get_text()方法----獲取標簽里面的內容,同text屬性返回的結果一樣
In [50]: bs.li.get_text() #獲取第一個li最里面的內容 Out[50]: 'first item' In [51]: bs.find(attrs={"class":"bold"}).get_text() #獲取class屬性為bold標簽(即span標簽)里面的內容 Out[51]: 'third item' In [52]: bs.find_all('a')[3].get_text() #獲取第4個a標簽里面的內容 Out[52]: 'fourth item'
-
select()方法----css選擇器,同find_all方法有點類似,返回的是列表
-
通過標簽名查找
In [53]: bs.select('li') #查找所有li標簽 Out[53]: [<li class="item-0" id="first"><a href="link1.html">first item</a></li>, <li class="item-1"><a href="link2.html">second item</a></li>, <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>, <li class="item-1"><a href="link4.html">fourth item</a></li>, <li class="item-0"><a href="link5.html">fifth item</a></li>]
-
通過類名查找,類名前加上'.'
In [54]: bs.select('.bold') #查找class='bold'的標簽 Out[54]: [<span class="bold">third item</span>]
-
通過id查找,id前加上'#'
In [55]: bs.select('#first') #查找id為first的標簽 Out[55]: [<li class="item-0" id="first"><a href="link1.html">first item</a></li>]
-
混合查找
In [56]: bs.select('.item-0 a') #查找class="item-0"下的a標簽 Out[56]: [<a href="link1.html">first item</a>, <a href="link5.html">fifth item</a>] In [57]: bs.select('#first a') #查找id="first"下面的a標簽 Out[57]: [<a href="link1.html">first item</a>] In [58]: bs.select('ul span') #查找ul下面的span標簽 Out[58]: [<span class="bold">third item</span>] In [59]: bs.select('ul>span') #標簽后面帶上">"表示直接子標簽,因為span標簽不是ul的直接子標簽,所以匹配不到 Out[59]: [] In [60]: bs.select('a>span') #span標簽是a標簽的子標簽,所以能匹配到 Out[60]: [<span class="bold">third item</span>]
直接子標簽查找,則使用
>
分隔 -
通過屬性查找
In [61]: bs.select('li[class="item-inactive"]') #查找class屬性為'item-inactive'的li標簽 Out[61]: [<li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>] In [62]: bs.select('a[href="link2.html"]') #查找href屬性為'link2.html'的a標簽 Out[62]: [<a href="link2.html">second item</a>]
-
-