三分钟搞定 Python XPath 语法

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 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

相关文章
|
11天前
|
存储 数据挖掘 程序员
揭秘Python:掌握这些基本语法和数据类型,你将拥有编程世界的钥匙!
【9月更文挑战第3天】Python 是一种简洁强大的高级编程语言,其清晰的语法和丰富的功能深受程序员喜爱。本文从基本语法入手,介绍 Python 的代码结构特点,如通过缩进区分代码块,使逻辑更清晰。接着详细讲解主要数据类型:数值型、字符串、列表、元组、集合与字典,每个类型均附有示例代码,帮助初学者快速掌握 Python,为后续学习打下坚实基础。
26 2
|
23天前
|
IDE Java 测试技术
Python接口自动化测试框架(基础篇)-- 基础语法(真的很基础)
这篇文章是关于Python编程语言的基础语法介绍,包括编码、标识符、注释、行和缩进、输入输出以及导包等基础知识点,旨在帮助初学者理解并掌握Python编程的基础。
16 2
|
23天前
|
测试技术 索引 Python
Python接口自动化测试框架:回顾Python3基础语法知识总览
本文是Python 3基础语法知识的全面总结,涵盖了标识符、数据类型、运算符、控制流程、函数、模块和文件操作、异常处理以及面向对象编程的各个方面,旨在为编写Python接口自动化测试框架提供必要的语法知识支持。
19 1
|
1月前
|
存储 数据挖掘 程序员
揭秘Python:掌握这些基本语法和数据类型,你将拥有编程世界的钥匙!
【8月更文挑战第8天】Python是一种高级、解释型语言,以简洁的语法和强大的功能广受好评。本文从基本语法入手,强调Python独特的缩进规则,展示清晰的代码结构。接着介绍了Python的主要数据类型,包括数值、字符串、列表、元组、集合和字典,并提供了示例代码。通过这些基础知识的学习,你将为深入探索Python及其在文本处理、数据分析等领域的应用打下坚实的基础。
33 3
|
2月前
|
存储 Python
Python 基础语法变量
【7月更文挑战第27天】
35 9
|
2月前
|
开发者 Python
Python 基础语法注释
【7月更文挑战第27天】
30 6
|
2月前
|
Python
Python基础语法:运算符详解(算术运算符、比较运算符、逻辑运算符、赋值运算符)
运算符是Python编程中的重要组成部分,理解并熟练使用这些运算符有助于编写高效、简洁的代码。本文详细介绍了算术运算符、比较运算符、逻辑运算符和赋值运算符的使用方法,并通过综合示例展示了它们在实际编程中的应用。希望通过本文的介绍,您能更好地掌握Python中的运算符。
|
30天前
|
存储 数据安全/隐私保护 索引
Python基础语法day02字符串详解和列表
Python基础语法day02字符串详解和列表
|
30天前
|
Python
Python基础语法day01基础语句
Python基础语法day01基础语句
|
3月前
|
XML 数据格式 Python
Python使用xpath对解析内容进行数据提取
在前面的文章当中,已经教大家如何去获取我们需要的数据原文内容,今天就介绍一个用于提取所需数据的方法之一xpath。在后续会讲解bs4(beautifulsoup),re正则表达式。