XML解析库 lxml 教程(三)
发布日期:2021-05-06 19:34:30 浏览次数:24 分类:技术文章

本文共 2372 字,大约阅读时间需要 7 分钟。

简介

本篇文章主要介绍利用 XPath 提取文本节点或属性节点

XPath 回顾

对于 XPath 表达式, nodename 表示元素节点, @attribute 表示属性节点, text() 表示文本节点

除了节点, XPath 还提供了表示节点之间关系的符号, // 表示所有后代节点, / 表示直接子节点, 某一个节点的属性或文本内容均属于该节点的直接子节点

XPath 提取文本节点

与 text() 不同, 功能函数 string() 表示递归提取元素的文本内容, 并将它们连接成一个文本

创建 XML 示例

from lxml import etree# 创建 Elementshtml = etree.Element("html")body = etree.SubElement(html, "body")body.text = "BODY"span = etree.SubElement(body, "span")span.text = "SPAN_1"span.tail = "SPAN_2"html_s = etree.tostring(html, pretty_print=True).decode()print(html_s)
  BODYSPAN_1SPAN_2

对比 text() 与 string()

# 使用 //text() 提取所有文本节点print(html.xpath("//text()"))# 使用 string() 提取所有文本节点print(html.xpath("string()"))

打印结果

['BODY', 'SPAN_1', 'SPAN_2']BODYSPAN_1SPAN_2

使用 html 调用 xpath 表示从 html 节点开始解析

# string() 中使用参数, 仅寻找 span 的文本节点print(html.xpath("string(//span)"))# 寻找所有 body 的文本节点print(html.xpath("//body/text()"))

打印结果

SPAN_1['BODY', 'SPAN_2']

string() 中可以使用参数限制递归查找的范围, 仅寻找 html 下所有 span 元素的文本节点

这里 span 元素末尾的文本内容 “SPAN_2” 被分给了 body 元素

如果要经常使用某一个 XPath 表达式, 可以将解析规则保存到变量

# 保存解析规则text_xpath = etree.XPath("//text()")# 解析 html 元素r = text_xpath(html)# 解析结果为列表print(r)# 查看解析后的文本类型r_0, r_1, r_2 = rprint(type(r_0))

打印结果

['BODY', 'SPAN_1', 'SPAN_2']

在 lxml 包中, XPath 解析的结果通常为列表

对于lxml.etree._ElementUnicodeResult这个类无需感到陌生, 因为它直接继承了str, 并新增了一些内容

# 直接继承字符串print("r_0 -> str:", isinstance(r_0, str))# 可获取父元素p = r_0.getparent()# 父元素标签名print(p.tag)print("r_0 is text:", r_0.is_text)print("r_2 is tail:", r_2.is_tail)

打印结果

r_0 -> str: Truebodyr_0 is text: Truer_2 is tail: True

XPath 提取属性节点

创建 HTML 示例

# 创建 Elementshtml = etree.Element("html")html.attrib["lang"] = "en"head = etree.SubElement(html, "head")meta = etree.SubElement(head, "meta")meta.set("charset", "UTF-8")etree.SubElement(head, "title").text = "Element_3"html_s = etree.tostring(html, pretty_print=True).decode()print(html_s)
      
Element_3

@*表示匹配所有属性节点, 对比一下几种提取方法

# 绝对路径-1charset_1 = html.xpath("/html/@*")# 绝对路径-2head = html[0]charset_2 = head.xpath("/html/@*")# 相对路径charset_3 = html.xpath("./@*")print(charset_1)print(charset_2)print(charset_3)

三种方法的结果是一致的

['en']['en']['en']

提取属性节点和文本节点的结果类型是一样的, 都是继承了内置字符串并新增了一些方法

# 结果类型r = charset_1[0]print(type(r))# 父元素标签名print("parent's tag:", r.getparent().tag)# 是否为属性节点print("is_attribute:", r.is_attribute)# 属性名print("attrname:", r.attrname)
parent's tag: htmlis_attribute: Trueattrname: lang
上一篇:Python 使用 __getstate__ 和 __setstate__ 魔法方法
下一篇:XML解析库 lxml 教程(二)

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2025年04月05日 19时20分29秒