python解析库
1. Beautiful Soup (bs4 )
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.
在测试学习使用bs4的过程中,需要反复用到xml文档。这里就采用bs4官方文档中提供的一个html代码。这是爱丽丝梦游仙境中的一段内容。
<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>
包含一个简单的页面。
下面使用python做简单测试。首先是格式化输出:
# 构造BeautifulSoup 对象,其中html_doc为前文的爱丽丝梦游仙境页面
page = BeautifulSoup(html_doc, 'html.parser')
# 格式化输出
print(page.prettify())
控制台的输出结果为:
<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 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>
</html>
显然这是一个规范的html文件。使用起来实在是太方便了~再探索一下其他的功能吧。
bs4能够很轻松地获取到文档信息,浏览结构化信息。例如,获取页面的title,只需要
page.title.name
需要注意的是,如果使用CSS选择器,应该使用select方法,如:
#查找class为sister的
print('class为sister的(CSS方式查找的):', page.select('.sister'))
#查找id为link2的
print('id为link2的(CSS方式查找的:)', page.select('#link2'))
完整的测试代码:
# 构造BeautifulSoup 对象,其中html_doc为前文的爱丽丝梦游仙境页面
page = BeautifulSoup(html_doc, 'html.parser')
# 格式化输出
# print(page.prettify())
# 获取title相关信息
print('page.title : ', page.title)
print('page.title.name : ', page.title.name)
print('page.title.text : ', page.title.text)
print('page.title.parent.name : ', page.title.parent.name)
# 获取a标签
print('单个a标签:', page.a)
print('所有a标签: ', page.find_all('a'))
# 以css的方式查找 使用select
print('class为sister的(CSS方式查找的):', page.select('.sister'))
print('id为link2的(CSS方式查找的:)', page.select('#link2'))
输出结果为:
page.title : <title>The Dormouse's story</title>
page.title.name : title
page.title.text : The Dormouse's story
page.title.parent.name : head
单个a标签: <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
所有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>]
class为sister的(CSS方式查找的): [<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为link2的(CSS方式查找的:) [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
如果要获取标签中的某一部分,可以使用get方法。例如:获取页面中所有a标签的链接内容。
for line in page.find_all('a'):
print(line.get('href'))
输出为:
http://example.com/elsie
http://example.com/lacie
http://example.com/tillie
如果要获取页面中所有的文字信息,只需要一行代码:
text = page.get_text()
这是bs4一些最基础的用法。遇到问题就查一下官方文档:bs4.4.0官方文档
2. lxml
lxml是一个Python库,使用它可以轻松处理XML和HTML文件,还可以用于web爬取。市面上有很多现成的XML解析器,但是为了获得更好的结果,开发人员有时更愿意编写自己的XML和HTML解析器。这时lxml库就派上用场了。这个库的主要优点是易于使用,在解析大型文档时速度非常快,归档的也非常好,并且提供了简单的转换方法来将数据转换为Python数据类型,从而使文件操作更容易。
2.1 Xpath语言
节点:元素、属性、文本、命名空间、文档节点等。
节点关系:父、字、同胞、先辈、后代等。
表达式 | 描述 |
---|---|
nodename | 选此节点的所有子节点 |
// | 从任意子节点选择 |
/ | 从根节点选择(这里是相对的) |
. | 从当前节点选择 |
.. | 从上一级节点选择 |
@ | 取属性 |
2.2 lxml的使用
首先需要导入lxml库
from lxml import etree
from bs4_sample import html_doc
构造etree
et = etree.HTML(html_doc)
需要使用单个属性获取所需内容
- 变量.tag——标签名——字符串
- 变量.attrib——节点标签a的属性——字典
- 变量.text——标签文本——字符串
通过例子体会:
et = etree.HTML(html_doc)
print(et)
for tag in et:
print("TAG : ", et.tag)
for attrib in et:
print("ATTRIB : ", et.attrib)
for text in et:
print("TEXT : ", et.text)
输出结果为:
TAG : html
TAG : html
ATTRIB : {}
ATTRIB : {}
TEXT : None
TEXT : None
也就是说,et变量实际上是这个html页面的根节点。若执行
print(et)
输出的是
<Element html at 0x1a5b5135b40>
也就是html,也即该页面的最外层:
html测试代码:
for i in range(len(et)):
print(et[i].tag)
输出结果为:
head
body
观察页面的结构,发现html下两个同胞节点为head 和body。如图:
页面结构
获取各个子节点的信息,以类似于多维数组的方式,通过代码实现遍历:
for i in range(len(et)):
print(et[i].tag)
for j in range(len(et[i])):
print(" "+et[i][j].tag)
输出结果为:
head
title
body
p
p
p
与页面标签结构相符。这样就基本理解了etree.HTML(html_doc)语句所生成对象的结构。
下面来做几件爬虫可能需要的工作。
- 检查元素是都有子元素
- 检查节点是都为一个elements
- 检查一个元素是否有父元素
- 检查同胞元素
- 寻找元素
在python代码中依次做这些测试。比较简单,基本方法总结见表:
功能 | 方法 |
---|---|
检查是否存在子元素 | len(et)>0 |
检查是否为element | etree.iselement(et[i])) |
检查是否存在父元素 | getparent() 注意:是方法 不是getparent属性! |
检查同胞元素 | getprevious()和getnext()方法 |
寻找元素 | find()方法 |
代码比较简单,测试结果写在注释中:
# 1.检查元素是都有子元素 ——检查长度
# 1.1 检查根节点是否有子元素
if len(et) > 0:
print("根节点有%s个子元素" % len(et))
else:
print("根节点没有子元素!")
# 1.2检查根节点的子节点是否有子元素
for i in range(len(et)):
if len(et[i]) > 0:
print("%s标签有子节点,第一个子节点为:%s" % (et[i].tag, et[i][0].tag))
else:
print("%s标签没有子节点!" % et[i].tag)
# 此部分的输出结果为:
# 根节点有2个子元素
# head标签有子节点,第一个子节点为:title
# body标签有子节点,第一个子节点为:p
# 2.检查是否为elements etree.iselement(et[i]))
for i in range(len(et)):
print("%s是否为element : %s" % (et[i].tag, etree.iselement(et[i])))
# 此部分输出结果为:
# head是否为element : True
# body是否为element : True
# 3.检查是否存在父元素——getparent() 注意:是方法 不是getparent属性!
print(et.getparent())
for i in range(len(et)):
if et[i].getparent():
print("%s存在父元素!" % et[i].tag)
else:
print("%s不存在父元素!" % et[i].tag)
# 此部分输出结果:
# None
# head存在父元素!
# body存在父元素!
# 4.检查同胞——getprevious()和getnext()方法
# 代码略
# 5.寻找元素
print(et[1].find('p'))
print(et[1].find('p').tag)
# 此部分输出结果:
# <Element p at 0x1b688db5c40>
# p
2.3 lxml的xpath方法
取出所有的a标签中的href链接:et.xpath('//a/@href')
x = et.xpath('//a/@href')
for i in range(len(x)):
print(x[i])
输出结果为:
http://example.com/elsie
http://example.com/lacie
http://example.com/tillie