一.介绍:

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. 深入GCD(一): 基本概念和Dispatch Queue

    什么是GCD?Grand Central Dispatch或者GCD,是一套低层API,提供了一种新的方法来进行并发程序编写.从基本功能上讲,GCD有点像NSOperationQueue,他们都允许程 ...

  2. 初探STL之算法

    算法 STL算法部分主要由头文件<algorithm>,<numeric>,<functional>组成.要使用 STL中的算法函数必须包括头文件<algor ...

  3. Cg入门8:Vertex Shader - 更好的数据组织方式struct

    数据结构的使用:与C语言语法一样 參数的传递:參数匹配的是映射的语义的类型 输入输出:採用结构体,输入输出相应的參数的in和out可省略.函数的參数结构体就是输入參数集,函数的返回结构体就是输出參数集 ...

  4. Linux-----Ubuntu设置开机启动模式

  5. Objective-C之成魔之路【10-继承性】

    郝萌主倾心贡献.尊重作者的劳动成果.请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠,支持郝萌主.捐赠数额任意.重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 继承性是面 ...

  6. mybatis一对多

    mapper.xml <mapper namespace="com.oracle.dao.one2manyDao"> <resultMap type=" ...

  7. Eclipse搭建Web Service服务

    1.建立动态Web工程(Dynamic Web Project),工程名为Server.编写类HelloWorld. package com.mysever; public class HelloWo ...

  8. (org.openqa.selenium.WebDriverException: Unable to launch the app: Error: Trying to start logcat capture but it's already started! )错误解决办法

    新增: capabilities.setCapability("autoLaunch",false); 将setup中的: driver = new AndroidDriver(n ...

  9. 图像处理之 opencv 学习---矩阵的操作

    OpenCV的一些操作,如生成随机矩阵,高斯矩阵,矩阵相乘之类的 /*功能:说明矩阵的一些操作方法*/#include "cv.h"//该头文件包含了#include " ...

  10. visual studio 2013 update 3正式版出来了

    微软的更新速度还是蛮快的吗.新版本号出来了,大家快下载体验一下吧,详细下载地址在http://www.visualstudio.com/zh-cn/downloads/download-visual- ...