一.介绍:

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.你可能在寻找 Beautiful Soup3 的文档,Beautiful Soup 3 目前已经停止开发,官网推荐在现在的项目中使用Beautiful Soup 4, 移植到BS4。安装步骤如下:

#安装 Beautiful Soup  我们在爬虫中一般推荐使用lxml解析器,因为其爬取效率比较高
pip install beautifulsoup4 #安装解析器
Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml .根据操作系统不同,可以选择下列方法来安装lxml: $ apt-get install Python-lxml $ easy_install lxml $ pip install lxml 另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib: $ apt-get install Python-html5lib $ easy_install html5lib $ pip install html5lib

下表列出了主要的解析器,以及它们的优缺点,官网推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定.

解析器 使用方法 优势 劣势
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格式的文档
  • 速度慢
  • 不依赖外部扩展

中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html

二.基本使用

html_doc = """
<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>
""" #基本使用:容错处理,文档的容错能力指的是在html代码不完整的情况下,使用该模块可以识别该错误。使用BeautifulSoup解析上述代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出
from bs4 import BeautifulSoup
soup=BeautifulSoup(html_doc,'lxml') #具有容错功能
res=soup.prettify() #处理好缩进,结构化显示
print(res)

1.通过标签寻定位,如果有多个标签,那么只返回第一个,看下面的例子:

# 遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p id="my p" class="title"><b id="bbb" class="boldest">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>
""" # 、用法
from bs4 import BeautifulSoup soup = BeautifulSoup(html_doc, 'lxml') # 第一个参数直接是一个标签文档字符串
# soup=BeautifulSoup(open('a.html'),'lxml') # 第一个参数是一个文件句柄对象 print(soup.p) # 存在多个相同的标签则只返回第一个
print(soup.a) # 存在多个相同的标签则只返回第一个

打印结果如下:

print(soup.p) 上面有2个p标签,只返回找到的第一个p标签
<p class="title" id="my p"><b class="boldest" id="bbb">The Dormouse's story</b></p> print(soup.a) 只返回找到的第一个a标签
<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>

2.获取标签的属性:

# _*_ coding:utf- _*_
# 遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b>111</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>
""" # 、用法
from bs4 import BeautifulSoup soup = BeautifulSoup(html_doc, 'lxml') # 第一个参数直接是一个标签文档字符串
# # soup=BeautifulSoup(open('a.html'),'lxml') # 第一个参数是一个文件句柄对象
#
# print(soup.p) # 存在多个相同的标签则只返回第一个
# # print(soup.a) # 存在多个相同的标签则只返回第一个
#
# # 、获取标签的名称
# print(soup.p.name) # 打印 p
#
# # 、获取标签的属性
# """
# 打印找到的第一个p标签的属性,属性被封装为字典: {'class': ['title'], 'id': 'my p'}
# 原始找到的p标签为:<p class="title" id="my p"><b class="boldest" id="bbb">The Dormouse's story</b></p>
# """
# print(soup.p.attrs) # # 、获取标签的内容
"""
表示查看p标签下的文本,只寻找一个,如果里面有多个标签或者文本,则打印None
当第一个p标签如下所示时:<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b></p>
打印出The Dormouse's story
当p标签如下所示时:<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b>
</p>
相当于多了一个换行符,那么就打印出None
又或者当p标签如下所示时:<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b>111</p>
此时有两个文本内容The Dormouse's story和111,此时soup不知道要找哪个,所以为None """
# print(soup.p.string) # p下的文本只有一个时,取到,否则为None
# print(soup.p.strings) # 拿到一个生成器对象, 取到p标签下下所有的文本内容
# # 打印结果:<generator object _all_strings at 0x000002A324FAF3B8>
# print(list(soup.p.strings)) # 打印结果: ["The Dormouse's story", '']
"""
查看soup文档对象中的所有标签文本: 使用stripped_strings去除很多空行:
打印结果如下:
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
;
and they lived at the bottom of a well.
...
"""
# for line in soup.stripped_strings: # 去掉空白
# print(line) '''
如果tag包含了多个子节点,tag就无法确定 .string 方法应该调用哪个子节点的内容, .string 的输出结果是 None,如果只有一个子节点那么就输出该子节点的文本,比如下面的这种结构,soup.p.string 返回为None,但soup.p.strings就可以找到所有文本
<p id='list-1'>
哈哈哈哈
<a class='sss'>
<span>
<h1>aaaa</h1>
</span>
</a>
<b>bbbbb</b>
</p>
'''

接着看下面的:

# _*_ coding:utf- _*_
# 遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p id="my p" class="title">
aaa<b id="bbb" class="boldest">The Dormouse's story</b>ddd
<ul>
spark很重要
<li>python</li>
</ul>
</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>
""" # 、用法
from bs4 import BeautifulSoup soup = BeautifulSoup(html_doc, 'lxml') # 第一个参数直接是一个标签文档字符串
# # soup=BeautifulSoup(open('a.html'),'lxml') # 第一个参数是一个文件句柄对象
#
# print(soup.p) # 存在多个相同的标签则只返回第一个
# # print(soup.a) # 存在多个相同的标签则只返回第一个
#
# # 、获取标签的名称
# print(soup.p.name) # 打印 p
#
# # 、获取标签的属性
# """
# 打印找到的第一个p标签的属性,属性被封装为字典: {'class': ['title'], 'id': 'my p'}
# 原始找到的p标签为:<p class="title" id="my p"><b class="boldest" id="bbb">The Dormouse's story</b></p>
# """
# print(soup.p.attrs) # # 、获取标签的内容
"""
表示查看p标签下的文本,只寻找一个,如果里面有多个标签或者文本,则打印None
当第一个p标签如下所示时:<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b></p>
打印出The Dormouse's story
当p标签如下所示时:<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b>
</p>
相当于多了一个换行符,那么就打印出None
又或者当p标签如下所示时:<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b>111</p>
此时有两个文本内容The Dormouse's story和111,此时soup不知道要找哪个,所以为None """
# print(soup.p.string) # p下的文本只有一个时,取到,否则为None
# print(soup.p.strings) # 拿到一个生成器对象, 取到p标签下下所有的文本内容
# # 打印结果:<generator object _all_strings at 0x000002A324FAF3B8>
# print(list(soup.p.strings)) # 打印结果: ["The Dormouse's story", '']
"""
查看soup文档对象中的所有标签文本: 使用stripped_strings去除很多空行:
打印结果如下:
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
;
and they lived at the bottom of a well.
...
"""
# for line in soup.stripped_strings: # 去掉空白
# print(line) '''
如果tag包含了多个子节点,tag就无法确定 .string 方法应该调用哪个子节点的内容, .string 的输出结果是 None,如果只有一个子节点那么就输出该子节点的文本,比如下面的这种结构,soup.p.string 返回为None,但soup.p.strings就可以找到所有文本
<p id='list-1'>
哈哈哈哈
<a class='sss'>
<span>
<h1>aaaa</h1>
</span>
</a>
<b>bbbbb</b>
</p>
''' # 、嵌套选择 打印结果:The Dormouse's story
# print(soup.head.title.string)
# 由于此时有三个a标签,但是这样嵌套寻找只找到第一个,所以只打印出Elsie
# print(soup.body.a.string) # 、子节点、子孙节点
"""
打印结果如下所示:
[<b class="boldest" id="bbb">The Dormouse's story</b>, '']
可以看到这样也只是定位到第一个p标签:
<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b>111</p>
相当于打印的就是第一个p标签内部的所有元素,包括子节点和文本,我们再来测试下:
<p id="my p" class="title">
aaa<b id="bbb" class="boldest">The Dormouse's story</b>ddd
<ul>
spark很重要
<li>python</li>
</ul>
</p> 这是文档中的第一个p标签,那么print(soup.p.contents)的打印结果如下:
['\n aaa', <b class="boldest" id="bbb">The Dormouse's story</b>, 'ddd\n ']
可以看到它找到的是第一个子标签和子文本
"""
# print(soup.p.contents) #p下所有子节点
# print(soup.p.children) #得到一个迭代器,包含p下所有子节点
# print(list(soup.p.children))
# <list_iterator object at 0x000001FD6AA47A20>
# ['\n aaa', <b class="boldest" id="bbb">The Dormouse's story</b>, 'ddd\n ']
"""
打印结果如下: aaa
<b class="boldest" id="bbb">The Dormouse's story</b>
ddd """
# for i,child in enumerate(soup.p.children):
# print(i,child) """
打印结果如下:
<generator object descendants at 0x0000017D7863F3B8>
['\n aaa', <b class="boldest" id="bbb">The Dormouse's story</b>, "The Dormouse's story", 'ddd\n ']
"""
# print(soup.p.descendants) # 获取子孙节点,p下所有的标签都会选择出来
# print(list(soup.p.descendants))
# for i, child in enumerate(soup.p.descendants):
# print(i, child)
#
# #、父节点、祖先节点
# print(soup.a.parent) # 获取a标签的父节点,其父节点是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>
"""
# print(soup.a.parents) # 找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲...
# print(list(soup.a.parents)) # 、兄弟节点
# print('=====>')
# print(soup.a.next_sibling) #下一个兄弟
# print(soup.a.previous_sibling) #上一个兄弟
#
print(list(soup.a.next_siblings)) #下面的兄弟们=>生成器对象
print(soup.a.previous_siblings) #上面的兄弟们=>生成器对象

继续看bs中的五种过滤器

# _*_ coding:utf- _*_

# 搜索文档树:BeautifulSoup定义了很多搜索方法,这里着重介绍2个: find() 和 find_all() .其它方法的参数和用法类似
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p id="my p" class="title"><b id="bbb" class="boldest">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>
""" from bs4 import BeautifulSoup soup = BeautifulSoup(html_doc, 'lxml') # 、五种过滤器: 字符串、正则表达式、列表、True、方法
# 1.1、字符串:即标签名
# print(soup.find_all('b'))
"""
结果是一个列表:
[<b class="boldest" id="bbb">The Dormouse's story</b>]
""" # 1.2、正则表达式
import re
#
# print(soup.find_all(re.compile("^b"))) # 找出b开头的标签,结果有body和b标签
"""
打印结果如下:
[<body>
<p class="title" id="my p"><b class="boldest" id="bbb">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>
</body>, <b class="boldest" id="bbb">The Dormouse's story</b>] """
#
# # 1.3、列表:如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.下面代码找到文档中所有<a>标签和<b>标签:
# print(soup.find_all(['a', 'b']))
"""
返回结果仍然是一个列表:
[<b class="boldest" id="bbb">The Dormouse's story</b>,
<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.4、True:可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点
# print(soup.find_all(True))
# 例如我再需要查找到文档中所有包含id的标签:
# print(soup.find_all(id=True))
"""
返回结果如下,是一个列表:
[<p class="title" id="my p"><b class="boldest" id="bbb">The Dormouse's story</b>
</p>, <b class="boldest" id="bbb">The Dormouse's story</b>,
<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>]
"""
"""
找到文档中的所有标签: """
# for tag in soup.find_all(True):
# print(tag.name)
#
#
# # 1.5、方法:如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 ,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False
"""
下面方法表示寻找到标签中有class属性,但是没有id属性的标签,打印结果如下:
[<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>]
可以看到两个p标签只有class属性,但是没有id属性
"""
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id') print(soup.find_all(has_class_but_no_id))

重点方法之find_all( name , attrs , recursive , text , **kwargs )

Python网络爬虫之BeautifulSoup模块的更多相关文章

  1. 04.Python网络爬虫之requests模块(1)

    引入 Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用. 警告:非专业使用其他 HTTP 库会导致危险的副作用,包括:安全缺陷症.冗余代码症.重新发明轮子症.啃文档 ...

  2. Python网络爬虫之requests模块(1)

    引入 Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用. 警告:非专业使用其他 HTTP 库会导致危险的副作用,包括:安全缺陷症.冗余代码症.重新发明轮子症.啃文档 ...

  3. 04,Python网络爬虫之requests模块(1)

    引入 Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用. 警告:非专业使用其他 HTTP 库会导致危险的副作用,包括:安全缺陷症.冗余代码症.重新发明轮子症.啃文档 ...

  4. 06.Python网络爬虫之requests模块(2)

    今日内容 session处理cookie proxies参数设置请求代理ip 基于线程池的数据爬取 知识点回顾 xpath的解析流程 bs4的解析流程 常用xpath表达式 常用bs4解析方法 引入 ...

  5. Python网络爬虫之requests模块(2)

    session处理cookie proxies参数设置请求代理ip 基于线程池的数据爬取 xpath的解析流程 bs4的解析流程 常用xpath表达式 常用bs4解析方法 引入 有些时候,我们在使用爬 ...

  6. Python网络爬虫之requests模块

    今日内容 session处理cookie proxies参数设置请求代理ip 基于线程池的数据爬取 知识点回顾 xpath的解析流程 bs4的解析流程 常用xpath表达式 常用bs4解析方法 引入 ...

  7. python网络爬虫之解析网页的BeautifulSoup(爬取电影图片)[三]

    目录 前言 一.BeautifulSoup的基本语法 二.爬取网页图片 扩展学习 后记 前言 本章同样是解析一个网页的结构信息 在上章内容中(python网络爬虫之解析网页的正则表达式(爬取4k动漫图 ...

  8. 【python网络爬虫】之requests相关模块

    python网络爬虫的学习第一步 [python网络爬虫]之0 爬虫与反扒 [python网络爬虫]之一 简单介绍 [python网络爬虫]之二 python uillib库 [python网络爬虫] ...

  9. 利用Python网络爬虫采集天气网的实时信息—BeautifulSoup选择器

    相信小伙伴们都知道今冬以来范围最广.持续时间最长.影响最重的一场低温雨雪冰冻天气过程正在进行中.预计,今天安徽.江苏.浙江.湖北.湖南等地有暴雪,局地大暴雪,新增积雪深度4-8厘米,局地可达10-20 ...

随机推荐

  1. send to instance already dealloc nil error

    这个是因为发送消息的对象已经被dealloc了,然后再次发送[release]请求就不行了.所以可以retain或者alloc对象 if (self.buttonsList) {            ...

  2. 使用Myeclipse + SVN + TaoCode 免费实现项目版本控制的详细教程

    通过Myeclipse + SVN插件 + TaoCOde可以省去代码仓库的租建:同时还可以很好的满足小团队之间敏捷开发的需求.接下来详细介绍整个搭建流程. 首先,介绍所用到的工具: 1,Myecli ...

  3. HeatMap(热图)的原理和实现

    先来看两张图: (1)10年世界杯决赛,冠军西班牙队中门将.后卫.中场及前锋的跑位热图 通过热图,我们可以很清楚的看出四个球员在比赛中跑动位置的差异. (2)历史地震震源位置的热图 也可以很清楚的看出 ...

  4. Mysql 之配置文件my.cnf

    mysql配置文件为my.cnf,它所在位置根据安装时设定的. 当mysqld服务启动的时候,默认会按一定的顺序读取配置文件的. 1 2 3 [root@zhu2 ~]# /opt/mysql/lib ...

  5. 转:给 Android 开发者的 RxJava 详解

    转自:  http://gank.io/post/560e15be2dca930e00da1083 评注:多图解析,但是我还是未看懂. 前言 我从去年开始使用 RxJava ,到现在一年多了.今年加入 ...

  6. ElasticDownload

    https://github.com/eltld/ElasticDownload

  7. Codeforces 558C Amr and Chemistry

    题意: n个数.每次能够选一个数 让其 *=2 或者 /=2 问至少操作多少次使得全部数相等. 思路: 对于每一个数,计算出这个数能够变成哪些数,以及变成那个数的最小步数,用两个数组保存 cnt[i] ...

  8. VMWare 14 Workstation Pro 下载与安装

    1.双击安装运行 2.下一步 3.接受 下一步 4.自定义安装路径,下一步 5.下一步,取消勾选加入vmware客户体验 6.下一步 7.安装 8.安装中 9.完成 10.点击许可证安装 输入:FF3 ...

  9. CentOS7虚拟机桥接设置及问题

    转载请注明出处:jiq•钦's technical Blog  今天在VMWare WorkStation9中安装了CentOS7虚拟机. 虚拟机与宿主机网络连接有三种方式:桥接模式.NAT模式和Ho ...

  10. C系列语言终极校对宝典【第一、第二部分】

    第一部分:基本概念及其它问答题 1.关键字static的作用是什么? 这个简单的问题很少有人能回答完全.在C语言中,关键字static有三个明显的作用: 1). 在函数体,一个被声明为静态的变量在这一 ...