爬蟲框架
-
BeautifulSoup
-
功能
BeautifulSoup是用來從HTML或XML中提取數(shù)據(jù)的Python庫。 - 導(dǎo)入
-
使用方法:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html) -
對象種類
有四種類型:Tag,NavigableString婿滓,BeautifulSoup色难,Comment肉瓦。
BeautifulSoup將文檔轉(zhuǎn)化為樹形結(jié)構(gòu)梅忌,每個節(jié)點都是上述四種類型的Python對象嘲玫。
-
Tag
與XML和HTML中Tag對象相同娇钱。
如:
soup = BeautifulSoup(<b class="boldest">Extremely bold</b>)
soup.b就是一個Tag對象伤柄。-
Name
tag.name 可獲取,可更改
-
Name
-
Attribute
一個Tag對象可以有多個屬性文搂,操作方法和字典相同适刀,如上述Tag對象b就有一個class屬性:
soup.b['class']
或者使用get方法soup.b.get('class')
獲取所有屬性鍵值對:
soup.b.attrs
tag的屬性可添加、刪除(del soup.b['class'])煤蹭、修改笔喉,和字典方法相同。
如果一個屬性key對應(yīng)多個value硝皂,則返回一個value的list常挚,如:
-
Attribute
css_soup = BeautifulSoup('<p class="body strikeout" name="lzy"></p>')
print css_soup.p.attrs
輸出:{'class': ['body', 'strikeout'], 'name': 'lzy'}
這種多個值的屬性是需要在HTML中有定義的,如果并沒有被定義為多值屬性吧彪,則返回字符串:
id_soup = BeautifulSoup('')
id_soup.p['id']
輸出'my id'
如果轉(zhuǎn)換的是XML文檔待侵,則不會存在多值屬性,返回字符串姨裸。
可以使用list或字符串對屬性賦值秧倾。
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()慷垮,只支持部分遍歷文檔樹和搜索文檔樹中的屬性揖闸。BeautifulSoup
表示的是一個文檔的全部內(nèi)容,大部分情況可當(dāng)做Tag對象料身,支持遍歷文檔樹和搜索文檔樹的大部分屬性汤纸。
而在HTML或XML中并沒有叫做BeautifulSoup的Tag,所以并沒有name和attribute屬性芹血,但是有個特殊屬性:
soup.name
輸出u'[document]'
-
Comment
Comment類型是NavigableString類型的子類贮泞,BeautifulSoup中也有同樣道理的一些其他類型楞慈。
<a class="sister" id="link1"><!-- Elsie --></a>
Elsie
<class 'bs4.element.Comment'>
我們在使用前最好做一下判斷,判斷代碼如下
if type(soup.a.string)==bs4.element.Comment:
print soup.a.string
-
遍歷文檔樹
BeautifulSoup對象作為一棵樹啃擦,有多個節(jié)點囊蓝。對于一個節(jié)點,相對于它所在的位置令蛉,有子節(jié)點聚霜、父節(jié)點、兄弟節(jié)點言询。
- 子節(jié)點
一個Tag可包含多個Tag以及字符串俯萎,這些都是這個Tag的子節(jié)點傲宜。而NavigableString不會有子節(jié)點运杭。
如果想要獲得某個Tag,上述已提到方法:
soup.tag_name
通過點取屬性函卒,只能獲得當(dāng)前名字的第一個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
去除车伞。 -
父節(jié)點
當(dāng)前節(jié)點的父節(jié)點:.parent
當(dāng)前節(jié)點的所有父輩節(jié)點:.parents -
兄弟節(jié)點
擁有同一父節(jié)點的節(jié)點之間。
.next_sibling
.previous_sibling
同理喻喳,所有兄弟節(jié)點:
.next_siblings
.previous_siblings
指向下一個或上一個解析對象:不區(qū)分層級
.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)⑵ヅ湟笊耗ぁ@纾?/li>
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
綜上,過濾器包括:純字符串宣脉、正則表達式车柠、列表、True塑猖、方法這幾種竹祷。
- find_all(name,attrs,recursive,text,kwargs)
該方法搜索當(dāng)前節(jié)點的所有tag子節(jié)點。**
- name參數(shù):
指的是tag的name屬性羊苟,字符串對象自動忽略塑陵。
過濾器可以使用全部種類。
- keyword參數(shù):
如果一個入?yún)⒅付嗣掷遣⒉皇巧鲜鎏岬降娜雲(yún)⒚至罨ǎ阉鲿r會把該入?yún)?dāng)做是tag的屬性來搜索。例如:
soup.find_all(id='link2')
會返回tag中存在屬性id凉倚,并且id對應(yīng)的值是link2的tag兼都。
以上方法可使用除方法之外的所有過濾器。
- 某些特殊屬性不能這樣直接使用稽寒,則使用如下方法:
soup.find_all(attrs={"key":"value"})
例如要使用class屬性進行搜索扮碧,由于class是python中的保留字,不能直接寫成入?yún)⑿硬冢壳坝袃煞N方法:
soup.find_all('tag.name',class_='class_value')
soup.find_all('tag.name',attrs={'class':'class_value'})
class_方法可以使用全部過濾器慎王。
另外,因為class是一個多值屬性搔啊,所以只需要匹配一個值柬祠,就可以得到結(jié)果,所謂的不完全匹配负芋。
使用完全匹配時漫蛔,過濾器中的字符順序需要和實際相符合才能得到對應(yīng)結(jié)果。
- text參數(shù):
搜索的是Tag中的字符串內(nèi)容旧蛾,可使用全部過濾器莽龟。
- limit參數(shù):
限制返回數(shù)量。
- recursive參數(shù):
find_all()默認(rèn)是搜索當(dāng)前節(jié)點的所有子孫節(jié)點锨天,若只需要搜索直接的子節(jié)點毯盈,則設(shè)置recursive=False
。
find_all()是實際當(dāng)中用的最廣泛的病袄。
因此有了等價的簡化版:
soup('a')```
2. find(name,attrs,recursive,text,**kwargs)
find()方法等價于find_all(limit=1)搂赋,返回符合條件的第一個對象赘阀。
區(qū)別在于,前者直接返回結(jié)果脑奠,后者返回只有一個元素的列表基公。若沒有對象符合條件,前者返回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()方法齿诞。
7. **輸出**
prettify()將文檔樹格式化之后輸出酸休。
若不注重格式,則可使用python的str()或unicode()祷杈。
如果想得到tag中包含的文本內(nèi)容斑司,使用get_text(),可獲取到當(dāng)前節(jié)點的文本吠式,以及子孫節(jié)點中的文本陡厘。返回的是Unicode抽米。
可以指定參數(shù)設(shè)置分隔符如get_text("|")是以“|”作為分隔符特占。
get_text(strip=True)可去除文本前后的空白。
或者用.stripped_strings進行遍歷云茸。
7. **文檔解析器**
BeautifulSoup的第一個入?yún)⑹俏臋n是目,第二個入?yún)⑹俏臋n解析器,默認(rèn)情況下的優(yōu)先順序是:lxml标捺, html5lib懊纳,python標(biāo)準(zhǔn)庫。其中只有l(wèi)xml支持xml文檔的解析亡容。