快速上手: 三分钟搞定 Python XPath 语法简介 XPath(XML Path Language)是一种用于在
简介
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