最近一直在用BeautifulSoup,但是語法很容易忘記。在這裡做個學習總結吧。
參考:
功能
BeautifulSoup是用來從HTML或XML中提取資料的Python庫。
匯入
使用方法:
1 2 |
from bs4 import BeautifulSoup soup = BeautifulSoup(html) |
編碼
soup使用Unicode編碼。
物件種類
有四種型別:Tag,NavigableString,BeautifulSoup,Comment。
BeautifulSoup將文件轉化為樹形結構,每個節點都是上述四種型別的Python物件。
1.Tag
與XML和HTML中Tag物件相同。
如:
soup = BeautifulSoup(Extremely bold)
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,如:
1 2 3 4 |
css_soup = BeautifulSoup(' ') css_soup.p['class'] |
輸出:[“body”, “strikeout”]
這種多個值的屬性是需要在HTML中有定義的,如果並沒有被定義為多值屬性,則返回字串:
1 2 |
id_soup = BeautifulSoup('') id_soup.p['id'] |
輸出‘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. 兄弟節點
擁有同一父節點的節點之間。
1 2 |
.next_sibling .previous_sibling |
同理,所有兄弟節點:
1 2 |
.next_siblings .previous_siblings |
指向下一個或上一個解析物件:
1 2 3 4 |
.next_element .previous_element .next_elements .previous_elements |
搜尋文件樹
經常使用的兩種方法: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中的保留字,不能直接寫成入參,目前有兩種方法:
1 2 |
soup.find_all('tag.name',class_='class_value') soup.find_all('tag.name',attrs={'class':'class_value'}) |
class_方法可以使用全部過濾器。
另外,因為class是一個多值屬性,所以只需要匹配一個值,就可以得到結果,所謂的不完全匹配。
使用完全匹配時,過濾器中的字元順序需要和實際相符合才能得到對應結果。
text引數:
搜尋的是Tag中的字串內容,可使用全部過濾器。
limit引數:
限制返回數量。
recursive引數:
find_all()預設是搜尋當前節點的所有子孫節點,若只需要搜尋直接的子節點,則設定recursive=False。
find_all()是實際當中用的最廣泛的。
因此有了等價的簡化版:
1 2 |
soup.find_all('a') soup('a') |
2. find(name,attrs,recursive,text,**kwargs)
find()方法等價於find_all(limit=1),返回符合條件的第一個物件。
區別在於,前者直接返回結果,後者返回只有一個元素的列表。若沒有物件符合條件,前者返回None,後者返回空列表。
它也有簡化版:
1 2 |
soup.find('head').find('title') soup.head.title |
除了find()和find_all()之外還有一些搜尋的方法:
1 2 3 |
find_parent() find_next_sibling() find_previous_sibling() |
上面三種可以在後面加’s’表示所有。
1 2 3 4 |
find_next() find_previous() find_all_next() find_all_previous() |
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庫可提高編碼檢測效率。