python爬蟲之BeautifulSoup

python爬蟲之BeautifulSoup

簡介

Beautiful Soup提供一些簡單的、python式的函數(shù)用來處理導(dǎo)航、搜索刷后、修改分析樹等功能吃靠。它是一個工具箱硫眨,通過解析文檔為用戶提供需要抓取的數(shù)據(jù),因為簡單巢块,所以不需要多少代碼就可以寫出一個完整的應(yīng)用程序礁阁。Beautiful Soup自動將輸入文檔轉(zhuǎn)換為Unicode編碼巧号,輸出文檔轉(zhuǎn)換為utf-8編碼。你不需要考慮編碼方式氮兵,除非文檔沒有指定一個編碼方式裂逐,這時,Beautiful Soup就不能自動識別編碼方式了泣栈。然后卜高,你僅僅需要說明一下原始編碼方式就可以了。
Beautiful Soup已成為和lxml南片、html6lib一樣出色的python解釋器掺涛,為用戶靈活地提供不同的解析策略或強勁的速度。

安裝

  • pip install BeautifulSoup4
  • easy_install BeautifulSoup4

創(chuàng)建BeautifulSoup對象

  • 首先應(yīng)該導(dǎo)入BeautifulSoup類庫 from bs4 import BeautifulSoup
  • 下面開始創(chuàng)建對像疼进,在開始之前為了方便演示薪缆,先創(chuàng)建一個html文本,如下:
html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><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>
"""
  • 創(chuàng)建對象:soup=BeautifulSoup(html,'lxml'),這里的lxml是解析的類庫伞广,目前來說個人覺得最好的解析器了拣帽,一直在用這個,安裝方法:pip install lxml

Tag

Tag就是html中的一個標(biāo)簽嚼锄,用BeautifulSoup就能解析出來Tag的具體內(nèi)容减拭,具體的格式為soup.name,其中namehtml下的標(biāo)簽,具體實例如下:

  • print soup.title輸出title標(biāo)簽下的內(nèi)容区丑,包括此標(biāo)簽拧粪,這個將會輸出<title>The Dormouse's story</title>
  • print soup.head

注意:

這里的格式只能獲取這些標(biāo)簽的第一個,后面會講到獲取多個標(biāo)簽的方法沧侥。其中對于Tag有兩個重要的屬性nameattrs,分別表示名字和屬性,介紹如下:

  • name:對于Tag可霎,它的name就是其本身,如soup.p.name就是p
  • attrs是一個字典類型的宴杀,對應(yīng)的是屬性-值癣朗,如print soup.p.attrs,輸出的就是{'class': ['title'], 'name': 'dromouse'},當(dāng)然你也可以得到具體的值,如print soup.p.attrs['class'],輸出的就是[title]是一個列表的類型旺罢,因為一個屬性可能對應(yīng)多個值,當(dāng)然你也可以通過get方法得到屬性的斯棒,如:print soup.p.get('class')。還可以直接使用print soup.p['class']

get

get方法用于得到標(biāo)簽下的屬性值主经,注意這是一個重要的方法荣暮,在許多場合都能用到,比如你要得到![](#)標(biāo)簽下的圖像url,那么就可以用soup.img.get('src'),具體解析如下:

    print soup.p.get("class")   #得到第一個p標(biāo)簽下的src屬性

string

得到標(biāo)簽下的文本內(nèi)容罩驻,只有在此標(biāo)簽下沒有子標(biāo)簽穗酥,或者只有一個子標(biāo)簽的情況下才能返回其中的內(nèi)容,否則返回的是None具體實例如下:

    print soup.p.string #在上面的一段文本中p標(biāo)簽沒有子標(biāo)簽,因此能夠正確返回文本的內(nèi)容
    
    print soup.html.string  #這里得到的就是None,因為這里的html中有很多的子標(biāo)簽

get_text()

可以獲得一個標(biāo)簽中的所有文本內(nèi)容砾跃,包括子孫節(jié)點的內(nèi)容骏啰,這是最常用的方法

搜索文檔樹

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

find_all是用于搜索節(jié)點中所有符合過濾條件的節(jié)點

  1. name參數(shù):是Tag的名字,如p,div,title .....
  • soup.find_all("p") 查找所有的p標(biāo)簽抽高,返回的是[<b>The Dormouse's story</b>]判耕,可以通過遍歷獲取每一個節(jié)點,如下:
    ps=soup.find_all("p")
    for p in ps:
        print p.get('class')   #得到p標(biāo)簽下的class屬性
  • 傳入正則表達(dá)式:soup.find_all(re.compile(r'^b')查找以b開頭的所有標(biāo)簽翘骂,這里的bodyb標(biāo)簽都會被查到
  • 傳入類列表:如果傳入列表參數(shù),BeautifulSoup會將與列表中任一元素匹配的內(nèi)容返回.下面代碼找到文檔中所有<a>標(biāo)簽和<b>標(biāo)簽
soup.find_all(["a", "b"])   

  1. KeyWords參數(shù)壁熄,就是傳入屬性和對應(yīng)的屬性值,或者一些其他的表達(dá)式
  • soup.find_all(id='link2'),這個將會搜索找到所有的id屬性為link2的標(biāo)簽碳竟。傳入正則表達(dá)式soup.find_all(href=re.compile("elsie")),這個將會查找所有href屬性滿足正則表達(dá)式的標(biāo)簽
  • 傳入多個值:soup.find_all(id='link2',class_='title') ,這個將會查找到同時滿足這兩個屬性的標(biāo)簽草丧,這里的class必須用class_傳入?yún)?shù),因為classpython中的關(guān)鍵詞
  • 有些屬性不能通過以上方法直接搜索莹桅,比如html5中的data-*屬性昌执,不過可以通過attrs參數(shù)指定一個字典參數(shù)來搜索包含特殊屬性的標(biāo)簽,如下:
# [<div data-foo="value">foo!</div>]
data_soup.find_all(attrs={"data-foo": "value"})   #注意這里的atts不僅能夠搜索特殊屬性诈泼,亦可以搜索普通屬性

soup.find_all("p",attrs={'class':'title','id':'value'})  #相當(dāng)與soup.find_all('p',class_='title',id='value')


  1. text參數(shù):通過 text 參數(shù)可以搜搜文檔中的字符串內(nèi)容.與 name 參數(shù)的可選值一樣, text 參數(shù)接受 字符串 , 正則表達(dá)式 , 列表, True
soup.find_all(text="Elsie")
# [u'Elsie']
 
soup.find_all(text=["Tillie", "Elsie", "Lacie"])
# [u'Elsie', u'Lacie', u'Tillie']
 
soup.find_all(text=re.compile("Dormouse"))
[u"The Dormouse's story", u"The Dormouse's story"]
  1. limit參數(shù):find_all() 方法返回全部的搜索結(jié)構(gòu),如果文檔樹很大那么搜索會很慢.如果我們不需要全部結(jié)果,可以使用 limit 參數(shù)限制返回結(jié)果的數(shù)量.效果與SQL中的limit關(guān)鍵字類似,當(dāng)搜索到的結(jié)果數(shù)量達(dá)到 limit 的限制時,就停止搜索返回結(jié)果.

文檔樹中有3tag符合搜索條件,但結(jié)果只返回了2個,因為我們限制了返回數(shù)量,代碼如下:

soup.find_all("a", limit=2)
# [<a class="sister"  id="link1">Elsie</a>,
#  <a class="sister"  id="link2">Lacie</a>]
  1. recursive 參數(shù):調(diào)用tagfind_all() 方法時,BeautifulSoup會檢索當(dāng)前tag的所有子孫節(jié)點,如果只想搜索tag的直接子節(jié)點,可以使用參數(shù) recursive=False

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

它與 find_all() 方法唯一的區(qū)別是 find_all() 方法的返回結(jié)果是值包含一個元素的列表,而 find() 方法直接返回結(jié)果,就是直接返回第一匹配到的元素懂拾,不是列表,不用遍歷铐达,如soup.find("p").get("class")

css選擇器

我們在寫 CSS 時岖赋,標(biāo)簽名不加任何修飾,類名前加點娶桦,id名前加#贾节,在這里我們也可以利用類似的方法來篩選元素汁汗,用到的方法是 soup.select()衷畦,返回類型是 list

通過標(biāo)簽名查找

print soup.select('title') 
#[<title>The Dormouse's story</title>]


print soup.select('a')
#[<a class="sister"  id="link1"><!-- Elsie --></a>, <a class="sister"  id="link2">Lacie</a>, <a class="sister"  id="link3">Tillie</a>]

通過類名查找

print soup.select('.sister')
#[<a class="sister"  id="link1"><!-- Elsie --></a>, <a class="sister"  id="link2">Lacie</a>, <a class="sister"  id="link3">Tillie</a>]

通過id名查找

print soup.select('#link1')
#[<a class="sister"  id="link1"><!-- Elsie --></a>]

組合查找

學(xué)過css的都知道css選擇器,如p #link1是查找p標(biāo)簽下的id屬性為link1的標(biāo)簽

print soup.select('p #link1')    #查找p標(biāo)簽中內(nèi)容為id屬性為link1的標(biāo)簽
#[<a class="sister"  id="link1"><!-- Elsie --></a>]

print soup.select("head > title")   #直接查找子標(biāo)簽
#[<title>The Dormouse's story</title>]  

屬性查找

查找時還可以加入屬性元素知牌,屬性需要用中括號括起來祈争,注意屬性和標(biāo)簽屬于同一節(jié)點,所以中間不能加空格角寸,否則會無法匹配到菩混。

print soup.select('a[class="sister"]')
#[<a class="sister"  id="link1"><!-- Elsie --></a>, <a class="sister"  id="link2">Lacie</a>, <a class="sister"  id="link3">Tillie</a>]


print soup.select('a[)
#[<a class="sister"  id="link1"><!-- Elsie --></a>]

同樣,屬性仍然可以與上述查找方式組合扁藕,不在同一節(jié)點的空格隔開沮峡,同一節(jié)點的不加空格,代碼如下:

print soup.select('p a[)
#[<a class="sister"  id="link1"><!-- Elsie --></a>]

以上的 select 方法返回的結(jié)果都是列表形式,可以遍歷形式輸出亿柑,然后用 get_text() 方法來獲取它的內(nèi)容


soup = BeautifulSoup(html, 'lxml')
print type(soup.select('title'))
print soup.select('title')[0].get_text()

for title in soup.select('title'):
    print title.get_text()

更多文章請移步本人博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末邢疙,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疟游,老刑警劉巖呼畸,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颁虐,居然都是意外死亡蛮原,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進(jìn)店門另绩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來儒陨,“玉大人,你說我怎么就攤上這事板熊】蛉” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵干签,是天一觀的道長津辩。 經(jīng)常有香客問我,道長容劳,這世上最難降的妖魔是什么喘沿? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮竭贩,結(jié)果婚禮上蚜印,老公的妹妹穿的比我還像新娘。我一直安慰自己留量,他們只是感情好窄赋,可當(dāng)我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著楼熄,像睡著了一般忆绰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上可岂,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天错敢,我揣著相機與錄音,去河邊找鬼缕粹。 笑死稚茅,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的平斩。 我是一名探鬼主播亚享,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼绘面!你這毒婦竟也來了欺税?” 一聲冷哼從身側(cè)響起糜芳,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎魄衅,沒想到半個月后峭竣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡晃虫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年皆撩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哲银。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡扛吞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荆责,到底是詐尸還是另有隱情滥比,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布做院,位于F島的核電站盲泛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏键耕。R本人自食惡果不足惜寺滚,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望屈雄。 院中可真熱鬧村视,春花似錦、人聲如沸酒奶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惋嚎。三九已至杠氢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瘸彤,已是汗流浹背修然。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工笛钝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留质况,地道東北人。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓玻靡,卻偏偏與公主長得像结榄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子囤捻,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,851評論 2 361

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