爬虫 网页数据的解析提取

Xpath

常用规则

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

表达式//title[@lang='eng']表示选择所有名称为title,同时属性lang的值为eng的节点。

安装

Python 复制代码
pip3 install lxml

实例

Python 复制代码
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 = etree.HTML(text)
result = etree.tostring(html)
print(result.decode('utf-8'))

导入lxml库的etree模块并调用HTML类对一段HTML文本进行初始化,这样就构造了一个Xpath解析对象。注意HTML文本中的最后一个li节点是没有闭合的,但是etree模块自动修正了HTML文本,并且自动添加了body、html节点。调用tostring方法输出修正后的bytes类型的HTML代码。

也可以直接解析html文件:

Python 复制代码
from lxml import etreeh

html = etree.parse('./temp.html', etree.HTMLParser())
result = etree.tostring(html)
print(result.decode('utf-8'))

其中temp.html就是上个例子中的HTML文本。这次的结果多了一个DOCPYTE声明。

所有节点

一般用//开头的Xpath规则,来选取所有符合规则的节点:

Python 复制代码
from lxml import etree

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

*表示匹配所有节点,运行结果就是整个HTML文本的所有节点,形式是一个element的列表。

Python 复制代码
from lxml import etree

html = etree.parse('./temp.html', etree.HTMLParser())
result = html.xpath('//li')
print(result)
print(result[0])

表达式//li就能获取全部的li节点。

子节点

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

Python 复制代码
from lxml import etree

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

表达式//li/a用于获取所有li节点的所有直接子节点a。

Python 复制代码
from lxml import etree

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

/用于获取直接子节点,要获取节点所有符合要求的子孙节点,可以使用//:

Python 复制代码
from lxml import etree

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

//ul//a是获取所有ul节点的所有子孙节点a。

Python 复制代码
from lxml import etree

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

因为ul节点的子节点中没有a节点,所以返回结果为空。注意/和//的区别。

父节点

..可以用来查找父节点。

Python 复制代码
from lxml import etree

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

//a[@href="link4.html"]/../@class表示href属性为link4.html的a节点的父节点,再获取该节点的class属性。

也可以用parent::获取父节点:

Python 复制代码
from lxml import etree

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

属性匹配

@符合可以用于属性过滤

Python 复制代码
from lxml import etree

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

@class="item-0"\]限制了节点li的class属性为item-0。 ## 文本获取 Xpath的text方法可以获取节点中的文本。 ```Python from lxml import etree html = etree.parse('./temp.html', etree.HTMLParser()) result = html.xpath('//li[@class="item-0"]/text()') print(result) ``` ![image.png](https://file.jishuzhan.net/article/1783043331605925890/5a0fb68af9143a4244525bda56a12497.webp) 没有获取任何文本,只得到了一个换行符。原因是text方法前面的是/,而/选取的是直接子节点。li节点的直接子节点都是a节点,文本实际上是a节点内部的。这里返回的是自动修正的li节点内部的换行符。 想获取li节点内部的文本有两个方法。第一是先选取li节点内部的a节点,再提取a节点内部的文本。 ```Python from lxml import etree html = etree.parse('./temp.html', etree.HTMLParser()) result = html.xpath('//li[@class="item-0"]/a/text()') print(result) ``` ![image.png](https://file.jishuzhan.net/article/1783043331605925890/0998e961624da70409c249496c983368.webp) 这种情况下我们是逐层选取的。 另一种方法是使用//选取所有子孙节点的文本。 ```Python from lxml import etree html = etree.parse('./temp.html', etree.HTMLParser()) result = html.xpath('//li[@class="item-0"]//text()') print(result) ``` ![image.png](https://file.jishuzhan.net/article/1783043331605925890/fd158c6d6efe68796ce1ca844b6b03b3.webp) 这样就获取了所有子孙节点的文本。但是这样的结果可能会掺杂一些特殊字符。 ## 属性获取 @也可以用来获取节点的属性。 ```Python from lxml import etree html = etree.parse('./temp.html', etree.HTMLParser()) result = html.xpath('//li/a/@href') print(result) ``` ![image.png](https://file.jishuzhan.net/article/1783043331605925890/6123a4625632844fece0a71b65c837ec.webp) 这样可以获取所有li节点的所有子节点a的href属性。

相关推荐
鹏程十八少15 分钟前
Android TransactionTooLargeException 的真相与修复:从 1.13MB Bundle 到 Binder 内核的完整剖析
前端·后端·面试
geovindu19 分钟前
go: Monitor Pattern
开发语言·后端·设计模式·golang·监控模式
ZHOUPUYU36 分钟前
PHP 开发实战:从零搭建一个高性能的 RESTful API 服务
运维·开发语言·后端·html·php
身如柳絮随风扬38 分钟前
除了 JWT,你还用过哪些认证方案?Spring Security 中如何集成 JWT?
java·后端·spring
techdashen43 分钟前
Rust 能帮你捕获什么,又不能捕获什么
开发语言·后端·rust
YOU OU43 分钟前
Spring MVC 练习项目
java·后端·spring
Spider Cat 蜘蛛猫10 小时前
Springboot SSO系统设计文档
java·spring boot·后端
zyk_computer12 小时前
AI 时代,或许 Rust 比 Python 更合适
人工智能·后端·python·ai·rust·ai编程·vibe coding
雨辰AI12 小时前
SpringBoot3 项目国产化改造完整流程|从 MySQL 到人大金仓落地
java·数据库·后端·mysql·政务
GreenTea13 小时前
【Rust 2026教程:从零构建 Mini-OLAP 引擎】第 6 章 Benchmark 与优化路线图
后端