目录
对于一个网页来说,都有一定的特殊结构和层级关系,而且很多节点都有 id,class 来作区分,所以借助它们的结构和属性来提取不也可以吗?介绍一个强大的解析工具 Beautiful Soup ,它借助网页的结构和属性等特性来 解析网页 有了它 ,我们不用再去写一些复杂的正则表达式,只需要简单的几条语句,就可以完成网页中某个元素的提取
Beautiful Soup 简介
Beautful Soup 就是 Python HTML或 XML 的解析库,可以用它来方便地从网页中提取数据:
Beautiful Soup 提供一些简单的、 python式的函数来处理导航、搜索、修改分析树等功能 ,它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
Beaut Soup 自动将输入文档转 Unicode 编码,输出文档转换为 UTF-8 编码 你不需考虑编码方式 ,除非文档没有指 一个编码方式,这时你仅仅需要说明一下原始编码方 式就可以了。
Beautiful Soup 成为和lxml, html6lib 一样出色的 Python 解释器,为用户灵活地提供不同的解析策略或强劲的速度.
解释器
Beautiful Soup 在解析时实际上依赖解析器,它除了支持 Python 标准库中的 HTML 解析器外,还 支持一些第三方解析器(比如 lxml)
通过以上对比可以看出, lxml 解析器有解析 HTML 和 XML 的功能,而且速度’快,容错能力强, 所以推荐使用它
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p>Hellow</p>","lxml")
print(soup.p.string)
基本用法
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="linkl"><! - Elsie … ><la>,
<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"> ... <Ip>
'''
soup = BeautifulSoup(html,"lxml")
print(soup.prettify())
print(soup.title.string)
结果:
<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 class="sister" href="http://example.com/elsie" id="linkl">
<la>
,
<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 .
</la>
</a>
</p>
<p class="story">
...
<ip>
</ip>
</p>
</body>
</html>
The Dormouse ’s story
第一步:首先声明变量html,它是一个HTML字符串,但是需要注意的是,他并不是一个完整的HTML字符串,因为body和html节点都没有闭合,接着,将他们当作第一个参数传给BeautifulSoup对象,该对象第二个参数为解析参数器类型(这里使用lmxl),此时就完成了BeautifulSoup对象的初始化,然后,将这个对象赋值给soup变量
第二步:调用prettify() 方法,这个方法可以把解析的字符串以标准的缩进格式输出,这里需要主义的是,输出结果里面包含body和html节点,也就是说对于不标准的HTML字符串BeautifulSoup可以自动更正格式,这一步prettiry() 方法做的,而是初始化BeautifulSoup时就完成了
第三步:soup.title.string 这实际上是输出HTML中title节点的文本内容。所以,soup.title可以选出HTML中的title节点,再调用string属性就可以得到里面的文本了,所以我们可以通过简单调用几个属性完成文本提取
节点选择器
直接调用节点的名称就可以选择节点元素,再调用string属性就可以得到文本
选择元素
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="linkl"><! - Elsie … ><la>,
<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"> ... <Ip>
'''
soup = BeautifulSoup(html,"lxml")
print(soup.title)
print(type(soup.title))
print(soup.title.string)
print(soup.head)
print(soup.p)
print(soup.p)
结果:
<title>The Dormouse ’s story</title>
<class 'bs4.element.Tag'>
The Dormouse ’s story
<head><title>The Dormouse ’s story</title></head>
<p class="title" name="dromouse"><b>The Dormouse ’s story</b></p>
<p class="title" name="dromouse"><b>The Dormouse ’s story</b></p>
尝试选择了 head 节点,结果也是节点加其内部的所有内容 最后,选择了p 节点 不过这次情况比较特殊,我们发现结果是第一个p 节点的内容,后面的几个p节点 点并没有选到 也就 是说,当有多个节点时,这种选择方式只会选择到第一个匹配的节点,其他的后面节点都会忽略
提起信息
1、提取名称
可以利用name属性获取节点的名称,选取title节点,然后调用name属性就可以得到节点名称
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="linkl"><! - Elsie … ><la>,
<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"> ... <Ip>
'''
soup = BeautifulSoup(html,"lxml")
print(soup.title.name)
结果:
title
2、获取属性
每个节点可能有多个属性,比如id和class等,选择这个节点元素后,可以调用sttrs获取属性
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="linkl"><! - Elsie … ><la>,
<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"> ... <Ip>
'''
soup = BeautifulSoup(html,"lxml")
print(soup.p.attrs)
print(soup.p.attrs['name'])
结果;
{'class': ['title'], 'name': 'dromouse'}
dromouse
attrs 的返回结果是字典格式,是属性和属性值合成一个字典,要获取name 属性,就相当于从字典中获取某个键值,只需要用中括号加属性名就可以使用
还可以再简化
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="linkl"><! - Elsie … >&l