基礎(chǔ)學(xué)習(xí)——BeautifulSoup篇(1)

BeautifulSoup 是一個(gè)可以從HTML或XML文件中提取數(shù)據(jù)的Python庫群嗤。它能夠通過你喜歡的轉(zhuǎn)換器實(shí)現(xiàn)慣用的文檔導(dǎo)航,查找,修改文檔的方式畅铭。換句話說氏淑,它是我們解析網(wǎng)頁的利器

BeautifulSoup3 目前已經(jīng)停止開發(fā),今天學(xué)習(xí)的是BeautifulSoup4

1.簡單入手

我們以豆瓣網(wǎng)為例,編輯下面這段代碼

from bs4 import BeautifulSoup
import requests
if __name__ == "__main__":
     req = requests.get("https://www.douban.com/") #獲取豆瓣網(wǎng)址
     html = req.text #獲得網(wǎng)頁源代碼
     soup = BeautifulSoup(html) 
     print(soup.prettify())

首先通過一個(gè)requests.get()來獲得目標(biāo)網(wǎng)址的信息硕噩,再通過req.text獲得網(wǎng)頁源代碼假残,之后就可以利用BeautifulSoup來對源碼進(jìn)行解析。這里進(jìn)行操作后榴徐,你可能會(huì)有這樣的疑問,print(html)print(soup.prettify())的輸出結(jié)果不是一樣嗎匀归?確實(shí)看輸出結(jié)果是這樣的坑资,好像沒什么區(qū)別,其實(shí)兩者是不一樣的穆端,前者只是單純的輸出網(wǎng)頁源碼袱贮,后者是將網(wǎng)頁源碼解析后模塊化輸出,仔細(xì)看一下輸出結(jié)果你會(huì)發(fā)現(xiàn)些許差別体啰。沒發(fā)現(xiàn)也沒有關(guān)系攒巍,下面我們來對解析后的網(wǎng)頁進(jìn)行操作嗽仪。

接著上面的代碼塊操作

     print(soup.title) #輸出<title>標(biāo)簽
     print(soup.title.name) #輸出title的name
     print(soup.title.string) #輸出title的內(nèi)容
     print(soup.title.parent.name) #輸出title父節(jié)點(diǎn)的name
     print(soup.p) #輸出<p>標(biāo)簽
     print(soup.p['class']) #輸出<p>標(biāo)簽的類
     print(soup.a) #輸出<a>標(biāo)簽
     print(soup.find_all('a')) #找到所有的<a>標(biāo)簽
     print(soup.find(id="anony-time")) #找到所有的id為anony-time標(biāo)簽
     print(soup.find_all('p',class_="app-title")) #找到所有class為app-title的<a>標(biāo)簽

自己操作實(shí)現(xiàn)一下,你就能對BeautifulSoup的功能有著更深入的了解柒莉。其實(shí)不限于此闻坚,BeautifulSoup能做的還有更多,比如它可以提取網(wǎng)頁中的鏈接

     #提取網(wǎng)頁所有<a>標(biāo)簽里的鏈接
     for link in soup.find_all('a'):
         print(link.get('href'))

對這段代碼稍加限定條件就可以提取到指定<a>標(biāo)簽的鏈接兢孝,比如soup.find_all('a',class_='lnk-book')就可以查找所有類別為lnk-book<a>標(biāo)簽

我們也可以通過下面的操作來獲得網(wǎng)頁所有的文字內(nèi)容

print(soup.get_text())

2.BeautifulSoup——解析器

在前面的代碼塊中有一行代碼是這樣的soup = BeautifulSoup(html)這行代碼其實(shí)不是很規(guī)范窿凤,一般會(huì)在后面補(bǔ)充一個(gè)解析器,變成這樣soup = BeautifulSoup(html,'lxml')跨蟹。BeautifulSoup支持Python標(biāo)準(zhǔn)庫中的HTML解析器雳殊,還支持一些第三方的解析器,它一共有這么幾種

解析器 使用方法 優(yōu)勢 劣勢
Python標(biāo)準(zhǔn)庫 BeautifulSoup(markup, "html.parser") Python的內(nèi)置標(biāo)準(zhǔn)庫
執(zhí)行速度適
文檔容錯(cuò)能力強(qiáng)
Python 2.7.3 or 3.2.2)前 的版本中文檔容錯(cuò)能力差
lxml HTML 解析器 BeautifulSoup(markup, "lxml") 速度快
唯一支持XML的解析器
需要安裝C語言庫
lxml XML 解析器 BeautifulSoup(markup, ["lxml", "xml"])
BeautifulSoup(markup, "xml")
速度快
唯一支持XML的解析器
需要安裝C語言庫
html5lib BeautifulSoup(markup, "html5lib") 最好的容錯(cuò)性
以瀏覽器的方式解析文檔
生成HTML5格式的文檔
速度慢
不依賴外部擴(kuò)展

推薦使用lxml作為解析器,因?yàn)樾矢? 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必須安裝lxmlhtml5lib, 因?yàn)槟切㏄ython版本的標(biāo)準(zhǔn)庫中內(nèi)置的HTML解析方法不夠穩(wěn)定窗轩。

3.對象

BeautifulSoup將復(fù)雜HTML文檔轉(zhuǎn)換成一個(gè)復(fù)雜的樹形結(jié)構(gòu)夯秃,每個(gè)節(jié)點(diǎn)都是Python對象,所有對象可以歸納為4種: Tag , NavigableString , BeautifulSoup,Comment .

3.1Tag

在前面的操作中痢艺,實(shí)際上我們已經(jīng)見識(shí)了解析后的tag仓洼,解析后的網(wǎng)頁都是由一個(gè)個(gè)的tag組成的。

     soup = BeautifulSoup(html,'lxml')
     print(soup.title) #輸出了<title>這個(gè)tag

每一個(gè)tag都有自己的name腹备,我們可以查看

     print(soup.title.name) #輸出title的name

每一個(gè)tag都有自己的屬性衬潦,比如<li> <a target="_blank" class="lnk-book" href="[https://book.douban.com](https://book.douban.com/)">豆瓣讀書</a></li>,我們可以查看

     soup = BeautifulSoup('<li> <a target="_blank" class="lnk-book" href=" 
     [https://book.douban.com](https://book.douban.com/)">豆瓣讀書</a></li>','lxml') 
     print(soup.a['target']) #查看target屬性
     print(soup.a['class']) #查看class屬性
     print(soup.a['href']) #查看href屬性

這里也就是我們上面獲取<a>標(biāo)簽里面鏈接的原理植酥,也可以直接查看它的所有屬性

     print(soup.a.attrs)

另外镀岛,tag里面的屬性也是可以操作的,可以刪除和修改友驮,和字典操作是一樣的

     soup.a['target'] = 'white' #修改
     del soup.a['class'] #刪除
     print(soup.a['target'])
     print(bool(soup.a['class'])) #這一步會(huì)報(bào)錯(cuò)漂羊,因?yàn)橐呀?jīng)被刪掉了

熟悉html的童鞋還會(huì)知道另外一個(gè)問題,就是有些html會(huì)有多值屬性卸留,比如<a class="lnk-book ink-book">豆瓣讀書</a>

     soup = BeautifulSoup('<a class="lnk-book ink-book">豆瓣讀書</a>','lxml')    
     print(soup.a['class'])
#['lnk-book', 'ink-book']

會(huì)發(fā)現(xiàn)走越,BeautifulSoup會(huì)自動(dòng)的區(qū)分開多值屬性,并以list的形式返回耻瑟,但是當(dāng)你將tag轉(zhuǎn)換為string字符串時(shí)旨指,它就會(huì)自動(dòng)將他們的多值屬性合并到一起。

3.2NavigableString

NavigableString是一個(gè)類喳整,用來包裝tag中的字符串谆构,一個(gè) NavigableString 字符串與Python中的Unicode字符串相同。tag中包含的字符串不能編輯,但是可以被替換成其它的字符串框都。

soup = BeautifulSoup('<a class="lnk-book ink-book">豆瓣讀書</a>','lxml')    
soup.a.string.replace_with('walt white')
print(soup.a)
#<a class="lnk-book ink-book">walt white</a>

3.3BeautifulSoup

BeautifulSoup 對象表示的是一個(gè)文檔的全部內(nèi)容搬素。大部分時(shí)候,可以把它當(dāng)作 Tag 對象。上一段代碼中的soup就是一個(gè)BeautifulSoup對象熬尺。

3.4Comment

comment其實(shí)顧名思義就是注釋的意思摸屠,它是NavigableString一個(gè)特殊子類,用來表示html中的注釋

soup = BeautifulSoup('<b><!--Hey, how you\'re doing ?--></b>','lxml')
comment = soup.b.string
print(comment)

注意這段代碼粱哼,輸出結(jié)果是Hey, how you're doing ?季二,而不是html的代碼中的``,已經(jīng)自動(dòng)過濾了注釋標(biāo)簽了

4.遍歷文檔樹

這里用一段官網(wǎng)給出的文檔來做例子

from bs4 import BeautifulSoup
if __name__ == "__main__":
     html_doc = """
        <html><head><title>The Dormouse's story</title></head>
        <p class="title"><b>The Dormouse's story</b></p>
        <p class="story">Once upon a time there were three little sisters; and their names were
        <a  class="sister" id="link1">Elsie</a>,
        <a  class="sister" id="link2">Lacie</a> and
        <a  class="sister" id="link3">Tillie</a>;
        and they lived at the bottom of a well.</p>
        <p class="story">...</p>
        """
     soup = BeautifulSoup(html_doc,'lxml')

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

我們可以通過這樣的方法來獲取節(jié)點(diǎn)中的子節(jié)點(diǎn)

     print(soup.body.b)

這樣通過點(diǎn)取的方法只能獲取第一個(gè)元素皂吮,如果需要獲取全部的標(biāo)簽戒傻,則需要通過另外一種方法

     print(soup.find_all('a'))

它可以通過列表的形式輸出所有的標(biāo)簽

4.2.contents

利用.contents可以來將子節(jié)點(diǎn)以列表的形式輸出

     soup = BeautifulSoup(html_doc,'lxml')
     head_tag = soup.head
     title_tag = head_tag.contents[0]
     print(title_tag)
     print(title_tag.contents)

通過結(jié)果可以看到.contents輸出了了當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn),并用列表的形式輸出蜂筹,直到到最后一個(gè)字符串節(jié)點(diǎn)需纳,無法再往下遍歷

4.3.children

利用.children操作也可以遍歷子節(jié)點(diǎn)

     soup = BeautifulSoup(html_doc,'lxml')
     title_tag = soup.head.contents[0]
     for child in title_tag.children:
         print(child)

4.4.descendants

利用.descendants操作也可以遍歷子孫節(jié)點(diǎn)

     for child in title_tag.descendants:
         print(child)

4.5.string

如果tag有且僅有一個(gè)子節(jié)點(diǎn),利用.string可以得到子節(jié)點(diǎn)的內(nèi)容艺挪,但是tag如果有多個(gè)子節(jié)點(diǎn)不翩,那么會(huì)輸出none

     print(title_tag.string)
     print(soup.string)
#The Dormouse's story
#None

4.6.strings 和 stripped_strings

如果tag中包含多個(gè)字符串 ,可以使用 .strings來循環(huán)獲取

     for string in soup.strings:
         print(repr(string))
#"The Dormouse's story"
#'\n'
#"The Dormouse's story"
#'\n'
#'Once upon a time there were three little sisters; and their names were\n        '
#'Elsie'
#',\n        '
#'Lacie'
#' and\n        '
#'Tillie'
#';\n        and they lived at the bottom of a well.'
#'\n'
#'...'
#'\n'

輸出的字符串中可能包含了很多空格或空行麻裳,使用 .stripped_strings可以去除多余空白內(nèi)容:

     for string in soup..stripped_strings:
         print(repr(string))
#"The Dormouse's story"
#"The Dormouse's story"
#'Once upon a time there were three little sisters; and their names were'
#'Elsie'
#','
#'Lacie'
#'and'
#'Tillie'
#';\n        and they lived at the bottom of a well.'
#'...'

今天的學(xué)習(xí)就到這里了口蝠,BeautifulSoup篇學(xué)習(xí)還沒有結(jié)束,后面還會(huì)繼續(xù)

歡迎關(guān)注公眾號(hào):老白和他的爬蟲

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末津坑,一起剝皮案震驚了整個(gè)濱河市妙蔗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疆瑰,老刑警劉巖眉反,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異穆役,居然都是意外死亡寸五,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門耿币,熙熙樓的掌柜王于貴愁眉苦臉地迎上來梳杏,“玉大人,你說我怎么就攤上這事淹接∈裕” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵塑悼,是天一觀的道長劲适。 經(jīng)常有香客問我,道長拢肆,這世上最難降的妖魔是什么减响? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮郭怪,結(jié)果婚禮上支示,老公的妹妹穿的比我還像新娘。我一直安慰自己鄙才,他們只是感情好颂鸿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著攒庵,像睡著了一般嘴纺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上浓冒,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天栽渴,我揣著相機(jī)與錄音,去河邊找鬼稳懒。 笑死闲擦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的场梆。 我是一名探鬼主播墅冷,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼或油!你這毒婦竟也來了寞忿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤顶岸,失蹤者是張志新(化名)和其女友劉穎腔彰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜕琴,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡萍桌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凌简。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片上炎。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖雏搂,靈堂內(nèi)的尸體忽然破棺而出藕施,到底是詐尸還是另有隱情,我是刑警寧澤凸郑,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布裳食,位于F島的核電站,受9級特大地震影響芙沥,放射性物質(zhì)發(fā)生泄漏诲祸。R本人自食惡果不足惜浊吏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望救氯。 院中可真熱鬧找田,春花似錦、人聲如沸着憨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽甲抖。三九已至漆改,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間准谚,已是汗流浹背挫剑。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留柱衔,地道東北人暮顺。 一個(gè)月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像秀存,于是被迫代替她去往敵國和親捶码。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容