Python 网络数据处理与编码实用指南
1. hashlib 模块
hashlib 模块实现了多种安全哈希和消息摘要算法,如 MD5 和 SHA1。要计算哈希值,需调用以下函数,函数名与所代表的算法相同:
| 函数 | 描述 |
| — | — |
| md5() | MD5 哈希(128 位) |
| sha1() | SHA1 哈希(160 位) |
| sha224() | SHA224 哈希(224 位) |
| sha256() | SHA256 哈希(256 位) |
| sha384() | SHA384 哈希(384 位) |
| sha512() | SHA512 哈希(512 位) |
这些函数返回的摘要对象实例 d 具有以下接口:
| 方法或属性 | 描述 |
| — | — |
| d.update(data) | 用新数据更新哈希。data 必须是字节串。重复调用等同于使用连接数据的单次调用。 |
| d.digest() | 以原始字节串形式返回摘要值。 |
| d.hexdigest() | 返回以十六进制数字编码的摘要值的文本字符串。 |
| d.copy() | 返回摘要的副本。副本保留原始摘要的内部状态。 |
| d.digest_size | 结果哈希的字节大小。 |
| d.block_size | 哈希算法的内部块大小(字节)。 |
该模块还提供了另一种构造接口:
- new(hashname) :创建一个新的摘要对象。 hashname 是一个字符串,如 ‘md5’ 或 ‘sha256’,指定要使用的哈希算法的名称。哈希名称可以是上述任何一种哈希算法,也可以是 OpenSSL 库公开的哈希算法(取决于安装情况)。
2. hmac 模块
hmac 模块支持 HMAC(用于消息认证的键控哈希),该算法在 RFC - 2104 中有所描述。HMAC 是一种基于 MD5 和 SHA - 1 等加密哈希函数的消息认证机制。
2.1 创建 HMAC 对象
-
new(key [, msg [, digest]]):创建一个新的 HMAC 对象。这里,key是一个字节串,包含哈希的起始密钥;msg包含要处理的初始数据;digest是用于加密哈希的摘要构造函数。默认情况下,digest是hashlib.md5。通常,初始密钥值是使用加密强随机数生成器随机确定的。
2.2 HMAC 对象的方法
| 方法 | 描述 |
|---|---|
| h.update(msg) | 将字符串 msg 添加到 HMAC 对象。 |
| h.digest() | 返回到目前为止处理的所有数据的摘要,并返回一个包含摘要值的字节串。字符串的长度取决于底层哈希函数。对于 MD5,为 16 个字符;对于 SHA - 1,为 20 个字符。 |
| h.hexdigest() | 以十六进制数字字符串形式返回摘要。 |
| h.copy() | 复制 HMAC 对象。 |
2.3 示例
hmac 模块的主要用途是在需要对消息发送者进行身份验证的应用程序中。以下是一个示例:
import hmac
secret_key = b"peekaboo" # 仅我知道的字节串。通常,你会希望使用 os.urandom() 或类似方法计算的随机字节串
data = b"Hello World" # 要发送的消息
# 发送消息
# out 代表一个套接字或其他 I/O 通道,我们通过它发送数据
h = hmac.new(secret_key)
h.update(data)
# 这里假设 out 是一个有效的发送通道
# out.send(data) # 发送数据
# out.send(h.digest()) # 发送摘要
# 接收消息
# in 代表一个套接字或其他 I/O 通道,我们通过它接收数据
h = hmac.new(secret_key)
# 这里假设 in 是一个有效的接收通道
# data = in.receive() # 获取消息数据
# h.update(data)
# digest = in.receive() # 获取发送者发送的摘要
# if digest != h.digest():
# raise AuthenticationError('Message not authenticated')
该示例展示了如何使用 hmac 模块进行消息身份验证。发送者使用密钥创建 HMAC 对象,更新对象并发送消息和摘要;接收者使用相同的密钥和消息数据计算自己的摘要,并与接收到的摘要进行比较。
3. HTMLParser 模块
在 Python 3 中,该模块名为 html.parser 。 HTMLParser 模块定义了一个 HTMLParser 类,可用于解析 HTML 和 XHTML 文档。要使用此模块,需定义自己的类,继承自 HTMLParser 并根据需要重新定义方法。
3.1 创建 HTML 解析器
-
HTMLParser():这是用于创建 HTML 解析器的基类,无需任何参数进行初始化。
3.2 HTMLParser 实例的方法
| 方法 | 描述 |
|---|---|
| h.close() | 关闭解析器并强制处理任何剩余的未解析数据。在所有 HTML 数据都已提供给解析器后调用此方法。 |
| h.feed(data) | 向解析器提供新数据。此数据将立即解析。如果数据不完整(例如,以不完整的 HTML 元素结尾),不完整的部分将被缓冲,下次调用 feed() 并提供更多数据时进行解析。 |
| h.getpos() | 以元组 (line, offset) 形式返回当前行号和该行中的字符偏移量。 |
| h.get_starttag_text() | 返回与最近打开的开始标签对应的文本。 |
| h.handle_charref(name) | 每当遇到字符引用(如 ‘&#ref;’)时调用此处理方法。 name 是一个包含引用名称的字符串。 |
| h.handle_comment(data) | 每当遇到注释时调用此处理方法。 data 是一个包含注释文本的字符串。 |
| h.handle_data(data) | 调用此处理程序处理标签之间出现的数据。 data 是一个包含文本的字符串。 |
| h.handle_decl(decl) | 调用此处理程序处理声明(如 ‘<!DOCTYPE HTML …>’)。 decl 是一个包含声明文本的字符串,不包括开头的 ‘<!’ 和结尾的 ‘>’。 |
| h.handle_endtag(tag) | 每当遇到结束标签时调用此处理程序。 tag 是转换为小写的标签名称。 |
| h.handle_entityref(name) | 调用此处理程序处理实体引用(如 ‘&name‘)。 name 是一个包含引用名称的字符串。 |
| h.handle_pi(data) | 调用此处理程序处理处理指令(如 ‘<?processing instruction>’)。 data 是一个包含处理指令文本的字符串,不包括开头的 ‘<?’ 或结尾的 ‘>’。对于 XHTML 风格的指令 ‘<?…?>’,最后一个 ‘?’ 将包含在 data 中。 |
| h.handle_startendtag(tag, attrs) | 处理 XHTML 风格的空标签(如 ‘
‘)。 tag 是一个包含标签名称的字符串。 attrs 包含属性信息,是一个元组列表,形式为 (name, value) ,其中 name 是转换为小写的属性名称, value 是属性值。如果派生类中未定义此方法,默认实现会调用 handle_starttag() 和 handle_endtag() 。 |
| h.handle_starttag(tag, attrs) | 处理开始标签(如 ‘
‘)。
tag 和
attrs 的含义与
handle_startendtag() 中描述的相同。
|
| h.reset() | 重置解析器,丢弃任何未处理的数据。 |
3.3 异常
-
HTMLParserError:由于解析错误而引发的异常。该异常有三个属性:msg属性包含描述错误的消息,lineno属性是解析错误发生的行号,offset属性是该行中的字符偏移量。
3.4 示例
以下示例使用 urllib 包获取 HTML 文档,并打印所有通过 ‘ ’ 声明指定的链接:
# printlinks.py
try:
from HTMLParser import HTMLParser
from urllib2 import urlopen
except ImportError:
from html.parser import HTMLParser
from urllib.request import urlopen
import sys
class PrintLinks(HTMLParser):
def handle_starttag(self, tag, attrs):
if tag == 'a':
for name, value in attrs:
if name == 'href':
print(value)
p = PrintLinks()
u = urlopen(sys.argv[1])
data = u.read()
charset = u.info().getparam('charset') # Python 2
# charset = u.info().get_content_charset() # Python 3
p.feed(data.decode(charset))
p.close()
此示例展示了如何使用 HTMLParser 解析 HTML 文档并提取链接。需要注意的是,使用 urllib 获取的 HTML 以字节串形式返回,需要根据文档字符集编码将其解码为文本。
4. json 模块
json 模块用于序列化和反序列化使用 JavaScript 对象表示法(JSON)表示的对象。JSON 格式实际上是 JavaScript 语法的一个子集,与 Python 表示列表和字典的语法非常相似。
4.1 JSON 值与 Python 值的映射
| JSON 类型 | Python 类型 |
|---|---|
| object | dict |
| array | list (tuple) |
| string | unicode (str, bytes) |
| number | int, float |
| true | True |
| false | False |
| null | None |
对于字符串数据,应假设使用 Unicode。编码时遇到字节串,默认使用 ‘utf - 8’ 解码为 Unicode 字符串(可控制)。解码时,JSON 字符串始终以 Unicode 形式返回。
4.2 编码函数
-
dump(obj, f, **opts):将对象obj序列化为类文件对象f。opts是一组关键字参数,可用于控制序列化过程:-
skipkeys:布尔标志,控制当字典键(而非值)不是字符串或数字等基本类型时的处理方式。如果为 True,则跳过这些键;如果为 False(默认),则引发TypeError。 -
ensure_ascii:布尔标志,确定是否可以将 Unicode 字符串写入文件f。默认值为 False。仅当f是能正确处理 Unicode 的文件(如由codecs模块创建或使用特定编码打开的文件)时,才将其设置为 True。 -
check_circular:布尔标志,确定是否检查容器中的循环引用。默认值为 True。如果设置为 False 且遇到循环引用,则引发OverflowError异常。 -
allow_nan:布尔标志,确定是否序列化超出范围的浮点值(如 NaN、inf、 - inf)。默认值为 True。 -
cls:要使用的JSONEncoder子类。如果通过继承JSONEncoder创建了自己的自定义编码器,则指定此参数。如果dump()有任何其他关键字参数,则将其作为参数传递给此类的构造函数。 -
indent:一个非负整数,设置打印数组和对象成员时使用的缩进量。设置此参数会产生一种漂亮打印的效果。默认值为 None,结果以最紧凑的表示形式呈现。 -
separators:形式为(item_separator, dict_separator)的元组,其中item_separator是包含数组项之间分隔符的字符串,dict_separator是包含字典键和值之间分隔符的字符串。默认值为(', ', ': ')。 -
encoding:用于 Unicode 字符串的编码,默认值为 ‘utf - 8’。 -
default:用于序列化不支持的基本类型对象的函数。它应返回一个可序列化的值(即字符串)或引发TypeError。默认情况下,对于不支持的类型引发TypeError。
-
-
dumps(obj, **opts):与dump()相同,只是返回包含结果的字符串。
4.3 解码函数
-
load(f, **opts):从类文件对象f反序列化 JSON 对象并返回。opts是一组关键字参数,可用于控制解码过程:-
encoding:用于解释解码的任何字符串值的编码,默认值为 ‘utf - 8’。 -
strict:布尔标志,确定是否允许 JSON 字符串中出现字面(未转义)换行符。默认值为 True,即对于此类字符串会生成异常。 -
cls:用于解码的JSONDecoder子类。仅当通过继承JSONDecoder创建了自定义解码器时才指定此参数。load()的任何额外关键字参数将提供给类构造函数。 -
object_hook:对每个解码的 JSON 对象的结果调用的函数。默认情况下,这是内置的dict()函数。 -
parse_float:用于解码 JSON 浮点值的函数。默认情况下,这是内置的float()函数。 -
parse_int:用于解码 JSON 整数值的函数。默认情况下,这是内置的int()函数。 -
parse_constant:用于解码 JSON 常量(如 ‘NaN’、’true’、’false’ 等)的函数。
-
-
loads(s, **opts):与load()相同,只是从字符串s反序列化对象。
需要注意的是,这些函数虽然与 pickle 和 marshal 模块中的函数同名且用于序列化数据,但使用方式不同。不应使用 dump() 将多个 JSON 编码对象写入同一文件,同样, load() 也不能用于从同一文件读取多个 JSON 编码对象。
4.4 自定义编码和解码
如果要自定义编码或解码过程,可以继承以下基类:
- JSONDecoder(**opts) :用于解码 JSON 数据的类。 opts 是一组关键字参数,与 load() 函数使用的参数相同。实例 d 具有以下两个方法:
- d.decode(s) :返回字符串 s 中 JSON 对象的 Python 表示形式。
- d.raw_decode(s) :返回一个元组 (pyobj, index) ,其中 pyobj 是字符串 s 中 JSON 对象的 Python 表示形式, index 是 s 中 JSON 对象结束的位置。可用于从输入流中解析对象,且流末尾有额外数据的情况。
- JSONEncoder(**opts) :用于将 Python 对象编码为 JSON 的类。 opts 是一组关键字参数,与 dump() 函数使用的参数相同。实例 e 具有以下方法:
- e.default(obj) :当 Python 对象 obj 无法根据任何正常编码规则进行编码时调用的方法。该方法应返回一个可编码的类型(如字符串、列表或字典)的结果。
- e.encode(obj) :调用此方法创建 Python 对象 obj 的 JSON 表示形式。
- e.iterencode(obj) :创建一个迭代器,在计算 Python 对象 obj 的 JSON 表示形式的字符串时生成这些字符串。创建 JSON 字符串的过程本质上是高度递归的。例如,它涉及遍历字典的键并深入到沿途找到的其他字典和列表中。如果使用此方法,可以逐块处理输出,而不是将所有内容收集到一个巨大的内存字符串中。
如果定义继承自 JSONDecoder 或 JSONEncoder 的子类,且类中定义了 __init__() ,需要注意处理所有关键字参数。以下是一个示例:
class MyJSONDecoder(JSONDecoder):
def __init__(self, **kwargs):
# 获取自己的参数
foo = kwargs.pop('foo', None)
bar = kwargs.pop('bar', None)
# 用剩余的参数初始化父类
JSONDecoder.__init__(self, **kwargs)
5. mimetypes 模块
mimetypes 模块用于根据文件名扩展名猜测与文件关联的 MIME 类型,还可将 MIME 类型转换为标准文件名扩展名。MIME 类型由类型/子类型对组成,例如 ‘text/html’、’image/png’ 或 ‘audio/mpeg’。
5.1 猜测 MIME 类型
-
guess_type(filename [, strict]):根据文件名或 URL 猜测文件的 MIME 类型。返回一个元组(type, encoding),其中type是 “type/subtype” 形式的字符串,encoding是用于传输数据编码的程序(如 compress 或 gzip)。如果无法猜测类型,则返回(None, None)。如果strict为 True(默认),则使用严格的 MIME 类型匹配规则。
以下是一个使用 mimetypes 模块的简单示例:
import mimetypes
filename = 'example.html'
mime_type, encoding = mimetypes.guess_type(filename)
print(f"MIME type: {mime_type}, Encoding: {encoding}")
这个示例展示了如何使用 guess_type 函数来猜测文件的 MIME 类型和编码。
综上所述,这些模块在 Python 的网络数据处理和编码方面提供了强大的功能。hashlib 和 hmac 模块用于哈希计算和消息认证,HTMLParser 模块用于解析 HTML 和 XHTML 文档,json 模块用于 JSON 数据的序列化和反序列化,mimetypes 模块用于猜测文件的 MIME 类型。通过合理使用这些模块,可以更高效地处理和传输网络数据。
6. 模块使用流程总结
6.1 hashlib 模块使用流程
graph LR
A[选择哈希算法函数] --> B[创建摘要对象]
B --> C{是否有新数据?}
C -- 是 --> D[调用 update 方法更新数据]
C -- 否 --> E[获取摘要值]
D --> E
E --> F[可选: 复制摘要对象]
6.2 hmac 模块使用流程
graph LR
A[确定密钥] --> B[创建 HMAC 对象]
B --> C[更新 HMAC 对象数据]
C --> D[发送消息和摘要]
D --> E[接收消息和摘要]
E --> F[验证摘要]
6.3 HTMLParser 模块使用流程
graph LR
A[定义继承类] --> B[创建解析器实例]
B --> C[获取 HTML 数据]
C --> D[解码数据]
D --> E[向解析器提供数据]
E --> F[关闭解析器]
6.4 json 模块使用流程
编码流程
graph LR
A[选择编码函数] --> B[确定对象和参数]
B --> C[生成 JSON 数据]
解码流程
graph LR
A[选择解码函数] --> B[确定数据源和参数]
B --> C[解析 JSON 数据]
6.5 mimetypes 模块使用流程
graph LR
A[提供文件名或 URL] --> B[调用 guess_type 函数]
B --> C[获取 MIME 类型和编码]
7. 注意事项和常见问题
7.1 hashlib 模块
- 不同的哈希算法产生的摘要长度不同,如 MD5 为 128 位(16 字节),SHA1 为 160 位(20 字节)等,使用时要根据需求选择合适的算法。
- 在更新摘要对象时,传入的数据必须是字节串。
7.2 hmac 模块
- 密钥必须是字节串,且要保证发送者和接收者使用相同的密钥。
- 处理消息时,要确保消息数据和摘要的完整性,避免传输过程中数据丢失或被篡改。
7.3 HTMLParser 模块
- 该模块的解析能力有限,对于复杂或格式错误的 HTML 文档,可能会出现解析错误。
- 使用
urllib获取的 HTML 数据是字节串,需要根据文档字符集编码进行解码。
7.4 json 模块
- 不要使用
dump()函数将多个 JSON 编码对象写入同一文件,也不要使用load()函数从同一文件读取多个 JSON 编码对象。 - 处理自定义类型时,需要自定义编码器或解码器。
7.5 mimetypes 模块
-
guess_type函数的猜测结果可能不准确,特别是对于一些不常见的文件扩展名。
8. 综合示例
以下是一个综合使用上述模块的示例,实现一个简单的网络消息认证和数据处理程序:
import hmac
import hashlib
from html.parser import HTMLParser
import json
import mimetypes
from urllib.request import urlopen
import sys
# 模拟消息发送和认证
secret_key = b"mysecretkey"
message = b"Hello, this is a test message."
h = hmac.new(secret_key, digestmod=hashlib.sha256)
h.update(message)
digest = h.digest()
# 模拟消息接收和验证
received_h = hmac.new(secret_key, digestmod=hashlib.sha256)
received_h.update(message)
if received_h.digest() == digest:
print("Message authenticated successfully.")
else:
print("Message authentication failed.")
# 解析 HTML 文档并提取链接
class PrintLinks(HTMLParser):
def handle_starttag(self, tag, attrs):
if tag == 'a':
for name, value in attrs:
if name == 'href':
print(value)
try:
u = urlopen(sys.argv[1])
data = u.read()
charset = u.info().get_content_charset()
p = PrintLinks()
p.feed(data.decode(charset))
p.close()
except IndexError:
print("Please provide a URL as a command-line argument.")
# JSON 数据处理
data = {
"name": "John",
"age": 30,
"city": "New York"
}
json_data = json.dumps(data)
print("JSON data:", json_data)
parsed_data = json.loads(json_data)
print("Parsed data:", parsed_data)
# 猜测文件的 MIME 类型
filename = 'example.html'
mime_type, encoding = mimetypes.guess_type(filename)
print(f"MIME type: {mime_type}, Encoding: {encoding}")
这个示例展示了如何在一个程序中综合使用 hmac 、 HTMLParser 、 json 和 mimetypes 模块,实现消息认证、HTML 解析、JSON 数据处理和 MIME 类型猜测等功能。
通过对这些模块的学习和使用,我们可以更好地处理 Python 中的网络数据,提高数据处理的效率和安全性。在实际应用中,要根据具体需求选择合适的模块和方法,并注意处理可能出现的异常情况。
超级会员免费看
9908

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



