专为HTML解析设计的强大工具——Beautiful Soup
在我们先前进行网站页面内容解析的过程中,通常选择运用正则表达式来完成此任务。然而,正如前面几篇文章所阐述和分析的那样,无论是正则表达式还是XPath,它们虽各自具备适应不同应用场景的优势,却也都存在着各自难以避免的缺陷。例如,正则表达式具有相对复杂的语法结构并且需要大量的编程知识才能熟练掌握;而XPath虽然使得实现路径查找更为简洁易懂,但却需要编写复杂的节点路径编码。因此,为了充分利用HTML读取技术的强大功能,同时追求更加简明直观的操作体验,本文将向您推荐Beautiful Soup这款强大的三方工具。那么,它是否能够如其名字那般“美丽”呢?接下来,让我们共同揭开这个谜团!
Beautiful Soup 也是一个 Python 的 XML 和 HTML 的解析库,其提供了简单的,Python 式的函数来处理导航,搜索,修改分析树等功能(来自官方介绍)。
开始使用
在使用 Beautiful Soup 之前,需要安装好 lxml(推荐 lxml 解析器) 和其自身的库。
pip install beautifulsoup4
pip install lxml
beautiful Soup 在解析过程中依赖各种解析器,除了支持 Python 标准的解析器外,还支持其他的三方解析器(如: lxml)。
一般在使用的过程中,推荐使用 lxml,因为 lxml 本身也是一个非常优秀的解析库,也支持 XML 的解析。
假设有以下内容的 html 文档。
<!DOCTYPE html>
<html lang="en">
<body>
<div>
<ul>
<li class="class-0">
<a href="a.html">
<span>第一个标签</span>
</a>
</li>
</ul>
</div>
</body>
</html>
from bs4 import BeautifulSoup
# 初始化BeautifulSoup,并指定lxml为解析器
soup = BeautifulSoup(open("index.html"),
"lxml")
# 获取span标签
print(soup.span)
print(soup.span.string)
# <span>第一个标签</span>
# 第一个标签
如上代码,BeautifulSoup 方法有有两个参数, 第一个参数接受一个 html 文档,第二个参数指定解释器类型,这样就初始化了一个BeautifulSoup 的对象,后续就可以使用这个对象来解析和获取 HTML 中的数据,如上方获取 span, 并获取 span 的内容。
获取 bs 对象有两种方式,一种是直接使用文本字符,另一种是读取文档:
from bs4 import BeautifulSoup
soup = BeautifulSoup(open("index.html"))
soup = BeautifulSoup("<html>data</html>")
元素选择
通过上边的代码示例可以看到,在获取到 bs 对象后,后续直接调用节点名称就可以获取到节点对象,再调用 string 属性就可以获取到节点的文本内容,相较于使用正则表达式或者 XPath 效率是非常高的。
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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')
# 获取title标签
soup.title
# <title>The Dormouse's story</title>
#获取title标签名字
soup.title.name
# u'title'
#获取title标签文本内容
soup.title.string
# u'The Dormouse's story'
#获取title父标签
soup.title.parent.name
# u'head'
#获取p标签
soup.p
# <p class="title"><b>The Dormouse's story</b></p>
#获取p标签的class属性
soup.p['class']
# u'title'
# 获取a标签
soup.a
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
# 查找所有的a标签
soup.find_all('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>]
# 查找id为link3的标签
soup.find(id="link3")
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
对象种类
虽然在 Beautiful Soup 中可以将复杂的 HTML 文档转换为树形结构,但是从大体可归纳为以下 4 个对象:
Tag:Tag 对象用于表示 HTML 和 XML 文档中的 tag 标签。
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
type(tag)
# <class 'bs4.element.Tag'>
tag.name
# u'b'
tag['class']
# u'boldest'
如上任何的标签在Beautiful Soup 都表示为一个 Tag 对象,且从该对象上获取到当前标签的各种属性值。
NavigableString :表示 Tag 中被包裹的字符串
tag.string
# u'Extremely bold'
type(tag.string)
# <class 'bs4.element.NavigableString'>
BeautifulSoup :该对象表示文档整体的一个类,即初始化后获得的类,所以获取到该类,就获取到了整个文档。需要注意需要和上边 Tag 类做出区分,BeautifulSoup 类是特殊的 Tag 类。
Comment :表示文档中的注释内容,其本质也是一个特殊的NavigableString 对象,但由于其特殊性,单独做封装处理。
使用 CSS 选择器选择节点
除了上边的属性选择器和方法选择器外,Beautiful Soup 还提供 CSS 选择器,这对于有前端样式开发经验的同学来说是非常给力的一个特性。通过 CSS 选择器也可以轻松的选定各个节点,但在使用中和上边的有所不同需要调用 .selsect() 方法, 如下方代码:
soup.select("title")
# [<title>The Dormouse's story</title>]
soup.select("p:nth-of-type(3)")
# [<p class="story">...</p>]
有不熟悉css选择器的小伙伴可以在w3c上学习,一般基础的选择器就可胜任绝大多数数据获取的任务。