關於BeautifulSoup的總結

發表於2016-04-11

最近一直在用BeautifulSoup,但是語法很容易忘記。在這裡做個學習總結吧。

參考:

Beautiful Soup 4.2.0 文件

功能

BeautifulSoup是用來從HTML或XML中提取資料的Python庫。


匯入

使用方法:


編碼

soup使用Unicode編碼。


物件種類

有四種型別:Tag,NavigableString,BeautifulSoup,Comment。
BeautifulSoup將文件轉化為樹形結構,每個節點都是上述四種型別的Python物件。

1.Tag

與XML和HTML中Tag物件相同。
如:
soup = BeautifulSoup(Extremely bold)
soup.b就是一個Tag物件。

  1. Name
    tag.name 可獲取,可更改
  2. Attribute
    一個Tag物件可以有多個屬性,操作方法和字典相同,如上述Tag物件b就有一個class屬性:
    soup.b[‘class’]
    或者使用get方法soup.b.get(‘class’)

獲取所有屬性鍵值對:
soup.b.attrs

tag的屬性可新增、刪除(del soup.b[‘class’])、修改,和字典方法相同。

如果一個屬性key對應多個value,則返回一個value的list,如:

輸出:[“body”, “strikeout”]

這種多個值的屬性是需要在HTML中有定義的,如果並沒有被定義為多值屬性,則返回字串:

輸出‘my id’
如果轉換的是XML文件,則不會存在多值屬性,返回字串。

可以使用list或字串對屬性賦值。

2. NavigableString

Tag中的字串即為NavigableString物件。
tag.string
在BeautifulSoup之外使用該型別,推薦轉換為Unicode:
unicode(Tag.string)

tag中包含的字串不可編輯,只能替換:
tag.string.replace_with(new string)

tag能夠包含其他tag或字串,而NavigableString則不能包含其他物件。不支援.content,.string,find(),只支援部分遍歷文件樹和搜尋文件樹中的屬性。

3. BeautifulSoup

表示的是一個文件的全部內容,大部分情況可當做Tag物件,支援遍歷文件樹和搜尋文件樹的大部分屬性。
而在HTML或XML中並沒有叫做BeautifulSoup的Tag,所以並沒有name和attribute屬性,但是有個特殊屬性:
soup.name
輸出u'[document]’

4. Comment

Comment型別是NavigableString型別的子類,BeautifulSoup中也有同樣道理的一些其他型別。


遍歷文件樹

BeautifulSoup物件作為一棵樹,有多個節點。對於一個節點,相對於它所在的位置,有子節點、父節點、兄弟節點。

1. 子節點

一個Tag可包含多個Tag以及字串,這些都是這個Tag的子節點。而NavigableString不會有子節點。

如果想要獲得某個Tag,上述已提到方法:
soup.tag_name
通過點取屬性,只能獲得當前名字的第一個tag,若要獲取所有,需要使用搜尋文件樹中的方法:
soup.find_all(‘tag_name’)

tag的.contents屬性可將所有子節點以列表的方式輸出。
可通過tag的.children生成器,對所有子節點進行遍歷。

.contents.children只對獲取Tag的直接子節點,.descendants可用於對Tag的所有子孫節點進行遍歷。

如果tag只有一個NavigableString型別子節點,則可用.string獲取。如果包含多個,使用.strings遍歷。若輸出的字串中包含空格或空行,使用.stripped_strings去除。

2. 父節點

當前節點的父節點:.parent
當前節點的所有父輩節點:.parents

3. 兄弟節點

擁有同一父節點的節點之間。

同理,所有兄弟節點:

指向下一個或上一個解析物件:


搜尋文件樹

經常使用的兩種方法:find(str)和find_all(str)。
其中的str,代表了tag的name。可以是純字串、正規表示式、列表(任一匹配就滿足條件,是或運算)、True(返回所有Tag節點不返回字串節點)。

另一種入參不是str,而是method。此方法是一個函式,只接受一個元素入參,若此函式返回True表示入參匹配要求。例如:
def has_class_but_no_id(tag):
return tag.has_attr(‘class’) and not tag.has_attr(‘id’)

綜上,過濾器包括:純字串、正規表示式、列表、True、方法這幾種。

1. find_all(name,attrs,recursive,text,**kwargs)

該方法搜尋當前節點的所有tag子節點。

name引數:
指的是tag的name屬性,字串物件自動忽略。
過濾器可以使用全部種類。

keyword引數:
如果一個入參指定了名字,但是並不是上述提到的入參名字,搜尋時會把該入參當做是tag的屬性來搜尋。例如:
soup.find_all(id=’link2′)
會返回tag中存在屬性id,並且id對應的值是link2的tag。
以上方法可使用除方法之外的所有過濾器。

某些特殊屬性不能這樣直接使用,則使用如下方法:
soup.find_all(attrs={“key”:”value”})

例如要使用class屬性進行搜尋,由於class是python中的保留字,不能直接寫成入參,目前有兩種方法:

class_方法可以使用全部過濾器。
另外,因為class是一個多值屬性,所以只需要匹配一個值,就可以得到結果,所謂的不完全匹配。
使用完全匹配時,過濾器中的字元順序需要和實際相符合才能得到對應結果。

text引數:
搜尋的是Tag中的字串內容,可使用全部過濾器。

limit引數:
限制返回數量。

recursive引數:
find_all()預設是搜尋當前節點的所有子孫節點,若只需要搜尋直接的子節點,則設定recursive=False

find_all()是實際當中用的最廣泛的。
因此有了等價的簡化版:

2. find(name,attrs,recursive,text,**kwargs)

find()方法等價於find_all(limit=1),返回符合條件的第一個物件。
區別在於,前者直接返回結果,後者返回只有一個元素的列表。若沒有物件符合條件,前者返回None,後者返回空列表。

它也有簡化版:

除了find()和find_all()之外還有一些搜尋的方法:

上面三種可以在後面加’s’表示所有。

3. CSS選擇器

Tag或BeautifulSoup物件的.select()方法。


修改文件樹

暫略


輸出

prettify()將文件樹格式化之後輸出。
若不注重格式,則可使用python的str()unicode()

如果想得到tag中包含的文字內容,使用get_text(),可獲取到當前節點的文字,以及子孫節點中的文字。返回的是Unicode。
可以指定引數設定分隔符如get_text(“|”)是以“|”作為分隔符。
get_text(strip=True)可去除文字前後的空白。
或者用.stripped_strings進行遍歷。


文件解析器

BeautifulSoup的第一個入參是文件,第二個入參是文件解析器,預設情況下的優先順序是:lxml, html5lib,python標準庫。其中只有lxml支援xml文件的解析。


編碼

soup使用Unicode編碼。
BeautifulSoup進行了編碼檢測並自動轉為Unicode。
BeautifulSoup物件的.original_encoding屬性來獲取自動識別編碼的結果。
當然這樣比較慢,有時候會出錯。可以在建立BeautifulSoup物件時,指定入參from_encoding來告知文件的編碼方式。

有時候轉碼時有些特殊字元替換成了特殊的Unicode,可通過BeautifulSoup物件的.contains_repalcement_characters屬性來判斷是否有此情況,為True即為有特殊替換。

輸出編碼統一為UTF8,若想要其他的編碼,則和一般的python字串相同,需要進行手動設定。

使用chartdet庫可提高編碼檢測效率。

相關文章