最近一直在用BeautifulSoup,但是語法很容易忘記。在這里做個學習總結吧。
參考:
功能
BeautifulSoup是用來從HTML或XML中提取數(shù)據(jù)的Python庫。
導入
使用方法:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html)
編碼
soup使用Unicode編碼。
對象種類
有四種類型:Tag,NavigableString,BeautifulSoup,Comment。
BeautifulSoup將文檔轉(zhuǎn)化為樹形結構,每個節(jié)點都是上述四種類型的Python對象。
1.Tag
與XML和HTML中Tag對象相同。
如:
soup = BeautifulSoup(<b class="boldest">Extremely bold</b>)
soup.b就是一個Tag對象。
Name
tag.name 可獲取,可更改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,如:
css_soup = BeautifulSoup('<p class="body strikeout"></p>')
css_soup.p['class']
輸出:["body", "strikeout"]
這種多個值的屬性是需要在HTML中有定義的,如果并沒有被定義為多值屬性,則返回字符串:
id_soup = BeautifulSoup('<p id="my id"></p>')
id_soup.p['id']
輸出'my id'
如果轉(zhuǎn)換的是XML文檔,則不會存在多值屬性,返回字符串。
可以使用list或字符串對屬性賦值。
2. NavigableString
Tag中的字符串即為NavigableString對象。
tag.string
在BeautifulSoup之外使用該類型,推薦轉(zhuǎn)換為Unicode:
unicode(Tag.string)
tag中包含的字符串不可編輯,只能替換:
tag.string.replace_with(new string)
tag能夠包含其他tag或字符串,而NavigableString則不能包含其他對象。不支持.content,.string,find(),只支持部分遍歷文檔樹和搜索文檔樹中的屬性。
3. BeautifulSoup
表示的是一個文檔的全部內(nèi)容,大部分情況可當做Tag對象,支持遍歷文檔樹和搜索文檔樹的大部分屬性。
而在HTML或XML中并沒有叫做BeautifulSoup的Tag,所以并沒有name和attribute屬性,但是有個特殊屬性:
soup.name
輸出u'[document]'
4. Comment
Comment類型是NavigableString類型的子類,BeautifulSoup中也有同樣道理的一些其他類型。
遍歷文檔樹
BeautifulSoup對象作為一棵樹,有多個節(jié)點。對于一個節(jié)點,相對于它所在的位置,有子節(jié)點、父節(jié)點、兄弟節(jié)點。
1. 子節(jié)點
一個Tag可包含多個Tag以及字符串,這些都是這個Tag的子節(jié)點。而NavigableString不會有子節(jié)點。
如果想要獲得某個Tag,上述已提到方法:
soup.tag_name
通過點取屬性,只能獲得當前名字的第一個tag,若要獲取所有,需要使用搜索文檔樹中的方法:
soup.find_all('tag_name')
tag的.contents屬性可將所有子節(jié)點以列表的方式輸出。
可通過tag的.children生成器,對所有子節(jié)點進行遍歷。
.contents和.children只對獲取Tag的直接子節(jié)點,.descendants可用于對Tag的所有子孫節(jié)點進行遍歷。
如果tag只有一個NavigableString類型子節(jié)點,則可用.string獲取。如果包含多個,使用.strings遍歷。若輸出的字符串中包含空格或空行,使用.stripped_strings去除。
2. 父節(jié)點
當前節(jié)點的父節(jié)點:.parent
當前節(jié)點的所有父輩節(jié)點:.parents
3. 兄弟節(jié)點
擁有同一父節(jié)點的節(jié)點之間。
.next_sibling
.previous_sibling
同理,所有兄弟節(jié)點:
.next_siblings
.previous_siblings
指向下一個或上一個解析對象:
.next_element
.previous_element
.next_elements
.previous_elements
搜索文檔樹
經(jīng)常使用的兩種方法:find(str)和find_all(str)。
其中的str,代表了tag的name。可以是純字符串、正則表達式、列表(任一匹配就滿足條件,是或運算)、True(返回所有Tag節(jié)點不返回字符串節(jié)點)。
另一種入?yún)⒉皇莝tr,而是method。此方法是一個函數(shù),只接受一個元素入?yún)?,若此函?shù)返回True表示入?yún)⑵ヅ湟?。例如?br>
*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)
該方法搜索當前節(jié)點的所有tag子節(jié)點。
name參數(shù):
指的是tag的name屬性,字符串對象自動忽略。
過濾器可以使用全部種類。
keyword參數(shù):
如果一個入?yún)⒅付嗣郑遣⒉皇巧鲜鎏岬降娜雲(yún)⒚?,搜索時會把該入?yún)斪鍪莟ag的屬性來搜索。例如:
soup.find_all(id='link2')
會返回tag中存在屬性id,并且id對應的值是link2的tag。
以上方法可使用除方法之外的所有過濾器。
某些特殊屬性不能這樣直接使用,則使用如下方法:
soup.find_all(attrs={"key":"value"})
例如要使用class屬性進行搜索,由于class是python中的保留字,不能直接寫成入?yún)?,目前有兩種方法:
soup.find_all('tag.name',class_='class_value')
soup.find_all('tag.name',attrs={'class':'class_value'})
class_方法可以使用全部過濾器。
另外,因為class是一個多值屬性,所以只需要匹配一個值,就可以得到結果,所謂的不完全匹配。
使用完全匹配時,過濾器中的字符順序需要和實際相符合才能得到對應結果。
text參數(shù):
搜索的是Tag中的字符串內(nèi)容,可使用全部過濾器。
limit參數(shù):
限制返回數(shù)量。
recursive參數(shù):
find_all()默認是搜索當前節(jié)點的所有子孫節(jié)點,若只需要搜索直接的子節(jié)點,則設置recursive=False。
find_all()是實際當中用的最廣泛的。
因此有了等價的簡化版:
soup.find_all('a')
soup('a')
2. find(name,attrs,recursive,text,**kwargs)
find()方法等價于find_all(limit=1),返回符合條件的第一個對象。
區(qū)別在于,前者直接返回結果,后者返回只有一個元素的列表。若沒有對象符合條件,前者返回None,后者返回空列表。
它也有簡化版:
soup.find('head').find('title')
soup.head.title
除了find()和find_all()之外還有一些搜索的方法:
find_parent()
find_next_sibling()
find_previous_sibling()
上面三種可以在后面加's'表示所有。
find_next()
find_previous()
find_all_next()
find_all_previous()
3. CSS選擇器
Tag或BeautifulSoup對象的.select()方法。
修改文檔樹
暫略
輸出
prettify()將文檔樹格式化之后輸出。
若不注重格式,則可使用python的str()或unicode()。
如果想得到tag中包含的文本內(nèi)容,使用get_text(),可獲取到當前節(jié)點的文本,以及子孫節(jié)點中的文本。返回的是Unicode。
可以指定參數(shù)設置分隔符如get_text("|")是以“|”作為分隔符。
get_text(strip=True)可去除文本前后的空白。
或者用.stripped_strings進行遍歷。
文檔解析器
BeautifulSoup的第一個入?yún)⑹俏臋n,第二個入?yún)⑹俏臋n解析器,默認情況下的優(yōu)先順序是:lxml, html5lib,python標準庫。其中只有l(wèi)xml支持xml文檔的解析。
編碼
soup使用Unicode編碼。
BeautifulSoup進行了編碼檢測并自動轉(zhuǎn)為Unicode。
BeautifulSoup對象的.original_encoding屬性來獲取自動識別編碼的結果。
當然這樣比較慢,有時候會出錯??梢栽趧?chuàng)建BeautifulSoup對象時,指定入?yún)rom_encoding來告知文檔的編碼方式。
有時候轉(zhuǎn)碼時有些特殊字符替換成了特殊的Unicode,可通過BeautifulSoup對象的.contains_repalcement_characters屬性來判斷是否有此情況,為True即為有特殊替換。
輸出編碼統(tǒng)一為UTF8,若想要其他的編碼,則和一般的python字符串相同,需要進行手動設置。
使用chartdet庫可提高編碼檢測效率。