HTML解析大法-Beautiful soup

Beautiful soup是一個(gè)可以從HTML或XML文件中提取數(shù)據(jù)的python庫。在python爬蟲開發(fā)中郎仆,我們主要用到的是Beautiful soup的查找提取功能只祠,修改文檔的方式很少用到。

python用戶可以通過anaconda安裝beautifulsoup4(推薦)扰肌,安裝簡單抛寝,這里不在介紹

安裝完成后铸鹰,接下來講解BeautifulSoup的使用。

1.快速開始

首先導(dǎo)入bs4庫:from bs4 import BeautifulSoup涯贞。

本節(jié)基于上節(jié)獲得網(wǎng)頁請求后扎谎,通過r.text獲得網(wǎng)頁源代碼,即html_str=r.text钻趋。接下來都是基于html_str進(jìn)行數(shù)據(jù)解析和提取川陆。

然后創(chuàng)建BeautifulSoup對象,方法有兩種蛮位,一是直接通過字符串創(chuàng)建:

soup=BeautifulSoup(html_str,'lxml',from_encoding='utf-8')

另一種通過文件來創(chuàng)建较沪,假如將html_str字符串保存為index.html文件,創(chuàng)建方式如下:

soup=BeautifulSoup(open(index.html'))

格式化輸出網(wǎng)頁內(nèi)容

soup.prettify()

2.對象種類

BeautifulSoup將復(fù)雜的HTML文檔轉(zhuǎn)換成一個(gè)復(fù)雜的樹形結(jié)構(gòu)失仁,每個(gè)節(jié)點(diǎn)都是python對象尸曼,所有對象可分為4種:Tag, NavigableString, BeautifulSoup, Comment,接下來依次進(jìn)行介紹。

2.1)Tag

Tag對象就是HTML中的標(biāo)記萄焦,如:<title> The story</title>或<a herf="http://baidu.com",class="sister" id="link1">else</a>控轿,title和a標(biāo)記及其里面的內(nèi)容稱為Tag對象。提取方法為:

抽取title:soup.title

抽取a:soup.a

以上兩個(gè)簡單的方法是查找所有內(nèi)容中第一個(gè)符合要求的標(biāo)記拂封,如果要查詢所有標(biāo)記茬射,且看后續(xù)分解。

Tag中有兩個(gè)重要的屬性:name和attributes冒签。每個(gè)Tag都有自己的名字在抛,通過.name來獲取

soup的name為[document],其他標(biāo)記的名字是標(biāo)記的本身的名稱镣衡。

Tag中具有屬性霜定,如a標(biāo)記中的herf屬性,class屬性和id屬性廊鸥。其使用方式和字典相同:

soup.a['herf']

soup.a.get('herf')

也可以直接用"點(diǎn)"取屬性望浩,比如.attrs,用于獲取Tag中的所有屬性,以字典形式返回:

soup.a.attrs

2.2)NavigableString

標(biāo)記中的內(nèi)容已經(jīng)可以通過Tag獲取惰说,那么其中的文本信息如何獲取呢磨德?需要用到.string:

soup.a.string

2.3)BeautifulSoup

BeautifulSoup對象表示的是一個(gè)文檔的全部內(nèi)容。大部分時(shí)候可以把它當(dāng)作Tag對象吆视,是一個(gè)特殊的Tag典挑。

2.4)Comment

Tag,NavigableString啦吧,BeautifulSoup幾乎覆蓋了HTML和XML中的所有內(nèi)容您觉,但還有一些文檔的注釋部分。

在提取字符串時(shí)授滓,可以判斷一下類型:

if type(soup.a.string)==bs4.element.Comment:

print soup.a.string

3遍歷文檔樹

BeautifulSoup會(huì)將HTML轉(zhuǎn)換成文檔樹進(jìn)行搜索琳水,既然是樹形結(jié)構(gòu)肆糕,必然有節(jié)點(diǎn)。

3.1)子節(jié)點(diǎn)

直接子節(jié)點(diǎn)在孝,Tag中的.contents和.children是非常重要的诚啃。Tag的.contents屬性可以將Tag子節(jié)點(diǎn)以列表的形式輸出.soup.head.contents

字符串沒有.contents屬性,因?yàn)樽址疀]有子節(jié)點(diǎn)私沮。

.children屬性返回一個(gè)生成器始赎,可以對Tag的子節(jié)點(diǎn)進(jìn)行循環(huán):

for children in soup.children:

? ? print(child)

.contents和.children屬性只包含Tag的直接節(jié)點(diǎn)(兒子節(jié)點(diǎn)),不含其他子孫節(jié)點(diǎn);.descendants屬性可以對所有tag的子孫節(jié)點(diǎn)進(jìn)行遞歸循環(huán)仔燕。

for children in soup.descendants:

? ? print(child)

以上都是如何獲取子節(jié)點(diǎn)造垛,也介紹過獲取文本內(nèi)容,.string涨享,.strings筋搏,.stripped_strings三個(gè)屬性。

.string屬性:如果一個(gè)標(biāo)記Tag里面有0個(gè)或1個(gè)標(biāo)記了厕隧,那么返回標(biāo)記里面的內(nèi)容;如果多于一個(gè)標(biāo)記則返回None俄周。

.strings屬性:應(yīng)用于tag中包含多個(gè)字符串的情況吁讨,可以進(jìn)行循環(huán)遍歷,

for string in soup.strings:

? ? print(rear(string))

.stripped_strings屬性可以去掉輸入字符串中包含的空格或空行峦朗,

for string in soup.stripped_strings:

? ? print(rear(string))

3.2)父節(jié)點(diǎn)

每個(gè)Tag都有父節(jié)點(diǎn):被包含在某個(gè)Tag中建丧。

通過.parent屬性來獲取某個(gè)元素的父節(jié)點(diǎn)。通過.parents屬性可以遞歸得到元素的所有父輩節(jié)點(diǎn)波势。

for parent in soup.a.parents:

? ? if parent is None:

? ? ? ? print(parent)

? ? else:

? ? ? ? print(parent.name)

3.3)兄弟節(jié)點(diǎn)

兄弟節(jié)點(diǎn)是和該節(jié)點(diǎn)同一級(jí)的節(jié)點(diǎn)翎朱,.next_sibling屬性可以獲取該節(jié)點(diǎn)的下一個(gè)兄弟節(jié)點(diǎn),.previous_sibling用于獲取上一個(gè)兄弟節(jié)點(diǎn)尺铣,如果不存在則返回None拴曲。

soup.a.next_sibling

soup.a.previous_sibling

通過.next_sibling或.previous_sibling可以對當(dāng)前節(jié)點(diǎn)的兄弟節(jié)點(diǎn)迭代輸出:

for sibling in soup.a.next_siblings:

? ? print(sibling)

3.4)前后節(jié)點(diǎn)

前后節(jié)點(diǎn)需要使用.next_element,.previous_element兩個(gè)屬性凛忿,它們是針對所有節(jié)點(diǎn)澈灼,不分層次。

如果想遍歷所有的前后節(jié)點(diǎn)店溢,通過.next_elements叁熔,.previous_elements的迭代器可以向前或向后訪問文檔解析內(nèi)容

for element in soup.a.next_elements:

? ? print(rear(element))

以上是遍歷文檔樹,接下來講解核心的搜索文檔樹床牧。

4搜索文檔樹

Beautiful Soup定義了多種搜索方法荣回,這里著重介紹find_all()方法。

find_all()方法用于搜索當(dāng)前Tag的所有Tag子節(jié)點(diǎn)戈咳,并判斷是否符合過濾器的條件心软,函數(shù)原型為:

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

1)name參數(shù)

name參數(shù)可以查找所有名字為name的標(biāo)記壕吹,字符串對象會(huì)被自動(dòng)忽略掉。name參數(shù)的取值可以是字符串糯累,正則表達(dá)式算利,列表,True和方法泳姐。

最簡單的是字符串效拭。在搜索方法中傳入一個(gè)字符串參數(shù),查找完整匹配的內(nèi)容胖秒。

soup.find_all('b')#查找所有的<b>標(biāo)記缎患,返回值為列表

傳入正則表達(dá)式作為參數(shù),會(huì)通過正則表達(dá)式的match()來匹配內(nèi)容阎肝,查找以b開頭的標(biāo)記

import re?

for tag in soup.find_all(re.compile('^b')):

? ? print(tag.name)

傳入列表參數(shù)挤渔,返回與列表中任意匹配的內(nèi)容,查找所有的<a>,<b>標(biāo)記:

soup.find_all(['a','b'])

傳入?yún)?shù)為True风题,可以匹配任何值判导,下面代碼會(huì)查找所有的Tag,但不會(huì)返回字符串節(jié)點(diǎn)。

for tag in soup.find_all(True):

? ? print(tag.name)

如果沒有合適的過濾器沛硅,還可以定義一個(gè)方法眼刃,方法只接受一個(gè)元素參數(shù)Tag節(jié)點(diǎn),如果方法返回True表示當(dāng)前元素匹配并且被找到摇肌,如果返回false擂红。

2)kwargs參數(shù)

kwargs參數(shù)在python中表示為keyword參數(shù)。如果一個(gè)指定名字的參數(shù)不是搜索內(nèi)置的參數(shù)名围小,搜索時(shí)會(huì)把該參數(shù)當(dāng)作指定名字Tag屬性來搜索昵骤。搜索指定名字的屬性時(shí)可以使用的參數(shù)值包括字符串,正則表達(dá)式肯适,列表变秦,True.(常用來通過屬性搜索)

soup.find_all(id='link2')#搜索每個(gè)標(biāo)記,id屬性為'link2'疹娶,返回列表

傳入正則表達(dá)式

import re

soup.find_all(herf=re.compile('elsie'))#查找herf屬性中包含'elsie'的標(biāo)記

查找含有id屬性的標(biāo)記

soup.find_all(id=True)

若想用python的關(guān)鍵字重復(fù)的屬性過濾伴栓,可以在后面加上下劃線,如class

soup.find_all('a',class_='sister')

使用多個(gè)指定名字的參數(shù)可以同時(shí)過濾tag的多個(gè)屬性:

soup.find_all(herf=re.compile("elsie"),id='link1')

3)text參數(shù)

通過text參數(shù)可以搜索文檔中的字符串內(nèi)容雨饺。與name參數(shù)的可選值一樣钳垮,text ? ?參數(shù)接受字符串,正則表達(dá)式额港,列表饺窿,True。

soup.find_all(text='Elsie')

soup.find_all(text=['Tille','Elsie'])

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末移斩,一起剝皮案震驚了整個(gè)濱河市肚医,隨后出現(xiàn)的幾起案子绢馍,更是在濱河造成了極大的恐慌,老刑警劉巖肠套,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舰涌,死亡現(xiàn)場離奇詭異,居然都是意外死亡你稚,警方通過查閱死者的電腦和手機(jī)瓷耙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刁赖,“玉大人搁痛,你說我怎么就攤上這事∮畛冢” “怎么了鸡典?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長枪芒。 經(jīng)常有香客問我彻况,道長,這世上最難降的妖魔是什么舅踪? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任疗垛,我火速辦了婚禮,結(jié)果婚禮上硫朦,老公的妹妹穿的比我還像新娘。我一直安慰自己背镇,他們只是感情好咬展,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瞒斩,像睡著了一般破婆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上胸囱,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天祷舀,我揣著相機(jī)與錄音,去河邊找鬼烹笔。 笑死裳扯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谤职。 我是一名探鬼主播饰豺,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼允蜈!你這毒婦竟也來了冤吨?” 一聲冷哼從身側(cè)響起蒿柳,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎漩蟆,沒想到半個(gè)月后垒探,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怠李,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年圾叼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扔仓。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡褐奥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出翘簇,到底是詐尸還是另有隱情撬码,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布版保,位于F島的核電站呜笑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏彻犁。R本人自食惡果不足惜叫胁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望汞幢。 院中可真熱鬧驼鹅,春花似錦、人聲如沸森篷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仲智。三九已至买乃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钓辆,已是汗流浹背剪验。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留前联,地道東北人功戚。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像蛀恩,于是被迫代替她去往敵國和親疫铜。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350