53、Python互联网数据处理与编码:从MIME到XML

Python互联网数据处理与编码:从MIME到XML

1. MIME类型处理

1.1 类型识别与扩展名猜测

在处理文件时,MIME类型的识别至关重要。默认情况下,仅识别在IANA注册的官方MIME类型。以下是一些与此相关的重要函数:
- guess_extension(type [, strict]) :根据MIME类型猜测文件的标准扩展名,返回包含前导点的字符串,未知类型返回 None 。若 strict True (默认),则仅识别官方MIME类型。
- guess_all_extensions(type [, strict]) :与 guess_extension() 类似,但返回所有可能的文件名扩展名列表。
- init([files]) :初始化模块, files 是用于提取类型信息的文件名序列,文件中包含将MIME类型映射到可接受文件后缀的行。
- read_mime_types(filename) :从给定文件名加载类型映射,返回将文件名扩展名映射到MIME类型字符串的字典,若文件不存在或无法读取则返回 None
- add_type(type, ext [, strict]) :向映射中添加新的MIME类型, type 是MIME类型, ext 是文件名扩展名, strict 表示该类型是否为官方注册的MIME类型,默认 strict True

1.2 示例

以下是一个简单的示例,展示如何使用这些函数:

import mimetypes

# 初始化模块
mimetypes.init()

# 猜测扩展名
extension = mimetypes.guess_extension('image/jpeg')
print(extension)  

# 添加新的MIME类型
mimetypes.add_type('text/markdown', '.md')

2. Quopri模块:引用可打印编码与解码

2.1 编码规则

Quopri模块用于对字节字符串进行引用可打印的传输编码和解码。这种格式主要用于编码大部分可作为ASCII读取,但可能包含少量非打印或特殊字符(如控制字符或范围在128 - 255的非ASCII字符)的8位文本文件。编码规则如下:
- 任何可打印的非空白ASCII字符(除 = 外)按原样表示。
- = 字符用作转义字符,后跟两个十六进制数字时,表示具有该值的字符(如 =0C ),等号本身表示为 =3D 。若 = 出现在行尾,则表示软换行,仅在输入文本的长行必须拆分为多个输出行时出现。
- 空格和制表符按原样保留,但不能出现在行尾。

2.2 函数介绍

  • decode(input, output [, header]) :将字节解码为Quopri格式, input output 是二进制模式打开的文件对象。若 header True ,则下划线( _ )将被解释为空格,默认 header False
  • decodestring(s [, header]) :解码字符串 s ,结果始终为字节字符串, header 含义与 decode() 相同。
  • encode(input, output, quotetabs [, header]) :将字节编码为Quopri格式, quotetabs 若设置为 True ,则强制对制表符进行引用,默认 quotetabs False header 含义与 decode() 相同。
  • encodestring(s [, quotetabs [, header]]) :编码字节字符串 s ,结果也是字节字符串, quotetabs header 含义与 encode() 相同。

2.3 示例

import quopri

# 编码字符串
encoded = quopri.encodestring(b'Copyright \xa9 2009')
print(encoded)  

# 解码字符串
decoded = quopri.decodestring(encoded)
print(decoded)  

3. XML处理

3.1 XML概述

Python提供了多种处理XML数据的模块,涵盖了SAX、DOM和ElementTree等解析方法。SAX基于事件处理,按顺序读取XML文档,遇到XML元素时触发处理函数;DOM构建表示整个XML文档的树结构,构建完成后提供遍历树和提取数据的接口;ElementTree是Python特有的XML解析方法,充分利用Python语言特性,对大多数用户来说比SAX或DOM更简单、更快速。

3.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>

3.3 xml.dom.minidom模块

3.3.1 解析函数
  • parse(file [, parser]) :解析文件内容,返回表示文档树顶部的节点, file 可以是文件名或已打开的文件对象, parser 是可选的SAX2兼容解析器对象,若省略则使用默认解析器。
  • parseString(string [, parser]) :与 parse() 相同,但输入数据以字符串形式提供。
3.3.2 节点属性和方法

文档树由一系列节点组成,每个节点 n 具有以下属性和方法:
|属性/方法|描述|
|----|----|
| n.attributes |保存属性值的映射对象(如果有)|
| n.childNodes | n 的所有子节点列表|
| n.firstChild |节点 n 的第一个子节点|
| n.lastChild |节点 n 的最后一个子节点|
| n.localName |元素的本地标签名|
| n.namespaceURI |与 n 关联的命名空间(如果有)|
| n.nextSibling |树中 n 之后且具有相同父节点的节点,若 n 是最后一个兄弟节点则为 None |
| n.nodeName |节点的名称,含义取决于节点类型|
| n.nodeType |描述节点类型的整数|
| n.nodeValue |节点的值,含义取决于节点类型|
| n.parentNode |对父节点的引用|
| n.prefix |标签名中冒号之前的部分|
| 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 |
| n.isSameNode(other) |若节点 other 引用与 n 相同的DOM节点则返回 True |
| n.normalize() |将相邻的文本节点合并为一个文本节点|
| n.removeChild(child) |从 n 中移除子节点 child |
| n.replaceChild(newchild,oldchild) |用 newchild 替换子节点 oldchild |

3.3.3 示例
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))

3.4 xml.etree.ElementTree模块

3.4.1 ElementTree对象

ElementTree([element [, file]]) :创建新的 ElementTree 对象, element 表示树的根节点, file 可以是文件名或文件类对象,用于读取XML数据以填充树。

3.4.2 方法和路径语法

ElementTree 对象具有以下方法:
- tree._setroot(element) :将根元素设置为 element
- tree.find(path) :查找并返回树中第一个类型与给定路径匹配的顶级元素,路径语法如下表所示:
|路径|描述|
|----|----|
| 'tag' |仅匹配具有给定标签的顶级元素|
| 'parent/tag' |若元素具有标签 tag 且是具有标签 parent 的元素的子元素,则匹配|
| '*' |选择所有子元素|
| '.' |从当前节点开始搜索|
| '//' |选择元素下方所有级别的子元素|
- 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 是输出编码,默认使用解释器的默认编码。

3.4.3 创建元素

可以使用以下函数创建元素:
- Comment([text]) :创建新的注释元素。
- Element(tag [, attrib [, **extra]]) :创建新元素, tag 是元素名称, attrib 是元素属性的字典, extra 中的任何额外关键字参数也用于设置元素属性。
- fromstring(text) :从XML文本片段创建元素。
- ProcessingInstruction(target [, text]) :创建对应于处理指令的新元素。
- SubElement(parent, tag [, attrib [, **extra]]) :与 Element() 相同,但自动将新元素添加为 parent 元素的子元素。
- XML(text) :通过解析XML代码片段创建元素。
- XMLID(text) :与 XML(text) 相同,但收集 'id' 属性并用于构建将ID值映射到元素的字典,返回元组 (elem, idmap)

3.4.4 元素接口

元素支持以下Python运算符和方法:
|运算符/方法|描述|
|----|----|
| elem[n] |返回 elem 的第 n 个子元素|
| elem[n] = newelem |将 elem 的第 n 个子元素更改为不同的元素 newelem |
| del elem[n] |删除 elem 的第 n 个子元素|
| len(elem) | elem 的子元素数量|
| elem.tag |标识元素类型的字符串|
| elem.text |与元素关联的数据|
| elem.tail |与属性一起存储的额外数据|
| 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 |
| 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 |

3.4.5 示例
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))

3.5 xml.sax模块

3.5.1 解析函数
  • parse(file, handler [, error_handler]) :解析XML文档, file 可以是文件名或打开的文件对象, handler 是内容处理程序对象, error_handler 是可选的SAX错误处理程序对象。
  • parseString(string, handler [, error_handler]) :与 parse() 相同,但解析字符串中包含的XML数据。
3.5.2 处理程序对象

要执行任何处理,需要向 parse() parseString() 函数提供内容处理程序对象。可以定义一个继承自 ContentHandler 的类,重写以下方法:
|方法|描述|
|----|----|
| c.characters(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元素时调用|
| c.startElementNS(name, qname, attrs) |遇到新的XML元素且使用XML命名空间时调用|
| c.startPrefixMapping(prefix, uri) |开始XML命名空间声明时调用|

3.5.3 示例
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())

3.6 xml.sax.saxutils模块

该模块定义了一些常用的实用函数和对象:
- escape(data [, entities]) :将字符串中的某些字符替换为转义序列。
- unescape(data [, entities]) :对数据中出现的特殊转义序列进行反转义。
- quoteattr(data [, entities]) :对字符串进行转义,并进行额外处理,使结果值可作为XML属性值。
- XMLGenerator([out [, encoding]]) :一个 ContentHandler 对象,将解析的XML数据作为XML文档回显到输出流,可用于调试解析代码。

4. 总结

Python提供了丰富的工具来处理互联网数据,从MIME类型的识别到XML文档的解析,每个模块都有其独特的优势和适用场景。Quopri模块适用于处理包含特殊字符的文本文件的编码和解码,而XML处理模块则提供了多种解析方法,可根据具体需求选择合适的方法。例如,对于简单的XML文档, ElementTree 模块是最容易和灵活的选择;而对于需要处理复杂XML文档的情况,可能需要使用第三方包。通过合理使用这些工具,可以高效地处理各种互联网数据。

3.7 各XML处理模块对比

为了更清晰地了解不同XML处理模块的特点,下面对 xml.dom.minidom xml.etree.ElementTree xml.sax 进行对比:
| 模块 | 特点 | 适用场景 | 优点 | 缺点 |
| — | — | — | — | — |
| xml.dom.minidom | 构建完整的文档树结构,提供丰富的节点操作方法 | 需要频繁遍历和修改文档结构,对文档进行复杂操作 | 提供完整的DOM接口,方便进行节点的增删改查操作 | 占用内存大,解析速度慢,不适合处理大文件 |
| xml.etree.ElementTree | 轻量级,操作简单,提供灵活的路径查找语法 | 处理简单的XML文档,需要快速提取数据 | 易于使用,代码简洁,内存占用相对较小 | 缺乏复杂的XML功能,如验证、DTD处理等 |
| xml.sax | 基于事件驱动,逐行解析XML文档 | 处理大文件,只需提取部分数据,无需构建完整文档树 | 内存占用小,解析速度快 | 编程复杂度高,需要编写大量的事件处理代码 |

3.8 处理XML命名空间

当XML文档使用命名空间时,处理起来会稍微复杂一些。下面是一个使用 xml.etree.ElementTree 处理命名空间的示例:

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))

在这个示例中,我们使用一个字典 ns 来映射命名空间前缀和URI,然后在路径中使用字符串格式化来填充URI。

3.9 处理大XML文件

对于大XML文件,将整个文件加载到内存中会消耗大量的内存。可以使用 ElementTree.iterparse() 函数来逐行解析文件,避免内存问题。以下是一个示例:

from xml.etree.ElementTree import iterparse

iparse = iterparse("music.xml", ['start', 'end'])
# Find the top-level music element
for event, elem in iparse:
    if event == 'start' and elem.tag == 'music':
        musicNode = elem
        break
# Get all albums
albums = (elem for event, elem in iparse if event == 'end' and elem.tag == 'album')
for album in albums:
    # Do some kind of processing
    ...
    musicNode.remove(album)  # Throw away the album when done

在这个示例中,我们使用 iterparse() 函数逐行解析文件,当遇到 <music> 元素时,记录该元素。然后,使用生成器表达式获取所有的 <album> 元素,并在处理完每个元素后将其从父元素中移除,以释放内存。

3.10 XML处理流程总结

下面是一个使用mermaid绘制的流程图,展示了处理XML文件的一般流程:

graph LR
    A[选择处理模块] --> B{文件大小}
    B -->|小文件| C[xml.dom.minidom或xml.etree.ElementTree]
    B -->|大文件| D[xml.sax或xml.etree.ElementTree.iterparse]
    C --> E{操作复杂度}
    E -->|简单操作| F[xml.etree.ElementTree]
    E -->|复杂操作| G[xml.dom.minidom]
    D --> H[逐行解析数据]
    F --> I[提取数据或修改文档]
    G --> I
    H --> I
    I --> J[输出结果]

4. 综合应用示例

假设我们需要从一个包含多个食谱的XML文件中提取所有食谱的名称和所需的啤酒数量,并将结果保存到一个新的文本文件中。以下是一个使用 xml.etree.ElementTree 实现的示例代码:

from xml.etree.ElementTree import ElementTree

# 解析XML文件
doc = ElementTree(file="recipes.xml")

# 打开输出文件
with open("beer_quantity.txt", "w") as outfile:
    # 查找所有食谱
    recipes = doc.findall(".//recipe")
    for recipe in recipes:
        # 获取食谱名称
        title = recipe.find("title").text.strip()
        # 查找啤酒配料
        beer_items = recipe.findall(".//item[contains(text(), 'beer')]")
        total_beer = 0
        for item in beer_items:
            num = item.get('num')
            try:
                total_beer += float(num)
            except ValueError:
                pass
        # 写入结果
        outfile.write(f"{title}: {total_beer} bottles of beer\n")

print("结果已保存到beer_quantity.txt")

5. 总结与展望

5.1 总结

Python在互联网数据处理和编码方面提供了丰富的工具和模块。MIME类型处理模块可以帮助我们识别和处理不同类型的文件,Quopri模块适用于处理包含特殊字符的文本文件的编码和解码。在XML处理方面, xml.dom.minidom xml.etree.ElementTree xml.sax 各有优缺点,可以根据具体需求选择合适的模块。对于简单的XML文档, ElementTree 模块是最容易和灵活的选择;而对于处理大文件或需要复杂操作的情况,可能需要使用 xml.sax xml.dom.minidom

5.2 展望

虽然Python的标准库提供了基本的XML处理功能,但对于一些高级需求,如XML验证、DTD处理、XSLT转换等,可能需要使用第三方库,如 lxml 。未来,随着互联网数据的不断增长和XML技术的不断发展,Python的XML处理能力也将不断完善和扩展。同时,对于其他类型的互联网数据处理,如JSON、CSV等,Python也提供了相应的工具和模块,我们可以进一步探索和应用这些工具,以满足不同的业务需求。

通过短时倒谱(Cepstrogram)计算进行时-倒频分析研究(Matlab代码实现)内容概要:本文主要介绍了一项关于短时倒谱(Cepstrogram)计算在时-倒频分析中的研究,并提供了相应的Matlab代码实现。通过短时倒谱分析方法,能够有效提取信号在时间倒频率域的特征,适用于语音、机械振动、生物医学等领域的信号处理故障诊断。文中阐述了倒谱分析的基本原理、短时倒谱的计算流程及其在实际工程中的应用价值,展示了如何利用Matlab进行时-倒频图的可视化分析,帮助研究人员深入理解非平稳信号的周期性成分谐波结构。; 适合人群:具备一定信号处理基础,熟悉Matlab编程,从事电子信息、机械工程、生物医学或通信等相关领域科研工作的研究生、工程师及科研人员。; 使用场景及目标:①掌握倒谱分析短时倒谱的基本理论及其傅里叶变换的关系;②学习如何用Matlab实现Cepstrogram并应用于实际信号的周期性特征提取故障诊断;③为语音识别、机械设备状态监测、振动信号分析等研究提供技术支持方法参考; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,先理解倒谱的基本概念再逐步实现短时倒谱分析,注意参数设置如窗长、重叠率等对结果的影响,同时可将该方法其他时频分析方法(如STFT、小波变换)进行对比,以提升对信号特征的理解能力。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值