在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ Beautiful Soup 的用法
綜述
Cookie 的使用
爬蟲基礎(chǔ)了解
計(jì)算大學(xué)本學(xué)期績點(diǎn)
抓取淘寶 MM 照片
爬蟲框架 Scrapy 安裝配置
模擬登錄淘寶并獲取所有訂單
Urllib 庫的高級用法
URLError 異常處理
正則表達(dá)式
Beautiful Soup 的用法
爬取糗事百科段子
爬取百度貼吧帖子
Urllib 庫的基本使用

Beautiful Soup 的用法

上一節(jié)我們介紹了正則表達(dá)式,它的內(nèi)容其實(shí)還是蠻多的,如果一個(gè)正則匹配稍有差池,那可能程序就處在永久的循環(huán)之中,而且有的小伙伴們也對寫正則表達(dá)式的寫法用得不熟練,沒關(guān)系,我們還有一個(gè)更強(qiáng)大的工具,叫 Beautiful Soup,有了它我們可以很方便地提取出 HTML 或 XML標(biāo)簽中的內(nèi)容,實(shí)在是方便,這一節(jié)就讓我們一起來感受一下 Beautiful Soup 的強(qiáng)大吧。

Beautiful Soup 的簡介

簡單來說,Beautiful Soup 是 python 的一個(gè)庫,最主要的功能是從網(wǎng)頁抓取數(shù)據(jù)。官方解釋如下:

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

廢話不多說,我們來試一下吧~

Beautiful Soup 安裝

Beautiful Soup 3 目前已經(jīng)停止開發(fā),推薦在現(xiàn)在的項(xiàng)目中使用 Beautiful Soup 4,不過它已經(jīng)被移植到 BS4 了,也就是說導(dǎo)入時(shí)我們需要 import bs4 。所以這里我們用的版本是 Beautiful Soup 4.3.2 (簡稱BS4),另外據(jù)說 BS4 對 Python3 的支持不夠好,不過我用的是 Python2.7.7,如果有小伙伴用的是 Python3 版本,可以考慮下載 BS3 版本。

如果你用的是新版的 Debain 或 Ubuntu,那么可以通過系統(tǒng)的軟件包管理來安裝,不過它不是最新版本,目前是4.2.1版本

sudo apt-get install Python-bs4  

如果想安裝最新的版本,請直接下載安裝包來手動安裝,也是十分方便的方法。在這里我安裝的是 Beautiful Soup 4.3.2

Beautiful Soup 3.2.1
Beautiful Soup 4.3.2

下載完成之后解壓

運(yùn)行下面的命令即可完成安裝

sudo python setup.py install  

如下圖所示,證明安裝成功了

http://wiki.jikexueyuan.com/project/python-crawler-guide/images/05.png" alt="" />

然后需要安裝 lxml

sudo apt-get install Python-lxml   

Beautiful Soup 支持 Python 標(biāo)準(zhǔn)庫中的 HTML 解析器,還支持一些第三方的解析器,如果我們不安裝它,則 Python 會使用 Python 默認(rèn)的解析器,lxml 解析器更加強(qiáng)大,速度更快,推薦安裝。

開啟 Beautiful Soup 之旅

在這里先分享官方文檔鏈接,不過內(nèi)容是有些多,也不夠條理,在此本文章做一下整理方便大家參考。

官方文檔

創(chuàng)建 Beautiful Soup 對象

首先必須要導(dǎo)入 bs4 庫

from bs4 import BeautifulSoup  

我們創(chuàng)建一個(gè)字符串,后面的例子我們便會用它來演示

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)建 beautifulsoup 對象

soup = BeautifulSoup(html)  

另外,我們還可以用本地 HTML 文件來創(chuàng)建對象,例如

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

上面這句代碼便是將本地 index.html 文件打開,用它來創(chuàng)建 soup 對象

下面我們來打印一下 soup 對象的內(nèi)容,格式化輸出

print soup.prettify()
<html>
 <head>
  <title>
   The Dormouse's story
  </title>   

以上便是輸出結(jié)果,格式化打印出了它的內(nèi)容,這個(gè)函數(shù)經(jīng)常用到,小伙伴們要記好咯。

四大對象種類

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

  • Tag
  • NavigableString
  • BeautifulSoup
  • Comment

下面我們進(jìn)行一一介紹

Tag

Tag 是什么?通俗點(diǎn)講就是 HTML 中的一個(gè)個(gè)標(biāo)簽,例如

<title>The Dormouse's story</title>
<a class="sister"  id="link1">Elsie</a>  

上面的 title a 等等 HTML 標(biāo)簽加上里面包括的內(nèi)容就是 Tag,下面我們來感受一下怎樣用 Beautiful Soup 來方便地獲取 Tags

下面每一段代碼中注釋部分即為運(yùn)行結(jié)果

print soup.title
\#<title>The Dormouse's story</title>
print soup.head
\#<head><title>The Dormouse's story</title></head>
print soup.a
\#<a class="sister"  id="link1"><!-- Elsie --></a>  
print soup.p
\#<p class="title" name="dromouse"><b>The Dormouse's story</b></p>  

我們可以利用 soup 加標(biāo)簽名輕松地獲取這些標(biāo)簽的內(nèi)容,是不是感覺比正則表達(dá)式方便多了?不過有一點(diǎn)是,它查找的是在所有內(nèi)容中的第一個(gè)符合要求的標(biāo)簽,如果要查詢所有的標(biāo)簽,我們在后面進(jìn)行介紹。

我們可以驗(yàn)證一下這些對象的類型

print type(soup.a)
\#<class 'bs4.element.Tag'>  

對于 Tag,它有兩個(gè)重要的屬性,是 name 和 attrs,下面我們分別來感受一下

name

print soup.name
print soup.head.name
\#[document]
\#head  

soup 對象本身比較特殊,它的 name 即為 [document],對于其他內(nèi)部標(biāo)簽,輸出的值便為標(biāo)簽本身的名稱。

attrs

print soup.p.attrs
\#{'class': ['title'], 'name': 'dromouse'}  

在這里,我們把 p 標(biāo)簽的所有屬性打印輸出了出來,得到的類型是一個(gè)字典。

如果我們想要單獨(dú)獲取某個(gè)屬性,可以這樣,例如我們獲取它的 class 叫什么

print soup.p['class']
\#['title']  

還可以這樣,利用 get 方法,傳入屬性的名稱,二者是等價(jià)的

print soup.p.get('class')
\#['title']  

我們可以對這些屬性和內(nèi)容等等進(jìn)行修改,例如

soup.p['class']="newClass"
print soup.p
\#<p class="newClass" name="dromouse"><b>The Dormouse's story</b></p>  

還可以對這個(gè)屬性進(jìn)行刪除,例如

del soup.p['class']
print soup.p
\#<p name="dromouse"><b>The Dormouse's story</b></p>  

不過,對于修改刪除的操作,不是我們的主要用途,在此不做詳細(xì)介紹了,如果有需要,請查看前面提供的官方文檔

NavigableString

既然我們已經(jīng)得到了標(biāo)簽的內(nèi)容,那么問題來了,我們要想獲取標(biāo)簽內(nèi)部的文字怎么辦呢?很簡單,用 .string 即可,例如

print soup.p.string
\#The Dormouse's story  

這樣我們就輕松獲取到了標(biāo)簽里面的內(nèi)容,想想如果用正則表達(dá)式要多麻煩。它的類型是一個(gè) NavigableString,翻譯過來叫 可以遍歷的字符串,不過我們最好還是稱它英文名字吧。

來檢查一下它的類型

print type(soup.p.string)
#<class 'bs4.element.NavigableString'>    

BeautifulSoup

BeautifulSoup 對象表示的是一個(gè)文檔的全部內(nèi)容.大部分時(shí)候,可以把它當(dāng)作 Tag 對象,是一個(gè)特殊的 Tag,我們可以分別獲取它的類型,名稱,以及屬性來感受一下

print type(soup.name)
\#<type 'unicode'>
print soup.name 
\# [document]
print soup.attrs 
\#{} 空字典  

Comment

Comment 對象是一個(gè)特殊類型的 NavigableString 對象,其實(shí)輸出的內(nèi)容仍然不包括注釋符號,但是如果不好好處理它,可能會對我們的文本處理造成意想不到的麻煩。

我們找一個(gè)帶注釋的標(biāo)簽

print soup.a
print soup.a.string
print type(soup.a.string)  

運(yùn)行結(jié)果如下

<a class="sister"  id="link1"><!-- Elsie --></a>
 Elsie 
<class 'bs4.element.Comment'>  

a 標(biāo)簽里的內(nèi)容實(shí)際上是注釋,但是如果我們利用 .string 來輸出它的內(nèi)容,我們發(fā)現(xiàn)它已經(jīng)把注釋符號去掉了,所以這可能會給我們帶來不必要的麻煩。

另外我們打印輸出下它的類型,發(fā)現(xiàn)它是一個(gè) Comment 類型,所以,我們在使用前最好做一下判斷,判斷代碼如下

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

上面的代碼中,我們首先判斷了它的類型,是否為 Comment 類型,然后再進(jìn)行其他操作,如打印輸出。

遍歷文檔樹

直接子節(jié)點(diǎn)

要點(diǎn):.contents .children 屬性

.contents

tag 的 .content 屬性可以將tag的子節(jié)點(diǎn)以列表的方式輸出

print soup.head.contents 
\#[<title>The Dormouse's story</title>]  

輸出方式為列表,我們可以用列表索引來獲取它的某一個(gè)元素

print soup.head.contents[0]
\#<title>The Dormouse's story</title>  

.children

它返回的不是一個(gè) list,不過我們可以通過遍歷獲取所有子節(jié)點(diǎn)。

我們打印輸出 .children 看一下,可以發(fā)現(xiàn)它是一個(gè) list 生成器對象

print soup.head.children
\#<listiterator object at 0x7f71457f5710>  

我們怎樣獲得里面的內(nèi)容呢?很簡單,遍歷一下就好了,代碼及結(jié)果如下

for child in  soup.body.children:
    print child
<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  

所有子孫節(jié)點(diǎn)

知識點(diǎn):.descendants 屬性

.descendants

.contents 和 .children 屬性僅包含tag的直接子節(jié)點(diǎn),.descendants 屬性可以對所有tag的子孫節(jié)點(diǎn)進(jìn)行遞歸循環(huán),和 children類似,我們也需要遍歷獲取其中的內(nèi)容。

for child in soup.descendants:
    print child  

運(yùn)行結(jié)果如下,可以發(fā)現(xiàn),所有的節(jié)點(diǎn)都被打印出來了,先生最外層的 HTML 標(biāo)簽,其次從 head 標(biāo)簽一個(gè)個(gè)剝離,以此類推。

<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>,   

節(jié)點(diǎn)內(nèi)容

知識點(diǎn):.string 屬性

如果 tag 只有一個(gè) NavigableString 類型子節(jié)點(diǎn),那么這個(gè) tag 可以使用 .string 得到子節(jié)點(diǎn)。如果一個(gè) tag 僅有一個(gè)子節(jié)點(diǎn),那么這個(gè) tag 也可以使用 .string 方法,輸出結(jié)果與當(dāng)前唯一子節(jié)點(diǎn)的 .string 結(jié)果相同。

通俗點(diǎn)說就是:如果一個(gè)標(biāo)簽里面沒有標(biāo)簽了,那么 .string 就會返回標(biāo)簽里面的內(nèi)容。如果標(biāo)簽里面只有唯一的一個(gè)標(biāo)簽了,那么 .string 也會返回最里面的內(nèi)容。例如

print soup.head.string
\#The Dormouse's story
print soup.title.string
\#The Dormouse's story  

如果 tag 包含了多個(gè)子節(jié)點(diǎn),tag 就無法確定,string 方法應(yīng)該調(diào)用哪個(gè)子節(jié)點(diǎn)的內(nèi)容, .string 的輸出結(jié)果是 None

print soup.html.string
\# None  

多個(gè)內(nèi)容

知識點(diǎn): .strings .stripped_strings 屬性

.strings

獲取多個(gè)內(nèi)容,不過需要遍歷獲取,比如下面的例子

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

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

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

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

知識點(diǎn): .parent 屬性

p = soup.p
print p.parent.name
\#body  
content = soup.head.title.string
print content.parent.name
\#title  

全部父節(jié)點(diǎn)

知識點(diǎn):.parents 屬性

通過元素的 .parents 屬性可以遞歸得到元素的所有父輩節(jié)點(diǎn),例如

content = soup.head.title.string
for parent in  content.parents:
    print parent.name  
title
head
html
[document]  

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

知識點(diǎn):.next_sibling .previous_sibling 屬性

兄弟節(jié)點(diǎn)可以理解為和本節(jié)點(diǎn)處在統(tǒng)一級的節(jié)點(diǎn),.next_sibling 屬性獲取了該節(jié)點(diǎn)的下一個(gè)兄弟節(jié)點(diǎn),.previous_sibling 則與之相反,如果節(jié)點(diǎn)不存在,則返回 None

注意:實(shí)際文檔中的tag的 .next_sibling 和 .previous_sibling 屬性通常是字符串或空白,因?yàn)榭瞻谆蛘邠Q行也可以被視作一個(gè)節(jié)點(diǎn),所以得到的結(jié)果可能是空白或者換行

print soup.p.next_sibling
\#       實(shí)際該處為空白
print soup.p.prev_sibling
\#None   沒有前一個(gè)兄弟節(jié)點(diǎn),返回 None
print soup.p.next_sibling.next_sibling
\#<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>
\#下一個(gè)節(jié)點(diǎn)的下一個(gè)兄弟節(jié)點(diǎn)是我們可以看到的節(jié)點(diǎn)  

全部兄弟節(jié)點(diǎn)

知識點(diǎn):.next_siblings .previous_siblings 屬性

通過 .next_siblings 和 .previous_siblings 屬性可以對當(dāng)前節(jié)點(diǎn)的兄弟節(jié)點(diǎn)迭代輸出

for sibling in soup.a.next_siblings:
    print(repr(sibling))
    \# u',\n'
    \# <a class="sister"  id="link2">Lacie</a>
    \# u' and\n'
    \# <a class="sister"  id="link3">Tillie</a>
    \# u'; and they lived at the bottom of a well.'
    \# None  

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

知識點(diǎn):.next_element .previous_element 屬性

與 .next_sibling .previous_sibling 不同,它并不是針對于兄弟節(jié)點(diǎn),而是在所有節(jié)點(diǎn),不分層次

比如 head 節(jié)點(diǎn)為

<head><title>The Dormouse's story</title></head>  

那么它的下一個(gè)節(jié)點(diǎn)便是 title,它是不分層次關(guān)系的

print soup.head.next_element
\#<title>The Dormouse's story</title>  

所有前后節(jié)點(diǎn)

知識點(diǎn):.next_elements .previous_elements 屬性

通過 .next_elements 和 .previous_elements 的迭代器就可以向前或向后訪問文檔的解析內(nèi)容,就好像文檔正在被解析一樣

for element in last_a_tag.next_elements:
    print(repr(element))
\# u'Tillie'
\# u';\nand they lived at the bottom of a well.'
\# u'\n\n'
\# <p class="story">...</p>
\# u'...'
\# u'\n'
\# None  

搜索文檔樹

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

find_all() 方法搜索當(dāng)前tag的所有tag子節(jié)點(diǎn),并判斷是否符合過濾器的條件

name 參數(shù)

name 參數(shù)可以查找所有名字為 name 的 tag,字符串對象會被自動忽略掉

傳字符串

最簡單的過濾器是字符串.在搜索方法中傳入一個(gè)字符串參數(shù),Beautiful Soup 會查找與字符串完整匹配的內(nèi)容,下面的例子用于查找文檔中所有的 標(biāo)簽

soup.find_all('b')
\# [<b>The Dormouse's story</b>]  
print soup.find_all('a')
\#[<a class="sister"  id="link1"><!-- Elsie --></a>, <a class="sister"  id="link2">Lacie</a>, <a class="sister"  id="link3">Tillie</a>]  
傳正則表達(dá)式

如果傳入正則表達(dá)式作為參數(shù),Beautiful Soup 會通過正則表達(dá)式的 match() 來匹配內(nèi)容.下面例子中找出所有以b開頭的標(biāo)簽,這表示 和 標(biāo)簽都應(yīng)該被找到

import re
for tag in soup.find_all(re.compile("^b")):
    print(tag.name)
\# body
\# b  
傳列表

如果傳入列表參數(shù),Beautiful Soup 會將與列表中任一元素匹配的內(nèi)容返回.下面代碼找到文檔中所有 <a> 標(biāo)簽和 <b> 標(biāo)簽

soup.find_all(["a", "b"])
\# [<b>The Dormouse's story</b>,
\#  <a class="sister"  id="link1">Elsie</a>,
\#  <a class="sister"  id="link2">Lacie</a>,
\#  <a class="sister"  id="link3">Tillie</a>]  
傳 True

True 可以匹配任何值,下面代碼查找到所有的 tag,但是不會返回字符串節(jié)點(diǎn)

for tag in soup.find_all(True):
    print(tag.name)
\# html
\# head
\# title
\# body
\# p
\# b
\# p
\# a
\# a  
傳方法

如果沒有合適過濾器,那么還可以定義一個(gè)方法,方法只接受一個(gè)元素參數(shù) [4] ,如果這個(gè)方法返回 True 表示當(dāng)前元素匹配并且被找到,如果不是則反回 False

下面方法校驗(yàn)了當(dāng)前元素,如果包含 class 屬性卻不包含 id 屬性,那么將返回 True:

def has_class_but_no_id(tag):
    return tag.has_attr('class') and not tag.has_attr('id')  

將這個(gè)方法作為參數(shù)傳入 find_all() 方法,將得到所有

標(biāo)簽:

soup.find_all(has_class_but_no_id)
\# [<p class="title"><b>The Dormouse's story</b></p>,
\#  <p class="story">Once upon a time there were...</p>,
\#  <p class="story">...</p>]   

keyword 參數(shù)

注意:如果一個(gè)指定名字的參數(shù)不是搜索內(nèi)置的參數(shù)名,搜索時(shí)會把該參數(shù)當(dāng)作指定名字 tag 的屬性來搜索,如果包含一個(gè)名字為 id 的參數(shù),Beautiful Soup 會搜索每個(gè) tag 的 ”id” 屬性

soup.find_all(id='link2')
\# [<a class="sister"  id="link2">Lacie</a>]  

如果傳入 href 參數(shù),Beautiful Soup 會搜索每個(gè) tag 的 ”href” 屬性

soup.find_all(href=re.compile("elsie"))
\# [<a class="sister"  id="link1">Elsie</a>]  

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

soup.find_all(href=re.compile("elsie"), id='link1')
\# [<a class="sister"  id="link1">three</a>]  

在這里我們想用 class 過濾,不過 class 是 python 的關(guān)鍵詞,這怎么辦?加個(gè)下劃線就可以

soup.find_all("a", class_="sister")
\# [<a class="sister"  id="link1">Elsie</a>,
\#  <a class="sister"  id="link2">Lacie</a>,
\#  <a class="sister"  id="link3">Tillie</a>]  

有些 tag 屬性在搜索不能使用,比如 HTML5 中的 data-* 屬性

data_soup = BeautifulSoup('<div data-foo="value">foo!</div>')
data_soup.find_all(data-foo="value")
\# SyntaxError: keyword can't be an expression  

但是可以通過 find_all() 方法的 attrs 參數(shù)定義一個(gè)字典參數(shù)來搜索包含特殊屬性的tag

data_soup.find_all(attrs={"data-foo": "value"})
\# [<div data-foo="value">foo!</div>]  

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"]  

limit 參數(shù)

find_all() 方法返回全部的搜索結(jié)構(gòu),如果文檔樹很大那么搜索會很慢.如果我們不需要全部結(jié)果,可以使用 limit 參數(shù)限制返回結(jié)果的數(shù)量.效果與 SQL 中的 limit 關(guān)鍵字類似,當(dāng)搜索到的結(jié)果數(shù)量達(dá)到 limit 的限制時(shí),就停止搜索返回結(jié)果.

文檔樹中有3個(gè) tag 符合搜索條件,但結(jié)果只返回了2個(gè),因?yàn)槲覀兿拗屏朔祷財(cái)?shù)量

soup.find_all("a", limit=2)
\# [<a class="sister"  id="link1">Elsie</a>,
\#  <a class="sister"  id="link2">Lacie</a>]  

recursive 參數(shù)

調(diào)用 tag 的 find_all() 方法時(shí),Beautiful Soup 會檢索當(dāng)前 tag 的所有子孫節(jié)點(diǎn),如果只想搜索 tag 的直接子節(jié)點(diǎn),可以使用參數(shù) recursive=False .

一段簡單的文檔:

<html\>  
 <head\>  
  <title\>  
   The Dormouse's story  
  </title\>  
 </head\>  
...  

是否使用 recursive 參數(shù)的搜索結(jié)果:

soup.html.find_all("title")
\# [<title>The Dormouse's story</title>]

soup.html.find_all("title", recursive=False)
\# []  

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

它與 find_all() 方法唯一的區(qū)別是 find_all() 方法的返回結(jié)果是值包含一個(gè)元素的列表,而 find() 方法直接返回結(jié)果

find_parents() fin_parent()

find_all() 和 find() 只搜索當(dāng)前節(jié)點(diǎn)的所有子節(jié)點(diǎn),孫子節(jié)點(diǎn)等. find_parents() 和 find_parent() 用來搜索當(dāng)前節(jié)點(diǎn)的父輩節(jié)點(diǎn),搜索方法與普通 tag 的搜索方法相同,搜索文檔搜索文檔包含的內(nèi)容

find_next_siblings() find_next_sibling()

這2個(gè)方法通過 .next_siblings 屬性對當(dāng) tag 的所有后面解析的兄弟 tag 節(jié)點(diǎn)進(jìn)行迭代, find_next_siblings() 方法返回所有符合條件的后面的兄弟節(jié)點(diǎn),find_next_sibling() 只返回符合條件的后面的第一個(gè) tag 節(jié)點(diǎn)

find_previous_siblings() find_previous_sibling()

這2個(gè)方法通過 .previous_siblings 屬性對當(dāng)前 tag 的前面解析的兄弟 tag 節(jié)點(diǎn)進(jìn)行迭代, find_previous_siblings() 方法返回所有符合條件的前面的兄弟節(jié)點(diǎn), find_previous_sibling() 方法返回第一個(gè)符合條件的前面的兄弟節(jié)點(diǎn)

find_all_next() find_next()

這2個(gè)方法通過 .next_elements 屬性對當(dāng)前 tag 的之后的 tag 和字符串進(jìn)行迭代, find_all_next() 方法返回所有符合條件的節(jié)點(diǎn), find_next() 方法返回第一個(gè)符合條件的節(jié)點(diǎn)

find_all_previous() 和 find_previous()

這2個(gè)方法通過 .previous_elements 屬性對當(dāng)前節(jié)點(diǎn)前面的 tag 和字符串進(jìn)行迭代, find_all_previous() 方法返回所有符合條件的節(jié)點(diǎn), find_previous()方法返回第一個(gè)符合條件的節(jié)點(diǎn)

注:以上(2)(3)(4)(5)(6)(7)方法參數(shù)用法與 find_all() 完全相同,原理均類似,在此不再贅述。

CSS選擇器

我們在寫 CSS 時(shí),標(biāo)簽名不加任何修飾,類名前加點(diǎn),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('b')
\#[<b>The Dormouse's story</b>]  

通過類名查找

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>]  

組合查找

組合查找即和寫 class 文件時(shí),標(biāo)簽名與類名、id 名進(jìn)行的組合原理是一樣的,例如查找 p 標(biāo)簽中,id 等于 link1 的內(nèi)容,二者需要用空格分開

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

直接子標(biāo)簽查找

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

屬性查找

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

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é)點(diǎn)的空格隔開,同一節(jié)點(diǎn)的不加空格

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

好,這就是另一種與 find_all 方法有異曲同工之妙的查找方法,是不是感覺很方便?

總結(jié)

本篇內(nèi)容比較多,把 Beautiful Soup 的方法進(jìn)行了大部分整理和總結(jié),不過這還不算完全,仍然有 Beautiful Soup 的修改刪除功能,不過這些功能用得比較少,只整理了查找提取的方法,希望對大家有幫助!小伙伴們加油!

熟練掌握了 Beautiful Soup,一定會給你帶來太多方便,加油吧!