解析库的使用——学习笔记

本文详细介绍了Python中用于网页解析的三大库:XPath、BeautifulSoup和PyQuery的使用方法。XPath提供简洁的路径选择表达式,包括选择节点、属性匹配、文本获取等功能。BeautifulSoup提供了多种选择器,如find_all()和select(),支持CSS选择器。PyQuery类似jQuery,提供快速的CSS选择和操作。文章深入浅出地展示了每个库的实例和关键方法,适合初学者学习。
摘要由CSDN通过智能技术生成

一、XPath

全称:XML Path Language,即XML路径语言。

1、XPath概念

XPath提供了非常简洁明了的路径选择表达式。还提供了100个内键函数,用于字符串、数值、时间的匹配以及节点、序列的处理等。

2、XPath常用规则

XPath常用规则

表达式 描述
nodename 选取此节点的所有子节点
/ 从当前节点选取直接子节点
// 从当前节点选择子孙节点
. 选取当前节点
选取当前节点的父节点
@ 选取属性

举例:

//title[@lang='eng']

选择所有名称为title,同时属性lang的值为eng的节点。

3、准备工作

下载lxml库

pip install lxml

4、实例引入

from lxml import etree

text = '''
<div>
<ul>
<li class='item-0'><a href="link1.html">first item</a></li>
<li class='item-1'><a href="link2.html">second item</a></li>
<li class='item-inactive'><a href="link3.html">third item</a></li>
<li class='item-1'><a href="link4.html">fourth item</a></li>
<li class='item-0'><a href="link5.html">fifth item</a>
</ul>
</div>
'''

# 使用HTML类初始化,构建一个XPath解析对象
html = etree.HTML(text)
# 输出修正后的html代码
result = etree.tostring(html)
print(result.decode('utf-8'))

首先导入lxml库的etree模块,然后声明一个HTML文本,调用etree的HTML类进行初始化,这里就成功构建了一个XPath解析对象。

注意:声明的文本中最后一个li节点是没有闭合的,但是etree模块自动修正了HTML文本。

调用tostring()方法,即可输出修正后的HTML,但是结果是bytes类型。这里利用decode()方法将其转换为str类型。

# 结果
<html><body><div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</li></ul>
</div>
</body></html>

看到结果发现,li节点标签被补全了,而且还自动添加了body、html节点。

另外,还可直接读取文本文件进行解析:

from lxml import etree


html = etree.parse('./test.html', etree.HTMLParser())
# 输出修正后的html代码
result = etree.tostring(html)
print(result.decode('utf-8'))

test.html文件中的代码就是上一个案例声明的代码。

这次输出的结果略有不同,多了一个DOCTYPE的声明,不过对解析无影响。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><div>&#13;
<ul>&#13;
<li class="item-0"><a href="link1.html">first item</a></li>&#13;
<li class="item-1"><a href="link2.html">second item</a></li>&#13;
<li class="item-inactive"><a href="link3.html">third item</a></li>&#13;
<li class="item-1"><a href="link4.html">fourth item</a></li>&#13;
<li class="item-0"><a href="link5.html">fifth item</a></li>&#13;
</ul>&#13;
</div></body></html>

5、所有节点(*)

我们一般会用//开头的XPath规则来选取所有符合要求的节点。

这里以前面的HTML文本为例,如要要选取出所有节点,可以这样实现:

from lxml import etree


html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//*')
print(result)

运行结果如下:

[<Element html at 0x234ab053648>, <Element body at 0x234ab053748>, <Element div at 0x234ab053788>, <Element ul at 0x234ab0537c8>, <Element li at 0x234ab053808>, <Element a at 0x234ab053888>, <Element li at 0x234ab0538c8>, <Element a at 0x234ab053908>, <Element li at 0x234ab053948>, <Element a at 0x234ab053848>, <Element li at 0x234ab053988>, <Element a at 0x234ab0539c8>, <Element li at 0x234ab053a08>, <Element a at 0x234ab053a48>]

这里使用*来匹配所有节点,也就是整个HTML文本中的所有节点都会被获取。可以看到,返回形式是一个列表,每个元素是Element类型,其后跟了节点的名称,如html、body、div、ul、li、a等。

匹配也可以指定节点名称。如果想要获取所有li节点:

from lxml import etree


html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li')
print(result)

这里选取所有li节点,可以使用//加上节点名即可。

[<Element li at 0x2e3ff7d0748>, <Element li at 0x2e3ff7d0788>, <Element li at 0x2e3ff7d07c8>, <Element li at 0x2e3ff7d0808>, <Element li at 0x2e3ff7d0848>]

提取结果是一个列表形式。其中每个元素都是一个Element对象。如果想要取出其中一个对象,可以直接用中括号加索引,例[0]

6、子节点

可以通过/或//查找子节点或子孙节点。

/ 是查找子节点

// 是查找子孙节点

选择 li 节点中的所有直接 a 子节点:

from lxml import etree


html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li/a')
print(result)

要获取 ul 节点下的所有子孙 a 节点:

from lxml import etree


html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//ul//a')
print(result)

如果这里用了//ul/a,就无法获取任何结果了。因为/用于获取直接子节点,而ul节点下没有a节点。

7、父节点

(1)、通过 …

通过 … 来查找父节点。

首先选中href属性为link4.html的a节点,然后在获取其父节点,然后其class属性:

from lxml import etree


html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//a[@href="link4.html"]/../@class')
print(result)

'''
结果:
['item-1']
'''

(2)、通过 parent::

通过parent::来获取父节点:

from lxml import etree


html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//a[@href="link4.html"]/parent::*/@class')
print(result)

'''
结果:
['item-1']
'''

8、属性匹配(@)

使用@符号进行属性过滤

选取class为item-0的 li 节点:

from lxml import etree


html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li[@class="item-0"]')
print(result)

'''
# 结果:
[<Element li at 0x165cc6b0748>, <Element li at 0x165cc6b0788>]
'''

我们通过加入[@class=“item-0”],限制了节点的class属性为item-0。

9、文本获取 (text())

用XPath中的text()方法获取节点中的文本

获取前面li节点中的文本:

from lxml import etree


html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li[@class="item-0"]/text()')
print(result)

'''
结果:
['\r\n']
'''

没有获取到任何文本,只是获取到了回车符和换行符,这是为什么?

因为XPath中text()前面是/,而此处/的含义是选取直接子节点,很明显li的直接子节点都是a节点,文本都是在a节点内部的,所以这里匹配的结果就是被修正的li节点内部的回车符和换行符,因为自动修正的li节点的尾标签换行了。

因此,如想获取li节点内部文本,就有两种方式:一是先选取a节点在获取文本,二是使用//

第一种:先选取a节点在获取文本

from lxml import etree


html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li[@class="item-0"]/a/text()')
print(result)

'''
结果:
['first item', 'fifth item']
'''

第二种:使用//

from lxml import etree


html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li[@class="item-0"]//text()')
print(result)

'''
结果:
['first item', 'fifth item', '\r\n']
'''

根据结果发现,返回的是3个结果。这里是选取子孙节点的文本,其中前两个是li的子节点中a节点内部的文本,最后一个是li节点内部的文本。

10、属性获取 (@)

用@就可以获取属性的值

获取所有li节点下a节点的href值:


                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值