lxml 是一个功能强大且高效的 Python 库,用于处理 XML 和 HTML 文档。它基于 C 库 libxml2
和 libxslt
,提供了高性能的解析、查询和转换功能,广泛用于网页抓取、XML 数据处理和文档操作。lxml 的主要接口包括 lxml.etree
(XML 处理和 ElementTree API)、lxml.html
(HTML 解析和清理)以及其他辅助模块。以下是对 lxml 主要接口的详细说明,包括核心类、方法、属性和常见用法,辅以简要示例,旨在帮助开发者快速理解和使用 lxml。
一、lxml 的主要模块
lxml.etree
:
- 核心模块,用于解析、操作 XML 和 HTML 文档。
- 提供 ElementTree API,支持树状结构操作和 XPath 查询。
- 适合处理严格的 XML 和简单的 HTML。
lxml.html
:
- 专门用于解析和处理 HTML 文档,优化了不规范 HTML 的处理。
- 提供 HTML 清理、表单处理和 CSS 选择器支持。
- 其他模块:
lxml.cssselect
:支持 CSS 选择器,转换为 XPath 查询。lxml.objectify
:将 XML 转换为 Python 对象,简化数据访问。lxml.sax
:支持 SAX 风格的 XML 解析。lxml.builder
:用于快速构建 XML 树。
二、lxml.etree 接口详解
lxml.etree
是 lxml 的核心模块,提供 XML 和 HTML 解析、XPath 查询和 DOM 操作功能。以下是主要类和方法的说明。
1. 核心类
etree.Element
:- 表示 XML/HTML 文档中的一个节点(标签)。
- 属性:
tag
:节点标签名(字符串,如'book'
)。text
:节点的文本内容(字符串,如'Apple'
)。tail
:节点后的尾随文本(标签闭合后的文本)。attrib
:字典,包含节点的属性(如{'class': 'company'}
)。
- 方法:
get(key, default=None)
:获取属性值,如element.get('href')
。set(key, value)
:设置属性值,如element.set('class', 'new')
。append(child)
:添加子节点。find(path)
:查找第一个匹配的子节点(支持简单路径或 XPath)。findall(path)
:查找所有匹配的子节点。xpath(expression)
:执行 XPath 查询,返回节点或值列表。iter(tag=None)
:迭代所有子节点(或指定标签)。remove(child)
:移除子节点。
etree.ElementTree
:- 表示整个 XML/HTML 文档树。
- 属性:
docinfo
:文档信息(如 XML 声明、编码)。getroot()
:获取文档根节点(Element
对象)。
- 方法:
xpath(expression)
:对整个文档执行 XPath 查询。write(file, encoding='utf-8', pretty_print=True)
:将文档写入文件。
etree.XMLParser
:- 解析器配置,用于控制解析行为。
- 参数:
remove_blank_text
:移除空白文本节点(适合 XSLT)。recover
:尝试恢复不规范的 XML/HTML。encoding
:指定输入编码。
2. 解析函数
etree.fromstring(text, parser=None)
:- 从字符串解析 XML/HTML,返回
Element
对象(文档根节点)。 - 示例:
from lxml import etree xml = '<root><child>Test</child></root>' element = etree.fromstring(xml) print(element.tag) # 输出: root
etree.parse(source, parser=None)
:- 从文件或文件对象解析 XML/HTML,返回
ElementTree
对象。 - 示例:
tree = etree.parse('input.xml') root = tree.getroot()
etree.tostring(element, encoding='utf-8', pretty_print=False)
:- 将节点或树序列化为字符串。
- 参数:
encoding
:输出编码(如'utf-8'
或'unicode'
)。pretty_print
:格式化输出(添加换行和缩进)。
- 示例:
python print(etree.tostring(root, pretty_print=True).decode())
3. XPath 支持
element.xpath(expression, namespaces=None)
:- 执行 XPath 查询,返回节点、属性或文本列表。
- 参数:
expression
:XPath 表达式(如'//book/title/text()'
)。namespaces
:命名空间映射字典。
- 示例:
titles = root.xpath('//book/title/text()') print(titles) # 输出: ['Everyday Italian', 'Harry Potter', ...]
- 常见 XPath 表达式:
//tag
:查找所有指定标签。@attr
:提取属性值(如//book/@category
)。text()
:提取文本内容。[condition]
:条件过滤(如//book[@category="web"]
)。./
:相对路径(如./title/text()
)。
4. XSLT 支持
etree.XSLT(xslt_element)
:- 创建 XSLT 转换器,用于将 XML 转换为其他格式。
- 示例:
python xslt = etree.fromstring('<xsl:stylesheet version="1.0" ...>...</xsl:stylesheet>') transform = etree.XSLT(xslt) result = transform(root)
5. 其他功能
- 命名空间处理:
- 使用
namespaces
参数处理 XML 命名空间:namespaces = {'ns': 'http://example.com'} nodes = root.xpath('//ns:tag', namespaces=namespaces)
- 迭代解析:
- 使用
etree.iterparse()
逐块解析大型 XML 文件,节省内存:python for event, elem in etree.iterparse('large.xml', tag='book'): print(elem.xpath('./title/text()')[0]) elem.clear() # 释放内存
三、lxml.html 接口详解
lxml.html
是专门为 HTML 解析和处理设计的模块,优化了不规范 HTML 的处理,适合网页抓取。
1. 核心类和函数
lxml.html.fromstring(html)
:- 从字符串解析 HTML,返回
Element
对象。 - 自动处理不规范 HTML(如缺失闭合标签)。
- 示例:
from lxml import html doc = html.fromstring('<div>Hello</div>') print(doc.text) # 输出: Hello
lxml.html.parse(source)
:- 从文件或 URL 解析 HTML,返回
ElementTree
对象。 lxml.html.clean_html(element)
:- 清理 HTML,移除脚本、样式等不安全内容。
- 示例:
dirty_html = '<div><script>alert("x")</script>Hello</div>' cleaned = html.clean_html(html.fromstring(dirty_html)) print(html.tostring(cleaned).decode()) # 输出: <div>Hello</div>
lxml.html.HtmlElement
:- 继承
etree.Element
,添加 HTML 特定方法:cssselect(expr)
:使用 CSS 选择器查询(如div.company
)。forms
:获取 HTML 表单。drop_tag()
:移除标签但保留内容。
2. CSS 选择器
- 使用
cssselect
模块将 CSS 选择器转换为 XPath:
from lxml.html import fromstring
doc = fromstring('<div class="company">Apple</div>')
elements = doc.cssselect('div.company')
print(elements[0].text) # 输出: Apple
3. 表单处理
- 解析和操作 HTML 表单:
form = doc.xpath('//form')[0]
print(form.form_values()) # 获取表单字段和值
四、结合示例解析接口
以下使用提供的 XML 内容展示 lxml.etree
和 lxml.html
的主要接口:
from lxml import etree
content = """<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="web">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
"""
# 解析 XML
tree = etree.fromstring(content.strip())
root = tree # 根节点 <bookstore>
# 1. 使用 Element 属性和方法
print("=== 遍历子节点 ===")
for book in root: # 迭代 <book> 子节点
print(f"Tag: {book.tag}, Category: {book.get('category')}")
# 2. 使用 XPath 查询
print("\n=== XPath 查询标题 ===")
titles = root.xpath('//book/title/text()')
print(titles) # 输出: ['Everyday Italian', 'Learning XML']
# 3. 修改 XML
print("\n=== 修改价格 ===")
for book in root.xpath('//book'):
price = float(book.xpath('./price/text()')[0])
book.xpath('./price')[0].text = str(price * 1.1) # 增加 10%
print(etree.tostring(root, pretty_print=True).decode())
# 4. 使用 lxml.html(假设 XML 作为 HTML 处理)
from lxml import html
doc = html.fromstring(content.strip())
print("\n=== 使用 CSS 选择器 ===")
titles = doc.cssselect('book > title')
for title in titles:
print(title.text)
输出:
=== 遍历子节点 ===
Tag: book, Category: cooking
Tag: book, Category: web
=== XPath 查询标题 ===
['Everyday Italian', 'Learning XML']
=== 修改价格 ===
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>33.0</price>
</book>
<book category="web">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>43.945</price>
</book>
</bookstore>
=== 使用 CSS 选择器 ===
Everyday Italian
Learning XML
五、注意事项
- 安装依赖:
- 确保安装
libxml2
和libxslt
(Linux:sudo apt-get install libxml2-dev libxslt1-dev
)。 - 安装 lxml:
pip install lxml
.
- 错误处理:
- 处理 XML 解析错误:
python try: tree = etree.fromstring(content) except etree.XMLSyntaxError as e: print(f"Parse error: {e}")
- XPath 学习:
- 熟悉 XPath 语法(如
//
,@
,text()
)是关键。 - 使用工具(如 Chrome 开发者工具)生成 XPath。
- 性能优化:
- 使用
lxml.etree
比lxml.html
更快,适合严格 XML。 - 对于大型文件,使用
iterparse()
节省内存。
- 合法性:
- 抓取网页时遵守服务条款和
robots.txt
。
六、文档和资源
- 官方文档:https://lxml.de/
- API 参考:https://lxml.de/api/index.html
- PyPI:https://pypi.org/project/lxml/
- GitHub:https://github.com/lxml/lxml
- XPath 教程:https://www.w3schools.com/xml/xpath_intro.asp
七、总结
lxml 提供强大的 lxml.etree
和 lxml.html
接口,适合处理 XML 和 HTML 文档。etree
提供 ElementTree 和 XPath 操作,适合精确查询和修改;lxml.html
优化了 HTML 解析和清理,适合网页抓取。相比 Beautiful Soup,lxml 更快但 API 更底层;相比 Bluemoss,lxml 更灵活但需要手动组织数据。如果您需要特定接口的深入示例(如 XSLT、表单处理)或处理特定 XML/HTML,请告诉我!