Beautiful Soup的简介

Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据。官方解释如下:

1、Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序

2、Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了

3、Beautiful Soup已成为和lxml、html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度

安装BeautifulSoup

1、BeautifulSoup4通过PyPi发布,所以如果你无法使用系统包管理安装,那么也可以通过easy_install或pip来安装。包的名字是beautifulsoup4这个包兼容Python2和Python3

2、 pip install BeautifulSoup4==4.0.1


安装解析器

1、Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器。其中一个是lxml

2、根据操作系统不同,可以选择pip方法来安装lxml:pip install lxml

各种解析器优缺点

Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果我们不安装它,则 Python 会使用 Python默认的解析器,lxml 解析器更加强大,速度更快,推荐安装(pip install lxml)

解析器使用方法优势劣势
Python标准库 BeautifulSoup(markup, “html.parser”) Python的内置标准库、执行速度适中、文档容错能力强Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差
lxml HTML 解析器BeautifulSoup(markup, “lxml”) 速度快、文档容错能力强需要安装C语言库
lxml XML 解析器BeautifulSoup(markup, [“lxml”, “xml”])或BeautifulSoup(markup, “xml”)速度快、唯一支持XML的解析器需要安装C语言库
html5lib BeautifulSoup(markup, “html5lib”) 最好的容错性、以浏览器的方式解析文档、生成HTML5格式的文档、不依赖外部扩展  速度慢

BeautifulSoup简介

1、将一段文档传入BeautifulSoup 的构造方法,就能得到一个文档的对象(beautifulsoup对象)。同时也可以传入一段字符串或一个文件句柄

2、首先,文档被转换成Unicode,并且HTML的实例都被转换成Unicode编码

3、然后Beautiful Soup选择最合适的解析器来解析这段文档,如果手动指定解析器,那么Beautiful Soup会选择指定的解析器来解析文档

例1:

# 导入所需第三方库
from bs4 import BeautifulSoup

# 这里先用一个简单的HTML数据为例
htmlData = """<html>
 <head> 
    <title>The Dormouse's story</title> 
 </head> 
 <body> 
  <p class="title"><b>The Dormouse's story</b></p> 
  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a> 
 </body>
</html>"""

# 将字符串型的HTML数据转为beautifulsoup对象(指定解析器)
soup = BeautifulSoup(htmlData, "lxml")
print("转换结果为:", soup)
print("转换结果的类型为:", type(soup))

# 格式化输出HTML数据
htmlPrettify = soup.prettify()
print("格式化输出HTML数据:", htmlPrettify)
print("格式化输出HTML数据的类型:", type(htmlPrettify))

"""
转换结果为: <html>
<head>
<title>The Dormouse's story</title>
</head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
</body>
</html>
转换结果的类型为: <class 'bs4.BeautifulSoup'>
格式化输出HTML数据: <html>
 <head>
  <title>
   The Dormouse's story
  </title>
 </head>
 <body>
  <p class="title">
   <b>
    The Dormouse's story
   </b>
  </p>
  <a class="sister" href="http://example.com/tillie" id="link3">
   Tillie
  </a>
 </body>
</html>
格式化输出HTML数据的类型: <class 'str'>
"""

例1_1:使用HTML文件来创建beautifulsoup对象

from bs4 import BeautifulSoup

html = open("F:\\test.txt","r",encoding="utf-8")
soup = BeautifulSoup(html,features="lxml") #将本地文件打开,用它来创建soup对象

注:
1、BeautifulSoup()方法返回的是一个bs4.BeautifulSoup对象(该对象表示整个HTML数据),我们可以根据这个对象来使用不同的方法来获得HTML中我们需要的数据

2、在BeautifulSoup()方法中感觉最好指定解析器(使用lxml解析器),不然有时候会报错

3、上面例子中使用了prettify()方法:该方法用于格式化打印出获得的内容。这个函数经常用到所以要记住了

4、在控制台打印bs4.BeautifulSoup对象时,虽然其看起来像一个字符串。但其实际不是字符串。可以使用str()或prettify()方法来将bs4.BeautifulSoup对象转为字符串

四大对象种类

Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:

对象名描述
BeautifulSoup文档自身:表示的是一个文档的全部内容
Tag标签对:Tag对象与XML或HTML原生文档中的tag相同,即标签对            
NavigableString 标签值:标签对中的字符串
Comment注释:文档的注释部分

Tag对象

1、Tag即HTML或XML中的标签对:Tag对象与XML或HTML原生文档中的tag相同

2、HTML中tag是由尖括号包围的关键词,即HTML中的一个个标签。一般是成对出现的。比如<p>和</p>

3、成对的tag里,第一个(不带"/"的)叫开始tag(又叫开放tag),第二个叫结束tag(又叫闭合tag)

4、例如:<title>The Dormouse's story</title>或<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
    ⑴上面的title、a等等HTML标签加上里面包括的内容就是Tag
    ⑵在BeautifulSoup中可以利用beautifulsoup对象下面的方法返回这些标签数据,这些标签数据称为Tag对象(Tag对象指的是整个标签对:从开始标签到结束标签,包括里面的嵌套标签)
    ⑶获取到Tag对象后,可以继续使用其下面的属性(方法)来获取标签对中的具体数据

5、Tag有很多方法和属性,暂时先介绍一下tag对象中最重要的属性:name属性和attributes属性

获取Tag对象

1、从一个beautifulsoup对象中获取指定的Tag对象,可以使用:beautifulsoup对象.标签名
    ⑴要获取哪个标签的Tag对象,就传入哪个标签的标签名

2、注:这种方法返回的Tag对象是所有内容中第一个符合要求的标签
    ⑴即:文档中存在多个同名的标签时,使用"beautifulsoup对象.标签名"返回的始终是第一个符合的标签(至于查找所有符合要求的标签,后面介绍)

例2:

from bs4 import BeautifulSoup  # 导入bs4库

htmlData = """
<html>
 <head> 
    <title>The Dormouse's story</title> 
 </head> 
 <body> 
  <p class="title"><b>The Dormouse's story</b></p> 
  <p class="story">
    <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
    <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
    <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
  </p> 
  <p class="story">they lived at the bottom of a well</p> 
  <ul class="nav nav-tabs"> 
    <li><a href="/codeformat/xml">XML格式化</a></li> 
    <li><a href="/codeformat/css">CSS格式化</a></li> 
    <li><a href="/codeformat/json">JSON格式化</a></li> 
    <li><a href="/codeformat/js">JavaScript格式化</a></li> 
    <li><a href="/codeformat/java">Java格式化</a></li> 
    <li><a href="/codeformat/sql">SQL格式化</a></li> 
  </ul>  
 </body>
</html>
"""

soup = BeautifulSoup(htmlData, "lxml")

# 获取header标签
headTag = soup.head
print("获取到的header标签为:", headTag)
# 获取title标签
titleTag = soup.title
print("获取到的title标签为:", titleTag)
# 获取a标签
aTag = soup.a
print("获取到的a标签为:", aTag)
# 获取p标签
pTag = soup.p
print("获取到的p标签为:", pTag)
print("获取到的p标签类型为:", type(pTag))

"""
获取到的header标签为: <head>
<title>The Dormouse's story</title>
</head>
获取到的title标签为: <title>The Dormouse's story</title>
获取到的a标签为: <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
获取到的p标签为: <p class="title"><b>The Dormouse's story</b></p>
获取到的p标签类型为: <class 'bs4.element.Tag'>
"""

注:
1、从上面例子中我们可以看出:可以使用soup对象加标签名轻松地获取这些标签的内容,返回的标签是一个" <class 'bs4.element.Tag'>",即Tag对象

2、不过需要注意的是:它查找的是在所有内容中的第一个符合要求的标签,如果要查询所有符合要求的标签,我们在后面进行介绍

tag对象的name属性

1、每个tag都有自己的名字,其成为tag对象的name属性(name属性:标签对的名称)

2、获取一个Tag对象的name属性,可以使用:Tag对象.name

例3:

from bs4 import BeautifulSoup #导入bs4库

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 href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""

soup = BeautifulSoup(html,"lxml")   #指定解析器
soup_tag_name = soup.name    #获取整个BeautifulSoup对象的name属性
title_tag_name = soup.title.name  #获取title标签对象的name属性
head_tag_name = soup.head.name  #获取head标签对象的name属性
a_tag = soup.a    #获取a标签对象
a_tag_name = a_tag.name #获取a标签对象的name属性

print("整个BeautifulSoup对象的name属性为:",soup_tag_name)
print("title标签对象的name属性为:",title_tag_name)
print("header标签对象的name属性为:",head_tag_name)
print("a标签对象为:",a_tag)
print("a标签对象的name属性为:",a_tag_name)

"""
整个BeautifulSoup对象的name属性为: [document]
title标签对象的name属性为: title
header标签对象的name属性为: head
a标签对象为: <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
a标签对象的name属性为: a
"""

注:
1、对于soup对象来说:soup对象本身比较特殊,它的name即为[document]

2、对于其他内部标签:输出的值便为标签本身的名称(值类型为字符串)

3、不过感觉获取一个Tag对象的name属性意义不大,毕竟都是通过其标签名来获取的tag对象,然后再通过Tag对象去获取其name属性就显得多此一举了

tag对象的attrs属性

1、attrs属性:指的是一个标签的属性
    ⑴一个标签的属性一般是由键值对组成,属性名=值
    ⑵<blockquote class="boldest">Extremely bold</blockquote>,其中的'class="boldest"'就是标签的属性

2、一个标签可能有很多个属性

3、获取一个Tag对象的attrs属性,可以使用:Tag对象.attrs

4、使用Tag对象的attrs属性可以把标签对的属性以字典形式返回
    ⑴ Tag对象无属性时返回的是一个空字典

例4:

from bs4 import BeautifulSoup #导入bs4库

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 href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""

soup = BeautifulSoup(html,"lxml")   #指定解析器
soup_tag_attrs = soup.attrs #获取整个BeautifulSoup对象的attrs属性
title_tag_attrs = soup.title.attrs #获取title Tag对象的attrs属性
head_tag_attrs = soup.head.attrs #获取head Tag对象的attrs属性
a_tag = soup.a      #获取a标签的Tag对象
a_tag_attrs = a_tag.attrs   #获取a Tag对象的attrs属性


print("BeautifulSoup对象的attrs属性为:",soup_tag_attrs)
print("titlea标签的Tag对象的attrs属性为:",title_tag_attrs)
print("heada标签的Tag对象的attrs属性为:",head_tag_attrs)
print("a标签的Tag对象为:",a_tag)
print("a标签的Tag对象的attrs属性为:",a_tag_attrs)

"""
BeautifulSoup对象的attrs属性为: {}
titlea标签的Tag对象的attrs属性为: {}
heada标签的Tag对象的attrs属性为: {}
a标签的Tag对象为: <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
a标签的Tag对象的attrs属性为: {'id': 'link1', 'href': 'http://example.com/elsie', 'class': ['sister']}
"""

注:
1、从上面的输出结果可以看出对于soup对象、head标签对、title标签对来说返回的为空字典:其标签对里面没有属性值以及对应的值(key:value)

2、对应存在key:value的标签:使用attrs方法可以将其所有的属性打印输出了出来,得到的类型是一个字典

3、如果想要单独获取某个属性具体的值时,可以使用下面三种方法:
    ⑴使用字典方法:字典索引、字典get()方法
    ⑵使用tag对象的get()方法:soup对象.标签名.get(属性名)
    ⑶使用soup对象.标签名.属性名(键名)

例5:

from bs4 import BeautifulSoup #导入bs4库

# 单独的一个标签也是可以构造为BeautifulSoup对象的
html = """<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>"""

soup = BeautifulSoup(html,"lxml")   #指定解析器
print("BeautifulSoup对象为:",soup)

print("--------")

a_tag_attrs = soup.a.attrs
print("a标签的tag对象的属性为:",a_tag_attrs)

a_tag_attrs_href_dict = a_tag_attrs["href"] #使用字典的索引
print("通过字典索引获取到的tag对象的属性",a_tag_attrs_href_dict)

print("--------")

a_tag_attrs_href_dict1 = soup.a.attrs.get("href") #使用字典的get方法
print("通过字典get方法获取到的tag对象的属性",a_tag_attrs_href_dict1)

print("--------")

a_tag_attrs_href_get = soup.a.get("href")#使用soup对象.标签名.get(属性名)
print(a_tag_attrs_href_get)

a_tag_attrs_href = soup.a["href"]#使用soup对象.标签名.属性名(键名)
print(a_tag_attrs_href )


"""
BeautifulSoup对象为: <html><body><a class="sister" href="http://example.com/tillie" id="link3">Tillie</a></body></html>
--------
a标签的tag对象的属性为: {'class': ['sister'], 'href': 'http://example.com/tillie', 'id': 'link3'}
通过字典索引获取到的tag对象的属性 http://example.com/tillie
--------
通过字典get方法获取到的tag对象的属性 http://example.com/tillie
--------
http://example.com/tillie
http://example.com/tillie
"""

注:
1、从上面例子中可以看出要获得标签对中具体属性的值时,共有三种方法:
    ⑴使用字典的方法相对于其他两种来说多了一步,会显得麻烦。不过毕竟字典方法用得比较多,用来很熟悉
    ⑵使用使用soup对象.标签名.属性名方法时:需要注意,需要使用中括号将属性名括起来
    ⑶使用get方法,传入属性的名称,这种方法与上面一种第二种是等价的

多值属性

1、一般情况下,对于标签的属性都是以键值对存在的(一键一值,键=值)。但是某些属性可以存在多个值的情况(一键多值)。这种情况就称为多值属性

2、最常见的多值的属性是 class (一个tag可以有多个CSS的class)。还有一些属性rel , rev , accept-charset , headers , accesskey。在Beautiful Soup中多值属性的返回类型是列表

例5_1:

from bs4 import BeautifulSoup

soup = BeautifulSoup('<p class="body strikeout"></p>',"lxml")

print("p标签的tag对象为",soup.p)

print("p标签的tag对象的属性为",soup.p.attrs)  #其值为一个字典
print("p标签的class属性为",soup.p.attrs.get("class"))


css_soup = BeautifulSoup('<p class="body"></p>',"lxml")
print(css_soup.p['class'])

"""
p标签的tag对象为 <p class="body strikeout"></p>
p标签的tag对象的属性为 {'class': ['body', 'strikeout']}
p标签的class属性为 ['body', 'strikeout']

['body']
"""

注:
1、如果某个属性看起来好像有多个值,但在任何版本的HTML定义中都没有被定义为多值属性,那么Beautiful Soup会将这个属性作为字符串返回

2、将tag转换成字符串时,多值属性会合并为一个值

3、如果转换的文档是XML格式,那么tag中不包含多值属性

例5_3:

from bs4 import BeautifulSoup

css_soup = BeautifulSoup('<p id="my id"></p>',"lxml")
print(css_soup.p['id'])


rel_soup = BeautifulSoup('<p>Back to the <a rel="index">homepage</a></p>',"lxml")
print(rel_soup.a['rel'])


#如果转换的文档是XML格式,那么tag中不包含多值属性
xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')
print(xml_soup.p['class'])

"""
my id
['index']
body strikeout
"""

NavigableString

1、NavigableString对象:指的是标签对中的数据

2、字符串常被包含在tag内。BeautifulSoup用NavigableString类来包装tag中的字符串

3、获取一个Tag对象中的数据(NavigableString对象),可以使用:Tag对象.string

4、使用"Tag对象.string"方法返回的数据的类型为NavigableString对象,可以使用str()方法将其转为字符串(Unicode字符串)
    ⑴也可以使用str()方法将一个Tag对象转为字符串

例6:

from bs4 import BeautifulSoup #导入bs4库

html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><b>The Dormouse's story A</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Tillie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3"><!-- Elsie --></a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""

soup = BeautifulSoup(html,"lxml")#指定解析器,创建beautifulsoup对象

head_string = soup.head.string
p_string = soup.p.string

a_tag = soup.a
a_tag_string = a_tag.string


print("header标签中的数据为:",head_string)
print("p标签中的数据为:",p_string)

print("a标签的tag对象为:",a_tag)
print("a标签中的数据为:",a_tag_string)
print("a标签中的数据的类型为为:",type(a_tag_string))

print("转换数据类型后为:",type(str(a_tag_string))) #使用str()方法将NavigableString对象转为字符串
print("转换数据类型后为--tag对象:",type(str(a_tag))) #使用str()方法将tag对象转为字符串
"""
header标签中的数据为: The Dormouse's story
p标签中的数据为: The Dormouse's story A
a标签的tag对象为: <a class="sister" href="http://example.com/elsie" id="link1">Tillie</a>
a标签中的数据为: Tillie
a标签中的数据的类型为为: <class 'bs4.element.NavigableString'>
转换数据类型后为: <class 'str'>
转换数据类型后为--tag对象: <class 'str'>
"""

BeautifulSoup

BeautifulSoup 对象表示的是一个文档的全部内容。大部分时候可以把它当作Tag对象,是一个特殊的Tag,我们可以分别获取它的类型,名称,以及属性来感受一下

例7:

from bs4 import BeautifulSoup #导入bs4库

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 href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""

soup = BeautifulSoup(html,"lxml")#指定解析器,创建beautifulsoup对象

soup_name = soup.name
print(soup_name)
print(type(soup_name))

soup_attrs = soup.attrs
print(soup_attrs)

"""
[document]
<class 'str'>
{}
"""

Comment

Comment 对象是一个特殊类型的NavigableString对象,其实输出的内容仍然不包括注释符号,但是如果不好好处理它,可能会对我们的文本处理造成意想不到的麻烦

例8:找一个带注释的标签

from bs4 import BeautifulSoup #导入bs4库

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 href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""

soup = BeautifulSoup(html,"lxml")#指定解析器,创建beautifulsoup对象

print("a标签的tag对象为:",soup.a)
print("a标签内的数据为:",soup.a.string)  #a标签内的数据为一个注释
print("a标签内的数据的类型为:",type(soup.a.string))

"""
a标签的tag对象为: <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
a标签内的数据为:  Elsie 
a标签内的数据的类型为: <class 'bs4.element.Comment'>
"""

注:a标签里的内容实际上是注释,但是如果我们利用 .string 来输出它的内容,我们发现它已经把注释符号去掉了,所以这可能会给我们带来不必要的麻烦

补充

获取Tag对象

获取某个指定的tag有两种情况:一种是获取指定的第一个标签(这种实际中用得很少),另一种是获取指定的全部标签对

获取指定的第一个标签

获取指定的第一个标签就是使用前面介绍的"soup对象.标签名"

例9:soup对象.标签名

from bs4 import BeautifulSoup

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 href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""

soup = BeautifulSoup(html,"lxml")#一个<class 'bs4.BeautifulSoup'>

tag_p = soup.p
print("p标签对为:",tag_p)

tag_a = soup.a
print("a标签对为:",tag_a)

"""
p标签对为: <p class="title" name="dromouse"><b>The Dormouse's story</b></p>
a标签对为: <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
"""

注:由上面的结果可以看出
1、获取某个标签对可以使用:soup对象.标签名

2、只是使用这种方法:只能获得整个文档中第一个符合要求的标签(存在多个一样的标签对时只会返回第一个)

3、如果想要的标签对中镶嵌了其他标签对,那么也会把里面镶嵌的标签对一起返回

4、这种方法在实际运用中发现:不能把标签名定义成变量,就是不能通过变量来批量获得一些标签对,所以这种方法有比较大的局限性

获取指定的全部标签对

1、要获取一个文档中某个指定的所有标签,就需要使用find_all()方法:BeautifulSoup对象或Tag对象都可以使用find_all()或find()方法来找其下面的子标签(只是查找范围不一样:BeautifulSoup对象->整个xml对象内,Tag对象->该Tag对象内)

2、其参数可以是很多类型,最常用的是:传入需要获取的标签的标签名

3、find_all()方法返回的是一个由所有符合要求的标签组成的列表

4、find_all()方法这里只是简单的介绍了,后面会详细介绍

5、个人感觉:就是不管HTML或XML文档中有无重复的标签,都最好用find_all()方法来找对应的Tag对象

例9_1:find_all()

from bs4 import BeautifulSoup

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 href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""

soup = BeautifulSoup(html,"lxml")

tag_body = soup.find_all("p") #获取所有p标签的tag对象
print("p标签对为:",tag_body)

tag_a = soup.find_all("a")    #获取所有a标签的tag对象
print("a标签对为:",tag_a)

"""
p标签对为: [<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" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>, <p class="story">...</p>]
a标签对为: [<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
"""

注:由上面的结果可以看出
1、find_all()方法用于返回整个文档中所有符合要求的标签对:返回值是由所有符合要求的tag对象组成的列表(遍历后就是一个个tsg对象)

2、同样的方法还有find()方法:只是说find()方法只是返回第一个符合要求的标签对

3、使用这种方法的话,就可以将标签名定义成变量,所以感觉这种方法比较好

tag对象的name和attrs属性

1、感觉解析过程就是:soup对象->Tag对象->通过tag对象的name、attrs和另外的string属性来获取想要的数据

2、只要是一个tag对象,就可以使用name、attrs和另外的string属性

例10:

from bs4 import BeautifulSoup

html = """
<html>
 <head>
  <title>The Dormouse's story</title>
 </head> 
 <body> 
  <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 href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, 
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and 
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.
  </p> 
  <p class="story">...</p>
 </body>
</html>

"""

soup = BeautifulSoup(html,"lxml")

tag_a_name = soup.a.name
print("a标签对name属性为:",tag_a_name)

tag_a_attrs = soup.a.attrs
print("a标签对attrs属性为:",tag_a_attrs)

"""
a标签对name属性为: a
a标签对attrs属性为: {'href': 'http://example.com/elsie', 'class': ['sister'], 'id': 'link1'}
"""

注:
1、可以使用:soup.标签名.attrs或soup.标签名.name来获得标签对的name和attrs属性
    ⑴其实分开来看就是先使用soup.标签名来返回tag对象,然后使用tag对象.name、tag对象.attrs来获得name和attrs,以及tag对象.string来获得标签对之间的数据

2、使用这种方法的话也是:只会返回第一个符合要求的标签名的name和attrs(因为返回的只有一个tag对象)

3、标签对的attrs属性返回值是一个字典,可以对其使用字典的方法

4、tag的属性可以被添加,删除或修改,与字典处理方法一致,如:tag['class'] = 'verybold'

例10_1:

from bs4 import BeautifulSoup

html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""

soup = BeautifulSoup(html,"lxml")

def parse_msg(tagName):
    tags = soup.find_all(tagName) #find_all()返回的是一个由tag对象组成的列表,因此需要遍历
    for tag in tags:
        print("标签的tag对象为为:", tag)
        print("标签的名称为:",tag.name)
        print("标签的属性为:",tag.attrs)
        print("标签的数据为:", tag.string)

parse_msg("a")
parse_msg("p")


"""
标签的tag对象为为: <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
标签的名称为: a
标签的属性为: {'class': ['sister'], 'href': 'http://example.com/elsie', 'id': 'link1'}
标签的数据为:  Elsie 
标签的tag对象为为: <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
标签的名称为: a
标签的属性为: {'class': ['sister'], 'href': 'http://example.com/lacie', 'id': 'link2'}
标签的数据为: Lacie
标签的tag对象为为: <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
标签的名称为: a
标签的属性为: {'class': ['sister'], 'href': 'http://example.com/tillie', 'id': 'link3'}
标签的数据为: Tillie

标签的tag对象为为: <p class="story">Once upon a time there were three little sisters; and their names were
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
标签的名称为: p
标签的属性为: {'class': ['story']}
标签的数据为: None
标签的tag对象为为: <p class="story">...</p>
标签的名称为: p
标签的属性为: {'class': ['story']}
标签的数据为: ...
"""

注:
1、上面的流程就是:先使用find_all()方法获取所有符合要求的tag对象组成的列表,然后遍历出每一个tag对象,最后获得每一个tag对象的name、attrs属性以及string

2、也可以可以使用soup.标签名["属性名"]来获取指定名字的attrs属性

2、这种嵌套在里面的标签对,如果返回的是外层的tag对象,那也只能获得外层tag对象的name和attrs属性

NavigableString对象

1、即可以遍历的字符串:就是被包含在tag内的字符串

例11:

from bs4 import BeautifulSoup

html = """ 
<html>
 <head>
  <title>The Dormouse's story</title>
 </head> 
 <body> 
  <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 href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, 
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and 
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.
  </p> 
  <p class="story">...</p>
 </body>
</html>
"""
soup = BeautifulSoup(html,"lxml")

tag_a_string = soup.a.string
print("第一个a标签对中的字符串:",tag_a_string)
print(type(tag_a_string))

for tag_a_name in  soup.find_all("a"):
    print("as标签对name属性为:",tag_a_name.string)

"""
第一个a标签对中的字符串: Elsie
<class 'bs4.element.NavigableString'>
as标签对name属性为: Elsie
as标签对name属性为: Lacie
as标签对name属性为: Tillie
"""

注:从上面的输出结果可以看出
1、获取标签对中的NavigableString对象,可以使用:soup对象.标签名.string的方法来获取(跟前面name或attrs一样,只是说这里的字符串属于另一个对象)。且这种方法只会返回第一个符合要求的标签对中的字符串

2、也可以先试用find_all()的方法先找出全部符合要求的标签对,然后遍历得到每一个标签对内的字符串

3、返回的是一个NavigableString对象:可以通过str()方法可以直接将NavigableString对象转换成Unicode字符串

4、如果想在Beautiful Soup之外使用NavigableString对象,需要调用str()方法,将该对象转换成普通的Unicode字符串,否则就算Beautiful Soup已方法已经执行结束,该对象的输出也会带有对象的引用地址.这样会浪费内存

5、tag中包含的字符串不能编辑,但是可以被替换成其它的字符串,用replace_with()方法(后面单独介绍吧)
 

解析XML文档

1、使用BeautifulSoup同样能解析XML文档,解析XML文档的方法、步骤与解析HTML文档一样

2、只是说在解析XML文档时最好指定解析器为"xml"

例12:

from bs4 import BeautifulSoup

html = """
<?xml version="1.0" encoding="utf-8"?>
<data> 
  <time>20200706</time>  
  <country name="Liechtenstein"> 
    <rank>1</rank>  
    <year type="year">2008</year>  
    <year type="month" date="week">11</year>  
    <gdppc>141100</gdppc>  
    <neighbor name="Austria" direction="E"/>
  </country>  
</data>
"""

soup = BeautifulSoup(html, 'xml')   # 使用xml解析器,将一个文件或字符串转为BeautifulSoup对象
# print(type(soup)) #返回一个<class 'bs4.BeautifulSoup'>
# print(soup.prettify()) #格式化输出HTML文件

tag_year = soup.find_all("year")  # find_all()方法返回文档中全部的year标签组成的列表
print("year标签对有:", tag_year)
for i in tag_year:
    print("返回的标签类型为:", type(i))  # 返回的是一个字符串型的Tag对象,可以直接使用str()方法进行强转换
    print(i.name)   # 通过Tag对象的name属性来获得标签的名字
    print(i.attrs)  # 通过Tag对象的attrs属性来获得标签的属性(为属性名与属性值组成的字典)
    print(i.string)  # 通过Tag对象的string属性来获得标签对中的数据(值)

"""
year标签对有: [<year type="year">2008</year>, <year date="week" type="month">11</year>]
返回的标签类型为: <class 'bs4.element.Tag'>
year
{'type': 'year'}
2008

返回的标签类型为: <class 'bs4.element.Tag'>
year
{'type': 'month', 'date': 'week'}
11
"""

例13:

from bs4 import BeautifulSoup

"""
解析目标:将标签名及其数据组成字典
[{标签名:值},{标签名:值}]
"""

msg = """
<?xml version="1.0" encoding="utf-8"?>
<breakfast_menu> 
  <food> 
    <name>Belgian Waffles</name>  
    <price>$5.95</price>  
    <description>two of our famous Belgian Waffles with plenty of real maple syrup</description>  
    <calories>650</calories> 
  </food>  
  <food> 
    <name>Strawberry Belgian Waffles</name>  
    <price>$7.95</price>  
    <description>light Belgian waffles covered with strawberries and whipped cream</description>  
    <calories/>
  </food> 
</breakfast_menu>
"""

def parse_msg(msg):
    soup = BeautifulSoup(msg, 'xml')
    # 通过xml可以看到,我们需要的数据都在"food"标签下面,且"food"标签可以存在一个或多个,
    # 因此可以先找到"food"标签,然后依次根据"food"标签来找其下面的子标签
    foods = soup.find_all("food")
    food_info_list = []
    for food in foods:
        # 获取所需标签值
        # food标签下name标签不会存在多个,因此使用find()方法比较方便,这里只是演示下find_all()方法
        food_name = food.find_all("name")[0].string
        food_price = food.find("price").string
        food_calories = food.find("calories").string
        food_info = {"name":food_name,"price":food_price,"calories":food_calories}
        food_info_list.append(food_info)
    return food_info_list

food_info_list = parse_msg(msg)
print(food_info_list)

"""
输出:
[{'name': 'Belgian Waffles', 'calories': '650', 'price': '$5.95'}, {'name': 'Strawberry Belgian Waffles', 'calories': None, 'price': '$7.95'}]
这里是找"标签名:值",也可以用同样的方法来找"标签名:属性值"等等
"""

注:

本文是在按照Beautiful Soup 4.2.0 文档学习时记录的。只是为了方便自己以后学习和搜索的,文章中肯定会有错误或者遗漏的,因此如果有幸被您看到,可以直接参考其官方文档:

https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#string

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐