三分钟搞定 Python XPath 语法

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: XPath(XML Path Language)是一种用于在 XML 文档中查找信息的语言。它基于树状结构的 XML 文档,可以通过路径表达式来选取节点或节点集。也常常用来解析 HTML。如果你是一个前端,对用路径获取元素可能陌生又熟悉。陌生是很多的路径,熟悉的路径上又有熟悉的属性和方法。下面我们就来探究一下 XPath 的魅力。

简介

XPath(XML Path Language)是一种用于在 XML 文档中查找信息的语言。它基于树状结构的 XML 文档,可以通过路径表达式来选取节点或节点集。也常常用来解析 HTML。


如果你是一个前端,对用路径获取元素可能陌生又熟悉。陌生是很多的路径,熟悉的路径上又有熟悉的属性和方法。下面我们就来探究一下 XPath 的魅力。

Python XPath 解析器

首先我们先了解一下工具,Python 是最简单的语言之一了,使用 Python 了解 XPath 尤其重要。

  • lxml
  • BeautifulSoup
  • scrapy
  • html5lib
  • python 标准库的:xml.etree.ElementTree

以 lxml 为例,首先安装 lxml 包:

pip install lxml

节点选择器

  • "/": 从根节点选取。
  • "//": 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
  • ".": 选取当前节点。
  • "..": 选取当前节点的父节点。
  • "@": 选取属性。


以下是一个示例:

from lxml import html

# 创建一个 HTML 示例
html_string = '''
<html>
    <body>
        <div id="main">
            <p class="text">Hello, world!</p>
            <p class="text">Welcome to lxml.</p>
            <a href="http://example.com">Example</a>
        </div>
    </body>
</html>
'''

# 解析 HTML 字符串
tree = html.fromstring(html_string)

# 从根节点选取
root = tree.xpath('/html')[0]
print("Root node:", root.tag)  # 输出: Root node: html

# 从文档中的所有 p 节点中选择
paragraphs = tree.xpath('//p')
print("All paragraph texts:", [p.text for p in paragraphs])  # 输出: ['Hello, world!', 'Welcome to lxml.']

# 选取当前节点的父节点
p = tree.xpath('//p')[0]
parent = p.xpath('..')[0]
print("Parent of first paragraph:", parent.tag)  # 输出: div

# 选取当前节点
print("Current paragraph node:", p.tag)  # 输出: p

# 选取属性值
link = tree.xpath('//a')[0]
href = link.xpath('@href')[0]
print("Href attribute of the link:", href)  # 输出: http://example.com

通配符

  • "*": 匹配任何元素节点。
  • "@*": 匹配任何属性节点。


示例:

from lxml import html

# 创建一个 HTML 示例
html_string = '''
<html>
    <body>
        <div id="main">
            <p class="text">Hello, world!</p>
            <p class="text">Welcome to lxml.</p>
            <a href="http://example.com" title="Example">Example</a>
        </div>
    </body>
</html>
'''

# 解析 HTML 字符串
tree = html.fromstring(html_string)

# 匹配任何元素节点
elements = tree.xpath('//*')
print("All element tags:", [el.tag for el in elements])
# 输出: ['html', 'body', 'div', 'p', 'p', 'a']

# 匹配任何属性节点
attributes = tree.xpath('//@*')
print("All attribute values:", [attr for attr in attributes])
# 输出: ['main', 'text', 'text', 'http://example.com', 'Example']

谓词 (Predicates)

  • "[ ]" : 谓词用于查找特定的节点或包含特定值的节点。
  • "[position()]": 用于选取节点的位置。
  • "[@attribute='value']": 用于选取具有特定属性值的节点。
from lxml import html

# 创建一个 HTML 示例
html_string = '''
<html>
    <body>
        <div id="main">
            <p class="text">Hello, world!</p>
            <p class="text">Welcome to lxml.</p>
            <a href="http://example.com" title="Example">Example</a>
        </div>
    </body>
</html>
'''

# 解析 HTML 字符串
tree = html.fromstring(html_string)

# 使用谓词查找特定的节点
# 查找所有 p 元素中,文本包含 'Welcome' 的节点
specific_paragraphs = tree.xpath('//p[contains(text(), "Welcome")]')
print("Paragraphs containing 'Welcome':", [p.text for p in specific_paragraphs])
# 输出: ['Welcome to lxml.']

# 使用 position() 选择节点的位置
# 选择第二个 p 元素
second_paragraph = tree.xpath('//p[position()=2]')[0]
print("Second paragraph text:", second_paragraph.text)
# 输出: Welcome to lxml.

# 使用特定属性值选择节点
# 选择具有 title="Example" 的 a 元素
specific_link = tree.xpath('//a[@title="Example"]')[0]
print("Link with title 'Example':", specific_link.text)
# 输出: Example

函数

  • "text()": 选取文本内容。
  • "contains()": 检查某个节点的文本或属性值是否包含特定的子串。
  • "starts-with()": 检查某个节点的文本或属性值是否以特定的子串开头。
  • "count()": 计算选定的节点数。
from lxml import html

# 创建一个 HTML 示例
html_string = '''
<html>
    <body>
        <div id="main">
            <p class="text">Hello, world!</p>
            <p class="text">Welcome to lxml.</p>
            <a href="http://example.com" title="Example">Example</a>
            <a href="http://example.org" title="Example">Another Example</a>
        </div>
    </body>
</html>
'''

# 解析 HTML 字符串
tree = html.fromstring(html_string)

# 使用 text() 选取文本内容
paragraph_texts = tree.xpath('//p/text()')
print("Paragraph texts:", paragraph_texts)
# 输出: ['Hello, world!', 'Welcome to lxml.']

# 使用 contains() 检查文本是否包含特定子串
contains_text = tree.xpath('//p[contains(text(), "lxml")]')
print("Paragraphs containing 'lxml':", [p.text for p in contains_text])
# 输出: ['Welcome to lxml.']

# 使用 starts-with() 检查文本是否以特定子串开头
starts_with_text = tree.xpath('//p[starts-with(text(), "Hello")]')
print("Paragraphs starting with 'Hello':", [p.text for p in starts_with_text])
# 输出: ['Hello, world!']

# 使用 count() 计算选定的节点数
num_links = tree.xpath('count(//a)')
print("Number of links:", int(num_links))
# 输出: 2

运算符

  • "|": 选择若干路径。
  • "+、-、*、div":算术运算符。

多路径选择

from lxml import html

# 创建一个 HTML 示例
html_string = '''
<html>
    <body>
        <div class="content">
            <p>First paragraph.</p>
            <p>Second paragraph.</p>
            <span>Some span text.</span>
            <a href="http://example.com">Example link</a>
        </div>
    </body>
</html>
'''

# 解析 HTML 字符串
tree = html.fromstring(html_string)

# 使用 "|" 选择多个路径
elements = tree.xpath('//p | //span')
print("Selected elements:", [el.tag for el in elements])
# 输出: ['p', 'p', 'span']

# 获取这些元素的文本
texts = [el.text for el in elements]
print("Texts of selected elements:", texts)
# 输出: ['First paragraph.', 'Second paragraph.', 'Some span text.']

xpath 节点运算

from lxml import etree

# 创建一个 XML 示例
xml_string = '''
<root>
    <numbers>
        <num1>10</num1>
        <num2>20</num2>
        <num3>30</num3>
    </numbers>
</root>
'''

# 解析 XML 字符串
tree = etree.XML(xml_string)

# 选择数字节点并进行算术运算
sum_result = tree.xpath('(/root/numbers/num1 + /root/numbers/num2)[1]')
difference_result = tree.xpath('(/root/numbers/num2 - /root/numbers/num1)[1]')
product_result = tree.xpath('(/root/numbers/num1 * /root/numbers/num3)[1]')
division_result = tree.xpath('(/root/numbers/num3 div /root/numbers/num1)[1]')

print("Sum of num1 and num2:", sum_result)         # 输出: 30
print("Difference between num2 and num1:", difference_result)  # 输出: 10
print("Product of num1 and num3:", product_result)  # 输出: 300
print("Division of num3 by num1:", division_result)  # 输出: 3

Scrapy 中的 xpath

Scrapy 中的 xpath 在 Spider 类中的  parse 方法的 response 的中获取。下面是一些示例:

import scrapy

class ExampleSpider(scrapy.Spider):
    name = 'example'
    start_urls = ['http://example.com']

    def parse(self, response):
        # 提取标题
        title = response.xpath('//title/text()').get()
        print("Title:", title)

        # 提取所有段落文本
        paragraphs = response.xpath('//p/text()').getall()
        print("Paragraphs:", paragraphs)

        # 提取第二个段落
        second_paragraph = response.xpath('//p[2]/text()').get()
        print("Second paragraph:", second_paragraph)

        # 提取具有特定 href 的链接文本
        link_text = response.xpath('//a[@href="http://example.com"]/text()').get()
        print("Link text:", link_text)

        # 提取所有 href 属性
        links = response.xpath('//a/@href').getall()
        print("All href attributes:", links)

小结

本文主要介绍了 Python 中的 XPath 语法,以及 XPath 的解析库,这里着重介绍了 lxml 用法,同时也介绍了 scrapy 中 xpath 的各种用法。在日常编码中这些内容已经足够日常使用了。

作者:编程杂货铺

链接:https://juejin.cn/post/7402131896363302975

相关文章
|
27天前
|
人工智能 Ubuntu IDE
【Python】基础:环境配置与基础语法
本文介绍了Python编程语言及其环境配置方法。Python由Guido van Rossum于1991年创建,以其简洁、易学和强大的功能著称。文章详细讲解了Python的主要特点、Windows和Ubuntu下的安装配置步骤、基础语法、控制流、函数、文件操作、模块使用及面向对象编程等内容,帮助读者快速入门Python编程。
52 4
|
5天前
|
机器学习/深度学习 数据挖掘 开发者
Python编程入门:理解基础语法与编写第一个程序
【10月更文挑战第37天】本文旨在为初学者提供Python编程的初步了解,通过简明的语言和直观的例子,引导读者掌握Python的基础语法,并完成一个简单的程序。我们将从变量、数据类型到控制结构,逐步展开讲解,确保即使是编程新手也能轻松跟上。文章末尾附有完整代码示例,供读者参考和实践。
|
16天前
|
存储 Python Perl
python正则语法
本文介绍了正则表达式的基础知识及其在 Python 中的应用。首先解释了为什么要使用正则表达式,通过一个判断手机号的示例展示了正则表达式的简洁性。接着详细介绍了 `re` 模块的常用方法,如 `match()`、`search()`、`findall()`、`finditer()` 等,并讲解了正则表达式的基本语法,包括匹配单个字符、数字、锚字符和限定符等。最后,文章还探讨了正则表达式的高级特性,如分组、编译和贪婪与非贪婪模式。
15 2
|
22天前
|
存储 程序员 开发者
Python编程入门:从零开始掌握基础语法
【10月更文挑战第21天】本文将带你走进Python的世界,通过浅显易懂的语言和实例,让你快速了解并掌握Python的基础语法。无论你是编程新手还是想学习一门新的编程语言,这篇文章都将是你的不二之选。我们将一起探索变量、数据类型、运算符、控制结构、函数等基本概念,并通过实际代码示例加深理解。准备好了吗?让我们开始吧!
|
1月前
|
数据采集 XML 数据格式
Python爬虫--xpath
Python爬虫--xpath
|
1月前
|
存储 C语言 索引
Python 语法及入门 (超全超详细) 专为Python零基础 一篇博客让你完全掌握Python语法
本文全面介绍了Python的基础知识,包括Python的诞生背景、为什么学习Python、Python的应用场景、Python环境的安装、Python的基础语法、数据类型、控制流、函数以及数据容器的使用方法,旨在为Python零基础读者提供一篇全面掌握Python语法的博客。
39 0
Python 语法及入门 (超全超详细) 专为Python零基础 一篇博客让你完全掌握Python语法
|
1月前
|
存储 数据可视化 数据处理
【Python篇】快速理解Python语法:全面指南
【Python篇】快速理解Python语法:全面指南
45 1
|
2月前
|
Java Linux C++
30天拿下Python之基础语法
30天拿下Python之基础语法
29 4
|
2月前
|
IDE Java 开发工具
Python的语法
Python的语法。
36 5
|
2月前
|
存储 数据挖掘 程序员
揭秘Python:掌握这些基本语法和数据类型,你将拥有编程世界的钥匙!
【9月更文挑战第3天】Python 是一种简洁强大的高级编程语言,其清晰的语法和丰富的功能深受程序员喜爱。本文从基本语法入手,介绍 Python 的代码结构特点,如通过缩进区分代码块,使逻辑更清晰。接着详细讲解主要数据类型:数值型、字符串、列表、元组、集合与字典,每个类型均附有示例代码,帮助初学者快速掌握 Python,为后续学习打下坚实基础。
45 2