一.介绍:

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. [Javascript] Convert a Callback-Based JavaScript Function to a Promise-Based One

    Sometimes, you might want to convert a JavaScript function that accepts a callback to one that retur ...

  2. 利用反射技术实现POJO的数据库操作

    记得第一次写项目的时候,傻傻的数据库一张表,代码里就写一个DAO类,几张表就写几个DAO类,大量的反复代码,自己粘着都嫌烦,后来接触了Hibernate,不得不说对我们这样的小白用处还是非常大的.那么 ...

  3. 高速清除winXP系统中explorer.exe病毒

    关于这个explorer.exe病毒.是眼下xp最为常见的一个病毒,会大量的消耗系统资源,造成电脑特别的卡顿. 1.关闭还原(假设没有,则跳过),为的是防止我们改动后,还原之后又回来了. 2.打开注冊 ...

  4. HTML页面底部无用留白

    HTML页面底部无用留白,可以再footer样式中加入: overflow: hidden; 如有错误,请您指正~

  5. SQL获取事件探查器保存的跟踪文件

    fn_trace_gettable (Transact-SQL) 以表格格式返回一或多个跟踪文件的内容. Transact-SQL 语法约定 语法 fn_trace_gettable ( filena ...

  6. 【转载】Http协议与TCP协议简单理解

    在C#编写代码,很多时候会遇到Http协议或者TCP协议,这里做一个简单的理解.TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性.Http协议是建立在TCP协议基础之上 ...

  7. iOS多线程编程指南

    iOS多线程编程指南(拓展篇)(1) 一.Cocoa 在Cocoa上面使用多线程的指南包括以下这些: (1)不可改变的对象一般是线程安全的.一旦你创建了它们,你可以把这些对象在线程间安全的传递.另一方 ...

  8. No Memory Alignment with GCC

    attribute method: #include <stdio.h> struct packed { char a; int b; } __attribute__((packed)); ...

  9. linux学习:进程间通信—管道

    1.进程间通信当中一种比較简单的方法是管道操作 /* ========================================================================= ...

  10. 利用BADI WORKORDER_INFOSYSTEM在COOIS中加入自己定义列办事处

    需求描写叙述:依据LC业务部门提出的需求.须要在COOIS中加入办事处一列. 1.在IOHEADER_TAB的CI_IOHEADER中加入字段办事处.如以下图所看到的:   watermark/2/t ...