Python 网络数据处理与编码
1. quopri 模块
1.1 MIME 类型识别
在处理 MIME 类型时,如果处于默认设置,只有在 IANA 注册的官方 MIME 类型才会被识别,可参考 IANA 媒体类型分配 。若不处于默认设置,一些常见但非官方的 MIME 类型也会被识别。以下是相关函数:
- guess_extension(type [, strict]) :根据文件的 MIME 类型猜测标准文件扩展名,返回包含前导点(.)的文件名扩展名的字符串。对于未知类型返回 None。若 strict 为 True(默认值),则只识别官方 MIME 类型。
- guess_all_extensions(type [, strict]) :与 guess_extension() 类似,但返回所有可能的文件名扩展名列表。
- init([files]) :初始化模块。 files 是一个文件名序列,用于读取以提取类型信息。这些文件包含将 MIME 类型映射到可接受的文件后缀列表的行,例如:
image/jpeg: jpe jpeg jpg
text/html: htm html
-
read_mime_types(filename):从给定的文件名加载类型映射,返回将文件名扩展名映射到 MIME 类型字符串的字典。若文件名不存在或无法读取,则返回 None。 -
add_type(type, ext [, strict]):向映射中添加新的 MIME 类型。type是 MIME 类型,如 ‘text/plain’;ext是文件名扩展名,如 ‘.txt’;strict是一个布尔值,指示该类型是否为官方注册的 MIME 类型,默认值为 True。
1.2 引用可打印编码与解码
quopri 模块用于对字节字符串进行引用可打印传输编码和解码。这种格式主要用于编码 8 位文本文件,这些文件大多可以作为 ASCII 读取,但可能包含少量不可打印或特殊字符(例如,控制字符或范围在 128 - 255 的非 ASCII 字符)。引用可打印编码的规则如下:
- 任何可打印的非空白 ASCII 字符(除了 ‘=’)按原样表示。
- ‘=’ 字符用作转义字符。后跟两个十六进制数字时,它表示具有该值的字符(例如,’=0C’)。等号由 ‘=3D’ 表示。如果 ‘=’ 出现在行尾,则表示软换行。只有当输入文本的长行必须拆分为多个输出行时才会出现这种情况。
- 空格和制表符按原样保留,但不能出现在行尾。
例如,若文档包含文本 “Copyright © 2009”,Python 字节字符串表示为 b'Copyright \xa9 2009' ,其引用可打印版本为 b'Copyright =A9 2009' ,其中特殊字符 '\xa9' 被转义序列 ‘=A9’ 替换。
以下是相关的编码和解码函数:
- decode(input, output [, header]) :将字节解码为引用可打印格式。 input 和 output 是二进制模式打开的文件对象。若 header 为 True,则下划线(_)将被解释为空格,否则保持不变,这用于解码已编码的 MIME 头,默认 header 为 False。
- decodestring(s [, header]) :解码字符串 s 。 s 可以是 Unicode 或字节字符串,但结果始终是字节字符串。 header 的含义与 decode() 相同。
- encode(input, output, quotetabs [, header]) :将字节编码为引用可打印格式。 input 和 output 是二进制模式打开的文件对象。若 quotetabs 为 True,则除了正常的引用规则外,还会强制对制表符进行引用,否则制表符按原样保留,默认 quotetabs 为 False。 header 的含义与 decode() 相同。
- encodestring(s [, quotetabs [, header]]) :编码字节字符串 s ,结果也是字节字符串。 quotetabs 和 header 的含义与 encode() 相同。
注意 :引用可打印数据编码早于 Unicode,仅适用于 8 位数据。尽管它最常用于文本,但实际上只适用于以单字节表示的 ASCII 和扩展 ASCII 字符。使用此模块时,请确保所有文件都处于二进制模式,并且处理的是字节字符串。
2. XML 处理
2.1 XML 概述
Python 包含多种用于处理 XML 数据的模块。XML 处理是一个广泛的主题,本文假设读者已经熟悉一些基本的 XML 概念。Python 提供了两种 XML 支持:一是对两种行业标准的 XML 解析方法(SAX 和 DOM)的基本支持;二是 ElementTree 接口,这是 Python 特有的 XML 解析方法,利用了 Python 语言特性,大多数用户认为它比 SAX 或 DOM 更简单、更快速。
2.2 XML 示例文档
以下是一个典型的 XML 文档示例,描述了一个食谱:
<?xml version="1.0" encoding="iso-8859-1"?>
<recipe>
<title>
Famous Guacamole
</title>
<description>
A southwest favorite!
</description>
<ingredients>
<item num="4"> Large avocados, chopped </item>
<item num="1"> Tomato, chopped </item>
<item num="1/2" units="C"> White onion, chopped </item>
<item num="2" units="tbl"> Fresh squeezed lemon juice </item>
<item num="1"> Jalapeno pepper, diced </item>
<item num="1" units="tbl"> Fresh cilantro, minced </item>
<item num="1" units="tbl"> Garlic, minced </item>
<item num="3" units="tsp"> Salt </item>
<item num="12" units="bottles"> Ice-cold beer </item>
</ingredients>
<directions>
Combine all ingredients and hand whisk to desired consistency.
Serve and enjoy with ice-cold beers.
</directions>
</recipe>
该文档由以标签开始和结束的元素组成,元素通常嵌套并组织成层次结构。每个文档有一个根元素,在此示例中为 <recipe> 元素。元素可以有属性,如 <item> 元素的 num 属性。
2.3 xml.dom.minidom 模块
xml.dom.minidom 模块根据 DOM 规范提供了基本的 XML 文档解析支持,并将其存储在内存中作为树结构。
2.3.1 解析函数
-
parse(file [, parser]):解析文件内容并返回表示文档树顶部的节点。file可以是文件名或已打开的文件对象。parser是可选的 SAX2 兼容解析器对象,用于构建树,若省略则使用默认解析器。 -
parseString(string [, parser]):与parse()相同,但输入数据以字符串形式提供。
2.3.2 节点属性和方法
解析函数返回的文档树由一组链接在一起的节点组成。每个节点 n 具有以下属性和方法:
| 节点属性 | 描述 |
|---|---|
n.attributes | 包含属性值的映射对象(如果有) |
n.childNodes | n 的所有子节点列表 |
n.firstChild | 节点 n 的第一个子节点 |
n.lastChild | 节点 n 的最后一个子节点 |
n.localName | 元素的本地标签名。如果标签中出现冒号(例如, <foo:bar ...> ),则只包含冒号后面的部分 |
n.namespaceURI | 与 n 关联的命名空间(如果有) |
n.nextSibling | 树中 n 之后且具有相同父节点的节点。如果 n 是最后一个兄弟节点,则为 None |
n.nodeName | 节点的名称,含义取决于节点类型 |
n.nodeType | 描述节点类型的整数,设置为 Node 类的类变量之一,如 ATTRIBUTE_NODE 、 CDATA_SECTION_NODE 等 |
n.nodeValue | 节点的值,含义取决于节点类型 |
n.parentNode | 对父节点的引用 |
n.prefix | 标签名中冒号之前的部分。例如,元素 <foo:bar ...> 的前缀为 ‘foo’ |
n.previousSibling | 树中 n 之前且具有相同父节点的节点 |
节点的方法通常用于操作树结构,例如:
- n.appendChild(child) :向 n 添加新的子节点 child ,新子节点添加到其他子节点的末尾。
- n.cloneNode(deep) :复制节点 n 。若 deep 为 True,则所有子节点也会被克隆。
- n.hasAttributes() :若节点有任何属性,则返回 True。
- n.hasChildNodes() :若节点有任何子节点,则返回 True。
- n.insertBefore(newchild, ichild) :在另一个子节点 ichild 之前插入新子节点 newchild , ichild 必须已经是 n 的子节点。
- n.isSameNode(other) :若节点 other 引用与 n 相同的 DOM 节点,则返回 True。
- n.normalize() :将相邻的文本节点合并为一个文本节点。
- n.removeChild(child) :从 n 中移除子节点 child 。
- n.replaceChild(newchild,oldchild) :用 newchild 替换子节点 oldchild , oldchild 必须已经是 n 的子节点。
2.3.3 常见节点类型
常见的节点类型有 Document、Element 和 Text 节点:
- Document 节点 :文档节点 d 出现在整个文档树的顶部,代表整个文档。它具有以下方法和属性:
- d.documentElement :包含整个文档的根元素。
- d.getElementsByTagName(tagname) :搜索所有子节点并返回具有给定标签名 tagname 的元素列表。
- d.getElementsByTagNameNS(namespaceuri, localname) :搜索所有子节点并返回具有给定命名空间 URI 和本地名称的元素列表,返回的列表是 NodeList 类型的对象。
- Element 节点 :元素节点 e 代表单个 XML 元素,如 <foo>...</foo> 。要获取元素的文本,需要查找作为子节点的 Text 节点。元素节点具有以下属性和方法:
- e.tagName :元素的标签名。例如,若元素定义为 <foo ...> ,标签名是 ‘foo’。
- e.getElementsByTagName(tagname) :返回具有给定标签名的所有子元素列表。
- e.getElementsByTagNameNS(namespaceuri, localname) :返回具有给定命名空间中给定标签名的所有子元素列表。
- e.hasAttribute(name) :若元素具有名为 name 的属性,则返回 True。
- e.hasAttributeNS(namespaceuri, localname) :若元素具有由 namespaceuri 和 localname 命名的属性,则返回 True。
- e.getAttribute(name) :返回属性 name 的值,若属性不存在则返回空字符串。
- e.getAttributeNS(namespaceuri, localname) :返回由 namespaceuri 和 localname 命名的属性的值,若属性不存在则返回空字符串。
- Text 节点 :文本节点用于表示文本数据,文本数据存储在 Text 对象 t 的 t.data 属性中。与给定文档元素关联的文本总是存储在该元素的子 Text 节点中。
2.3.4 实用函数
节点上定义了以下实用方法,这些方法不是 DOM 标准的一部分,但由 Python 提供以方便使用和调试:
- n.toprettyxml([indent [, newl]]) :创建一个格式良好的字符串,包含节点 n 及其子节点表示的 XML。 indent 指定缩进字符串,默认为制表符( \t ); newl 指定换行符,默认为 \n 。
- n.toxml([encoding]) :创建一个包含节点 n 及其子节点表示的 XML 的字符串。 encoding 指定编码(例如,’utf-8’),若未提供编码,则输出文本中不指定编码。
- n.writexml(writer [, indent [, addindent [, newl]]]) :将 XML 写入 writer 。 writer 可以是任何提供与文件接口兼容的 write() 方法的对象。 indent 指定 n 的缩进, addindent 指定应用于 n 的子节点的增量缩进, newl 指定换行符。
2.3.5 DOM 示例
以下示例展示了如何使用 xml.dom.minidom 模块解析 XML 文件并提取信息:
from xml.dom import minidom
doc = minidom.parse("recipe.xml")
ingredients = doc.getElementsByTagName("ingredients")[0]
items = ingredients.getElementsByTagName("item")
for item in items:
num = item.getAttribute("num")
units = item.getAttribute("units")
text = item.firstChild.data.strip()
quantity = "%s %s" % (num, units)
print("%-10s %s" % (quantity, text))
2.4 xml.etree.ElementTree 模块
xml.etree.ElementTree 模块定义了一个灵活的容器对象 ElementTree ,用于存储和操作层次结构数据。虽然该对象通常与 XML 处理结合使用,但实际上它是通用的,类似于列表和字典的结合。
2.4.1 ElementTree 对象
ElementTree([element [, file]]) :创建一个新的 ElementTree 对象。 element 是表示树的根节点的实例,支持后续描述的元素接口。 file 可以是文件名或文件类对象,用于读取 XML 数据以填充树。
2.4.2 ElementTree 方法
ElementTree 实例 tree 具有以下方法:
- tree._setroot(element) :将根元素设置为 element 。
- tree.find(path) :查找并返回树中第一个类型与给定路径匹配的顶级元素。 path 是一个字符串,描述元素类型及其相对于其他元素的位置。路径语法如下:
| 路径 | 描述 |
|---|---|
'tag' | 仅匹配具有给定标签的顶级元素,例如 <tag>...</tag> ,不匹配较低级别定义的元素 |
'parent/tag' | 若元素的标签为 ‘tag’ 且是标签为 ‘parent’ 的元素的子元素,则匹配该元素 |
'*' | 选择所有子元素。例如, '*/tag' 将匹配所有标签名为 ‘tag’ 的孙元素 |
'.' | 从当前节点开始搜索 |
'//' | 选择元素下所有级别的所有子元素。例如, './/tag' 匹配所有标签为 ‘tag’ 的元素 |
如果处理涉及 XML 命名空间的文档,路径中的标签字符串应具有 '{uri}tag' 的形式,其中 uri 是字符串,如 'http://www.w3.org/TR/html4/' 。
- tree.findall(path) :查找树中所有与给定路径匹配的顶级元素,并按文档顺序返回它们作为列表或迭代器。
- tree.findtext(path [, default]) :返回树中第一个与给定路径匹配的顶级元素的元素文本。若未找到匹配元素,则返回 default 字符串。
- tree.getiterator([tag]) :创建一个迭代器,按顺序生成树中所有标签与 tag 匹配的元素。若省略 tag ,则按顺序返回树中的每个元素。
- tree.getroot() :返回树的根元素。
- tree.parse(source [, parser]) :解析外部 XML 数据并将根元素替换为结果。 source 可以是文件名或表示 XML 数据的文件类对象。 parser 是可选的 TreeBuilder 实例。
- tree.write(file [, encoding]) :将树的全部内容写入文件。 file 可以是文件名或用于写入的文件类对象。 encoding 是输出编码,若未指定则默认为解释器的默认编码(大多数情况下为 ‘utf-8’ 或 ‘ascii’)。
2.4.3 创建元素
可以使用以下函数创建元素:
- Comment([text]) :创建一个新的注释元素, text 是包含元素文本的字符串或字节字符串。在解析或写入输出时,该元素映射到 XML 注释。
- Element(tag [, attrib [, **extra]]) :创建一个新元素, tag 是元素名称。 attrib 是元素属性的字典,以字符串或字节字符串指定。任何额外的关键字参数也用于设置元素属性。
- fromstring(text) :从 text 中的 XML 文本片段创建元素,与 XML() 相同。
- ProcessingInstruction(target [, text]) :创建一个对应于处理指令的新元素。 target 和 text 都是字符串或字节字符串。在映射到 XML 时,该元素对应于 '<?target text?>' 。
- SubElement(parent, tag [, attrib [, **extra]]) :与 Element() 相同,但会自动将新元素添加为 parent 元素的子元素。
- XML(text) :通过解析 text 中的 XML 代码片段创建元素。例如,若 text 设置为 <foo>....</foo> ,将创建一个标签为 ‘foo’ 的标准元素。
- XMLID(text) :与 XML(text) 相同,除了收集 ‘id’ 属性并用于构建将 ID 值映射到元素的字典。返回一个元组 (elem, idmap) ,其中 elem 是新元素, idmap 是 ID 映射字典。
2.4.4 元素接口
ElementTree 中存储的元素虽然类型可能不同,但都支持一个公共接口。如果 elem 是任何元素,则定义了以下 Python 运算符:
| 运算符 | 描述 |
|---|---|
elem[n] | 返回 elem 的第 n 个子元素 |
elem[n] = newelem | 将 elem 的第 n 个子元素更改为不同的元素 newelem |
del elem[n] | 删除 elem 的第 n 个子元素 |
len(elem) | elem 的子元素数量 |
所有元素具有以下基本数据属性:
| 属性 | 描述 |
|---|---|
elem.tag | 标识元素类型的字符串,例如 <foo>...</foo> 的标签为 ‘foo’ |
elem.text | 与元素关联的数据,通常是包含 XML 元素开始和结束标签之间文本的字符串 |
elem.tail | 与属性一起存储的额外数据,对于 XML,通常是元素结束标签之后但下一个标签开始之前的空白字符串 |
elem.attrib | 包含元素属性的字典 |
元素支持以下方法,其中一些方法类似于字典的方法:
- elem.append(subelement) :将子元素 subelement 添加到子元素列表中。
- elem.clear() :清除元素中的所有数据,包括属性、文本和子元素。
- elem.find(path) :查找第一个类型与 path 匹配的子元素。
- elem.findall(path) :查找所有类型与 path 匹配的子元素,按文档顺序返回匹配元素的列表或可迭代对象。
- elem.findtext(path [, default]) :查找第一个类型与 path 匹配的元素的文本。若没有匹配项,则返回 default 字符串。
- elem.get(key [, default]) :获取属性 key 的值。若属性不存在,则返回 default 默认值。如果涉及 XML 命名空间,则 key 应为 '{uri}key}' 的形式。
- elem.getchildren() :按文档顺序返回所有子元素。
- elem.getiterator([tag]) :返回一个迭代器,生成所有类型与 tag 匹配的子元素。
- elem.insert(index, subelement) :在子元素列表的位置 index 插入子元素。
- elem.items() :返回所有元素属性作为 (name, value) 对的列表。
- elem.keys() :返回所有属性名称的列表。
- elem.remove(subelement) :从子元素列表中移除元素 subelement 。
- elem.set(key, value) :将属性 key 设置为值 value 。
2.4.5 树构建
TreeBuilder([element_factory]) :用于通过一系列 start() 、 end() 和 data() 调用构建 ElementTree 结构,这些调用在解析文件或遍历其他树结构时会被触发。 element_factory 是用于创建新元素实例的操作函数。
TreeBuilder 实例 t 具有以下方法:
- t.close() :关闭树构建器并返回已创建的顶级 ElementTree 对象。
- t.data(data) :将文本数据添加到当前正在处理的元素中。
- t.end(tag) :关闭当前正在处理的元素并返回最终的元素对象。
- t.start(tag, attrs) :创建一个新元素, tag 是元素名称, attrs 是包含属性值的字典。
2.4.6 实用函数
定义了以下实用函数:
- dump(elem) :将元素结构 elem 转储到 sys.stdout 进行调试,输出通常是 XML。
- iselement(elem) :检查 elem 是否为有效的元素对象。
- iterparse(source [, events]) :从 source 逐步解析 XML。 source 可以是文件名或引用 XML 数据的文件类对象。 events 是要生成的事件类型列表,可能的事件类型有 'start' 、 'end' 、 'start-ns' 和 'end-ns' 。若省略,则仅生成 'end' 事件。该函数返回一个迭代器,生成元组 (event, elem) ,其中 event 是字符串,如 'start' 或 'end' , elem 是正在处理的元素。
- parse(source) :将 XML 源完全解析为 ElementTree 对象, source 是包含 XML 数据的文件名或文件类对象。
- tostring(elem) :创建一个表示 elem 及其所有子元素的 XML 字符串。
2.4.7 XML 示例
以下是使用 ElementTree 解析示例食谱文件并打印配料列表的示例:
from xml.etree.ElementTree import ElementTree
doc = ElementTree(file="recipe.xml")
ingredients = doc.find('ingredients')
for item in ingredients.findall('item'):
num = item.get('num')
units = item.get('units', '')
text = item.text.strip()
quantity = "%s %s" % (num, units)
print("%-10s %s" % (quantity, text))
也可以使用路径语法简化操作:
from xml.etree.ElementTree import ElementTree
doc = ElementTree(file="recipe.xml")
for item in doc.findall(".//item"):
num = item.get('num')
units = item.get('units', '')
text = item.text.strip()
quantity = "%s %s" % (num, units)
print("%-10s %s" % (quantity, text))
对于使用命名空间的 XML 文件,例如 recipens.xml :
<?xml version="1.0" encoding="iso-8859-1"?>
<recipe xmlns:r="http://www.dabeaz.com/namespaces/recipe">
<r:title>
Famous Guacamole
</r:title>
<r:description>
A southwest favorite!
</r:description>
<r:ingredients>
<r:item num="4"> Large avocados, chopped </r:item>
<!-- 其他配料 -->
</r:ingredients>
<r:directions>
Combine all ingredients and hand whisk to desired consistency.
Serve and enjoy with ice-cold beers.
</r:directions>
</recipe>
可以使用字典映射命名空间前缀到关联的命名空间 URI:
from xml.etree.ElementTree import ElementTree
doc = ElementTree(file="recipens.xml")
ns = {
'r': 'http://www.dabeaz.com/namespaces/recipe'
}
ingredients = doc.find('{%(r)s}ingredients' % ns)
for item in ingredients.findall('{%(r)s}item' % ns):
num = item.get('num')
units = item.get('units', '')
text = item.text.strip()
quantity = "%s %s" % (num, units)
print("%-10s %s" % (quantity, text))
对于大型 XML 文件,使用 ElementTree.iterparse() 函数可以减少内存消耗。例如,处理包含大量专辑信息的 music.xml 文件:
from xml.etree.ElementTree import iterparse
iparse = iterparse("music.xml", ['start', 'end'])
# 找到顶级音乐元素
for event, elem in iparse:
if event == 'start' and elem.tag == 'music':
musicNode = elem
break
# 获取所有专辑
albums = (elem for event, elem in iparse if event == 'end' and elem.tag == 'album')
for album in albums:
# 进行一些处理
...
musicNode.remove(album) # 处理完后丢弃专辑
使用 iterparse() 时,关键是及时丢弃不再使用的数据,以保持低内存占用。
2.5 xml.sax 模块
xml.sax 模块使用 SAX2 API 提供 XML 文档解析支持。
2.5.1 解析函数
-
parse(file, handler [, error_handler]):解析 XML 文档file,file可以是文件名或打开的文件对象。handler是内容处理程序对象,error_handler是可选的 SAX 错误处理程序对象,更多信息可在在线文档中找到。 -
parseString(string, handler [, error_handler]):与parse()相同,但解析字符串中包含的 XML 数据。
2.5.2 处理程序对象
要进行任何处理,需要向 parse() 或 parseString() 函数提供内容处理程序对象。定义处理程序时,需要定义一个继承自 ContentHandler 的类。 ContentHandler 实例 c 具有以下方法,可根据需要在处理程序类中重写:
- c.characters(content) :解析器调用此方法提供原始字符数据, content 是包含字符的字符串。
- c.endDocument() :解析器到达文档末尾时调用。
- c.endElement(name) :到达元素 name 的末尾时调用。
- c.endElementNS(name, qname) :到达涉及 XML 命名空间的元素末尾时调用。
- c.endPrefixMapping(prefix) :到达 XML 命名空间末尾时调用。
- c.ignorableWhitespace(whitespace) :在文档中遇到可忽略的空白时调用。
- c.processingInstruction(target, data) :遇到 XML 处理指令时调用。
- c.setDocumentLocator(locator) :解析器调用此方法提供定位器对象,用于跟踪行号、列号等信息。
- c.skippedEntity(name) :解析器跳过实体时调用。
- c.startDocument() :文档开始时调用。
- c.startElement(name, attrs) :遇到新的 XML 元素时调用, attrs 对象提供了获取属性信息的方法,如 attrs.getLength() 、 attrs.getNames() 等。
- c.startElementNS(name, qname, attrs) :遇到使用 XML 命名空间的新 XML 元素时调用, attrs 对象除了具有 startElement() 中的方法外,还添加了处理命名空间的方法。
- c.startPrefixMapping(prefix, uri) :在 XML 命名空间声明开始时调用。
2.5.3 示例
以下示例展示了一个基于 SAX 的解析器,用于打印食谱文件中的配料列表:
from xml.sax import ContentHandler, parse
class RecipeHandler(ContentHandler):
def startDocument(self):
self.initem = False
def startElement(self, name, attrs):
if name == 'item':
self.num = attrs.get('num', '1')
self.units = attrs.get('units', 'none')
self.text = []
self.initem = True
def endElement(self, name):
if name == 'item':
text = "".join(self.text)
if self.units == 'none':
self.units = ""
unitstr = "%s %s" % (self.num, self.units)
print("%-10s %s" % (unitstr, text.strip()))
self.initem = False
def characters(self, data):
if self.initem:
self.text.append(data)
parse("recipe.xml", RecipeHandler())
2.6 xml.sax.saxutils 模块
xml.sax.saxutils 模块定义了一些实用函数和对象,常用于 SAX 解析器,也在其他地方普遍有用。
- escape(data [, entities]) :给定字符串 data ,此函数将某些字符替换为转义序列。 entities 是可选的字典,用于将字符映射到转义序列。
- unescape(data [, entities]) :对 data 中出现的特殊转义序列进行反转义。 entities 是可选的字典,将实体映射到未转义的字符值。
- quoteattr(data [, entities]) :对字符串 data 进行转义,并进行额外处理,使结果值可作为 XML 属性值使用。
- XMLGenerator([out [, encoding]]) :一个 ContentHandler 对象,将解析的 XML 数据作为 XML 文档回显到输出流,重新创建原始 XML 文档。 out 是输出文档,默认为 sys.stdout 。 encoding 是字符编码,默认为 ‘iso-8859-1’,可用于调试解析代码。
3. 总结与对比
3.1 各模块特点总结
| 模块名称 | 特点 | 适用场景 |
|---|---|---|
| quopri | 用于对字节字符串进行引用可打印传输编码和解码,适用于处理包含少量非打印或特殊字符的 8 位文本文件 | 处理包含特殊字符的邮件内容、网页数据等 |
| xml.dom.minidom | 根据 DOM 规范将 XML 文档存储为树结构,提供了丰富的节点属性和方法来操作树结构 | 需要对 XML 文档进行复杂操作,如修改节点、添加属性等 |
| xml.etree.ElementTree | 定义了灵活的 ElementTree 对象,使用方便,路径语法简化了元素查找操作,内存占用相对较小 | 处理简单的 XML 文档,快速提取信息 |
| xml.sax | 使用 SAX2 API 解析 XML 文档,基于事件处理,逐行解析,内存占用低 | 处理大型 XML 文档,只需要顺序读取和处理数据 |
| xml.sax.saxutils | 提供了一些实用函数和对象,如转义、反转义字符,用于辅助 SAX 解析器 | 处理 XML 数据时需要对字符进行转义或反转义操作 |
3.2 不同 XML 解析方法对比
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
A([开始]):::startend --> B{选择解析方法}:::process
B --> C[DOM]:::process
B --> D[ElementTree]:::process
B --> E[SAX]:::process
C --> C1(构建树结构):::process
C --> C2(支持复杂操作):::process
C --> C3(内存占用高):::process
D --> D1(灵活容器对象):::process
D --> D2(路径语法方便):::process
D --> D3(内存占用适中):::process
E --> E1(基于事件处理):::process
E --> E2(逐行解析):::process
E --> E3(内存占用低):::process
C1 --> C4(适用于复杂修改):::process
D2 --> D4(适用于简单提取):::process
E2 --> E4(适用于大型文件):::process
C4 --> F([结束]):::startend
D4 --> F
E4 --> F
从上述流程图可以看出,不同的 XML 解析方法有不同的特点和适用场景。DOM 方法适合对 XML 文档进行复杂的修改和操作,但内存占用高;ElementTree 方法使用方便,路径语法简化了元素查找,适用于简单的 XML 文档信息提取;SAX 方法基于事件处理,逐行解析,内存占用低,适合处理大型 XML 文件。
3.3 实际应用建议
- 小型 XML 文件 :如果 XML 文件较小,且需要对文档进行一些修改和操作,建议使用
xml.dom.minidom模块。例如,需要修改 XML 文档中的节点属性、添加或删除节点等操作时,DOM 方法可以方便地实现这些功能。 - 简单 XML 信息提取 :对于简单的 XML 文档,只需要提取其中的信息,
xml.etree.ElementTree模块是一个不错的选择。其路径语法可以快速定位到需要的元素,代码实现简单易懂。 - 大型 XML 文件 :当处理大型 XML 文件时,为了避免内存占用过高,建议使用
xml.sax模块。SAX 方法基于事件处理,逐行解析 XML 文档,只在需要时处理数据,不会将整个文档加载到内存中。
4. 注意事项
4.1 quopri 模块注意事项
- 引用可打印数据编码早于 Unicode,仅适用于 8 位数据。在使用
quopri模块时,要确保所有文件都处于二进制模式,并且处理的是字节字符串。 - 处理包含特殊字符的文本时,要注意字符编码的问题,避免出现乱码。
4.2 XML 处理注意事项
- 命名空间处理 :在处理包含命名空间的 XML 文档时,要注意路径语法和属性查找方法的变化。例如,在
ElementTree模块中,路径中的标签字符串需要使用'{uri}tag'的形式;在xml.dom.minidom和xml.sax模块中,需要使用相应的命名空间方法来查找元素和属性。 - 内存管理 :处理大型 XML 文件时,要选择合适的解析方法,避免内存占用过高。如使用
xml.sax模块或ElementTree.iterparse()函数,及时丢弃不再使用的数据。
5. 拓展学习
5.1 第三方库推荐
- lxml.etree :提供了
ElementTreeAPI 到流行的libxml2和libxslt库的接口,支持 XPATH、XSLT 等功能,功能强大,性能优越。可以用于处理复杂的 XML 文档,进行 XML 转换和验证等操作。 - BeautifulSoup :虽然主要用于 HTML 解析,但也可以处理 XML 数据。它提供了简单易用的 API,能够快速定位和提取 XML 文档中的信息。
5.2 学习资源
- 官方文档 :Python 官方文档是学习这些模块的最佳资源,详细介绍了各个模块的功能和使用方法。
- 在线教程 :网上有很多关于 Python 网络数据处理和 XML 处理的教程,可以帮助你深入理解和掌握这些知识。
- 开源项目 :可以参考一些开源项目,学习他人的代码实现和处理思路。
通过学习和掌握这些模块,你可以更加高效地处理 Python 中的网络数据和 XML 文档,为开发各种应用程序打下坚实的基础。在实际应用中,要根据具体需求选择合适的模块和方法,同时注意处理过程中的细节和注意事项,以确保程序的正确性和性能。
超级会员免费看

被折叠的 条评论
为什么被折叠?



