
数据格式编码
更新: 2025/2/24 字数: 0 字 时长: 0 分钟
在爬取数据的过程或结果当中,我们会遇到各种各样的经过编码后的数据,熟知这些编码能更好规避采集过程中出现的错误。
JSON数据格式
JSON格式
**JSON 格式 ,即(JavaScript Object Notation)JavaScript 对象标记,它是网络响应中最常见的数据格式之一,也是大多数网站和数据接口服务所使用的格式。**特点如下:
- JSON 格式有两种,对象格式:
{"key1":obj,"key2":obj...}
,数组/集合格式:[obj,obj,obj...]
; - JSON 格式中的字符串没有单引号,全为双引号;
- 支持的数据类型:字符串、数字、布尔值、列表、字典。
**Python 中有内置的 json
模块专门处理 JSON 格式数据,直接导入就可以使用。**方法的使用案例如下:
# 导入json模块
import json
# json格式数据
data = '["iplaypython", [1, 2, 3], {"name": "xiaoming"}]'
# 将json格式数据转码成Python数据类型的数据
data = json.loads(data)
print(data, type(data))
# 将Python数据类型的数据编码为json格式的数据(indent参数表示可视化json的缩进空格数;ensure_ascii参数默认为True,会将汉字转为Unicode编码,可以指定False不转码汉字)
data = json.dumps(data)
print(data, type(data))
'''
输出:['iplaypython', [1, 2, 3], {'name': 'xiaoming'}] <class 'list'>
注释:json格式的数据里面的双引号全部变成了单引号,类型也从字符串变为了列表。
输出:["iplaypython", [1, 2, 3], {"name": "xiaoming"}] <class 'str'>
注释:将一个list列表对象进行json格式的转码,单引号变双引号,类型也从列表变为了JSON格式的字符串。
'''
**需要注意的是,并不是所有的字符串都可以进行 JSON 序列化,所以可以使用 json.loads
函数尝试将字符串解析为 JSON 对象,从而判断字符串是否可以进行 JSON 序列化。如果字符串是合法的 JSON 格式,json.loads
不会抛出异常,反之则会抛出异常。**以下是一个示例:
import json
def is_json_serializable(s):
try:
json.loads(s)
return True
except json.JSONDecodeError:
return False
# 测试字符串
json_serializable_string = '{"key": "value"}'
non_json_serializable_string = 'not a valid json string'
# 判断字符串是否可JSON序列化
print(is_json_serializable(json_serializable_string)) # 输出 True
print(is_json_serializable(non_json_serializable_string)) # 输出 False
JSON文件
**存储 JSON 格式数据且后缀名为 .json
的文本文件就是 JSON 文件,上面介绍的 json
模块也有专门处理 JSON 文件的方法。**方法的使用案例如下:
# 导入json模块
import json
# 将文件对象和操作类型赋值给f(r代表读取)
with open('./tt.json', 'r') as f:
# 将文件对象中的内容转码成python数据类型
file_data = json.load(f)
print(file_data, type(file_data))
'''
输出:[{"a": "aaa", "b": "bbb", "c": [1, 2, 3, [4, 5, 6]]}, 33, "tantengvip", true] <class 'list'>
'''
# 将文件对象和操作类型赋值给f(w代表写入)
with open('./ts.json', 'w') as f:
# 将python数据类型转化为json格式数据
json_data = json.dumps(file_data)
# 将json格式的数据写入文件对象f中
json.dump(json_data, f)
'''
新生成ts.json文件的内容为:"[{\"a\": \"aaa\", \"b\": \"bbb\", \"c\": [1, 2, 3, [4, 5, 6]]}, 33, \"tantengvip\", true]"
'''
字节编解码
字符串可以使用八进制字节码、十六进制字节码、Unicode(万国码)字节码来表示。
字节编码
string = 'abc'
o_s = ''.join([f'\\{ord(c):o}' for c in string])
print(o_s) # 输出:\141\142\143。注释:八进制编码。
h_s = ''.join([f'\\x{ord(c):x}' for c in string])
print(h_s) # 输出:\x61\x62\x63。注释:十六进制编码。
u_s = ''.join([f'\\u{ord(c):04x}' for c in string])
print(u_s) # 输出:\u0061\u0062\u0063。注释:Unicode编码。
字节解码
字节解码不需要使用方法,Python 会自动识别其编码,为其解码:
print('\141\142\143') # 输出:abc。注释:八进制写法。
print('\x61\x62\x63') # 输出:abc。注释:十六进制写法。
print('\u0061\u0062\u0063') # 输出:abc。注释:Unicode(万国码)表示法。
# 汉字编码范围十六进制(0x4e00, 0x9fa5)
for i in range(0x4e00, 0x9fa6):
print(chr(i), end='')
URL编解码
URL的编码格式采用的是ASCII编码,所有的非ASCII字符都要编码之后再传输。
URL编码
**URL编码(URL encoding),也称作百分号编码(Percent-encoding), 是特定上下文的统一资源定位符 (URL)的编码机制。**其编码原理为,将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式。比如,%
的ASCII码是37,对应16进制是25,那么 %%
的URL编码结果是 %25%25
。利用 urllib.parse
工具模块中的 quote
方法可以将内容转化为URL编码的格式。当URL中带有中文参数时,有可能导致乱码问题,此时用 quote
方法可以将中文字符转化为URL编码,适用于统一资源标识符(URI)的编码。
from urllib.parse import quote
url = 'https://www.baidu.com/s?wd=' + quote('公司')
print(url) # 输出:https://www.baidu.com/s?wd=%E5%85%AC%E5%8F%B8
url = 'https://www.baidu.com/s?wd=' + quote(quote('公司'))
print(url) # 输出:https://www.baidu.com/s?wd=%25E5%2585%25AC%25E5%258F%25B8
URL解码
**有了 quote
编码方法,当然就有 unquote
解码方法,它可以进行URL解码。**实例如下:
from urllib.parse import unquote
print(unquote('https://www.baidu.com/s?wd=%E5%85%AC%E5%8F%B8')) # 输出:https://www.baidu.com/s?wd=公司
print(unquote(unquote('https://www.baidu.com/s?wd=%25E5%2585%25AC%25E5%258F%25B8'))) # 输出:https://www.baidu.com/s?wd=公司
有的请求中会将中文字符先进行一次 gbk编码
,再进行URL编码,如果直接URL解码,会导致乱码,因为默认解码用的 utf-8编码
,但我们可以通过encoding参数指定编码解决。
from urllib.parse import quote, unquote
# 先将中文字符'公司'编码成GBK编码,再编码为URL编码
result = quote('公司', encoding='gbk')
# 输出编码结果
print(result) # 输出:%B9%AB%CB%BE
# 以默认的utf-8编码方式进行URL解码
print(unquote(result)) # 输出:��˾(乱码)
# 以GBK编码方式进行URL解码
print(unquote(result, encoding='gbk')) # 输出:公司
URL序列化
**这里再介绍一个非常常用的 urlencode
方法,它在构造 GET 请求参数的时候非常有用,只需提前声明一个字典 params
将参数表示出来,然后调用 urlencode
方法就会自动的将 params
序列化为 GET 请求的参数,而且也可以将中文字符指定编码再转化为 URL 编码。**代码如下:
from urllib.parse import urlencode
params = {
'name': 'germey',
'age': 25,
'wd': '公司'
}
# 默认的utf-8编码方式进行URL编码
url = 'https://www.baidu.com/s?' + urlencode(params)
print(url) # 输出:https://www.baidu.com/s?name=germey&age=25&wd=%E5%85%AC%E5%8F%B8
# gbk编码方式进行URL编码
url = 'https://www.baidu.com/s?' + urlencode(params, encoding='gbk')
print(url) # 输出:https://www.baidu.com/s?name=germey&age=25&wd=%B9%AB%CB%BE
URL反序列化
**有了序列化,必然会有反序列化,例用 parse_qs
、parse_qsl
方法,可以将一串GET请求参数返回序列化回字典或带元组的列表,也可以指定编码进行URL解码。**代码如下:
from urllib.parse import parse_qs, parse_qsl
query = 'name=germey&age=25&wd=%E5%85%AC%E5%8F%B8'
print(parse_qs(query)) # 输出:{'name': ['germey'], 'age': ['25'], 'wd': ['公司']}
print(parse_qsl(query)) # 输出:[('name', 'germey'), ('age', '25'), ('wd', '公司')]
query = 'name=germey&age=25&wd=%B9%AB%CB%BE'
print(parse_qs(query, encoding='gbk')) # 输出:{'name': ['germey'], 'age': ['25'], 'wd': ['公司']}
print(parse_qsl(query, encoding='gbk')) # 输出:[('name', 'germey'), ('age', '25'), ('wd', '公司')]
HTML编解码
HTML实体
**在 HTML 中一些字符是预留的,拥有特殊的含义,比如小于号 <
用于定义HTML标签的开始,所以这些字符是不允许在文本中使用的。**要想在 HTML 中显示 <
这个字符,就必须在 HTML 源码中插入字符实体,因此我们需要这样写 <
或这样写 <
,可以看到实体由三部分组成:一个和号 &
和一个实体名称 lt
或者一个 #实体编号
,以及一个分号 ;
,对于中文来说,HTML实体就是 &#中文Unicode码;
。建议在使用 HTML 实体时,用实体名称而不是实体编号,因为名称相对来说更容易记忆,几乎所有的浏览器对实体编号的支持都很好。
html模块
在 Python 中就有处理 HTML 实体的内置的 html
模块。使用如下:
# 导入内置的html模块
import html
# 字符串转HTML实体
str1 = '<随便写点代码>'
print(html.escape(str1))
# 将中文编码为html实体
str2 = ''.join([f'&#{ord(char)};' for char in str1])
print(str2)
# HTML实体转字符串
print(html.unescape(str2))
'''
输出:<随便写点代码>
注释:html模块方法不会将中文编码为HTML实体。
输出:<随便写点代码>
注释:<对应上面的<,>对应上面的>。
输出:<随便写点代码>
注释:将HTML实体转换为了符号和中文。
'''
警告
HTML实体对大小写敏感。
Base编解码
Base64编码
**Base64 是网络上最常见的用于传输字节码(Bit)的编码方式之一,是一种基于 64 个可打印字符(包括 A-Z
、a-z
、0-9
一共是 62 个字符,另外两个可打印符号通常是 +
和 /
,而 =
用在最后进行补位)来表示二进制数据到字符的过程,可用于在 HTTP 环境下传递较长的标识信息或者编码各类文件。**例如在网络传输图片请求中,有的 Base64 编码以 data:image/jpg;base64
开头,表明这是 jpg格式图片
的 Base64 编码,而有的图片 Base64 编码就没有这个开头,只是一串 Base64 编码。
Base32编码
Base32和Base64大同小异,其最大区别在于:Base64中包含大写字母(A-Z)、小写字母(a-z)、数字0——9以及 +
和 /
;Base32中只有大写字母(A-Z)和数字234567。
base64模块
在 Python 中就有处理 Base64 编码、Base32 编码的内置的 base64
模块。使用如下:
# 导入base64模块
import base64
'''
字符编解码
'''
# 将字符串数据编码为字符类型的Base32编码
print(base64.b32encode('abc'.encode()).decode()) # 输出:'MFRGG==='
# 将字符类型的Base32编码解码为字符串
print(base64.b32decode('MFRGG==='.encode()).decode()) # 输出:'abc'
# 将字符串数据编码为字符类型的Base64编码
print(base64.b64encode('abc'.encode()).decode()) # 输出:'YWJj'
# 将字符类型的Base64编码解码为字符串
print(base64.b64decode('YWJj'.encode()).decode()) # 输出:'abc'
'''
文件编解码
'''
# 以字节模式读写文件
with open('old.png', 'rb') as f1:
with open('new.png', 'wb') as f2:
# 读取old.png文件的bytes类型的数据,将其编码为bytes类型的Base64编码,最后解码为字符类型的Base64编码
img_base = base64.b64encode(f1.read()).decode()
print(img_base) # 输出:iVBORw0KGgoAAAA...(old.png文件的字符类型的Base64编码)
# 将字符类型的Base64编码编码为bytes类型的Base64编码,最后解码为bytes类型的数据,写入新的new.png文件
f2.write(base64.b64decode(img_base.encode()))
提醒
base64模块的编解码方法中传入的参数都是字节类型数据。
这个base64.b64decode('Tk8gUVE')为什么报错{Error}Incorrect padding?
报错 Incorrect padding
通常发生在 Base64 编码的字符串长度不符合正确的格式要求。Base64 编码要求输入的字符串长度必须是 4 的倍数,如果不是,必须在结尾添加 =
作为填充字符,以保证符合 Base64 的标准长度。
在你的例子中,Tk8gUVE
的长度是 7,不是 4 的倍数,缺少了必要的填充字符。
解决方法:
你可以手动添加 =
号来补足缺失的填充位。例如:
import base64
decoded = base64.b64decode('Tk8gUVE=')
print(decoded)
如果填充位缺失或不确定,可以通过添加 =
至长度为 4 的倍数来确保解码成功。
自动处理填充:
如果需要更通用的解决方案,自动补全 =
,你可以这样做:
import base64
def fix_base64_padding(s):
return s + '=' * (-len(s) % 4)
decoded = base64.b64decode(fix_base64_padding('Tk8gUVE'))
print(decoded)
这样可以保证自动填充,使得解码过程更灵活。