python中文编码&json中文输出问题
python2.x 版本的字符编码有时让人很头疼,遇到问题,网上方法可以解决错误,但对原理还是一知半解,本文主要介绍 python 中字符串处理的原理,附带解决 json 文件输出时,显示中文而非 unicode 问题。首先简要介绍字符串编码的历史,其次,讲解 python 对于字符串的处理,及编码的检测与转换,最后,介绍 python 爬虫采取的 json 数据存入文件时中文输出的问题。
参考书籍:Python 网络爬虫从入门到实践 by 唐松
在 python 2 或者 3 ,字符串编码只有两类 :
(1)通用的 Unicode 编码;
(2)将 Unicode 转化为某种类型的编码,如 UTF-8,GBK;
1、计算机历史:
计算机只处理数字,因此处理文本时,必须转换成数字才行。
8 位(bit)=1 字节(byte)=256 种不同状态 = 从 000000 到 111111;
1GB=1024M=1024(1024kb)=1024(1024(1024b));
ASCII 编码 是对应英文字符与二进制数字之间的关系;ASCII 一共规定了 128 种,如大写字母 A 是 65,即 01000001;可见一字母一字节;
GB2312 编码 简体中文常见的编码,两个字节代表一个中文汉字 ,理论上 256*256 个编码,即可表示 65536 种中文字;
各国编码不同,为了各国能扩平台进行文本的转换与处理,Unicode就被作为统一码或者单一码。Unicode 编码通常是两个字节,unicode 与 ASCII 编码的区别,在于 unicode 在 ASCII 编码前加了一个 0,即字母 A 的 ASCII 编码为 01000001,unicode 编码即为00000000
01000001; 但英文字母其实只用一个字节就够了,unicode 编码写英文时多了一个字节,浪费存储空间。因而 unicode 开发了通用转换格式(Unicode Transformation Format(UTF)), 常见的有 utf-8 或者 utf-16;
2、python 字符编码
参考地址:https://www.jb51.net/article/139878.htm
(1)encode 的作用是,将 unicode 对象编码成其他编码的字符串,str.encode('utf-8'), 编码成 UTF-8;(2)decode 的作用是将其他编码的字符串转换成 Unicode 编码,str.decode('UTF-8');
- import chardet 查阅具体的编码类型,
chardet.detect(str)
,但是 str 不能是 unicode 编码类型,但是该方法 不接受 本来已经是 unicode 的编码的 参数,会有 TypeError: Expected object of type bytes or bytearray, got: <type 'unicode'> 错误; - 作为统一标准,unicode 不能再被解码,如果 UTF-8 想转至其他非 unicode,则必须(2)先 decode 到 unicode,在 encode 到其他非 unicode 的编码。
爬取网页时,可在 F12 elements meta 中查看网页编码方式,如图:
(2) 中文,Python 中的字典能够被序列化到 json 文件中存入 json
with open("anjuke_salehouse.json","w",encoding='utf-8') as f:
json.dump(all_house,f,ensure_ascii=False,sort_keys=True, indent=4);
print(u'加载入文件完成...');
存储数据如图:
- dump() 的第一个参数是要序列化的对象,第二个参数是打开的文件句柄,注意文件打开
open()
时加上以UTF-8 编码打开,在dump()
的时候也加上ensure_ascii=False, 不然会变成 ascii 码写到 json 文件中json.dump(all_house,f,ensure_ascii=False,sort_keys=True, indent=4)
json.dumps()/json.loads() 等用法
json_str = json.dumps(all_house,ensure_ascii=False); #all——books 为列表、字典等 python 自带的数据结构,将其写成 json
#print json_str; #[{"brokername": "王东宇"},{},{}]
new_dict = json.loads(json_str);#主要是读 json 文件时,需要用到
#print new_dict; #{u'house_area': u'95', u'build_year': u'2005'}
- json.dumps() 是将一个 Python 数据结构转换为一个 JSON 编码的字符串,
json.loads()是将一个 JSON 编码的字符串(字典形式)转换为一个 Python 数据结构,{u'name': u'xiaoming'}
dumps 转化后键与值都变成了双引号,而在 loads 后变成 python 变量时,元素都变成了单引号,并且字符串前加多了个 u。
一般要求当要字符串通过 loads 转为 python 数据类型时,得外层用单引号,里面元素 key 和 value 用双引号。
- sort_keys:根据 key 排序
dump 与 dumps 的区别
dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, encoding='utf-8', default=None, sort_keys=False, **kw)
;dump 将一个对象序列化存入文件,dump 需要一个类似于文件指针的参数(并不是真的指针,可称之为类文件对象),可以与文件操作结合,也就是说可以将 dict 转成 str 存入文件中,如json.dump(all_house,f,ensure_ascii=False,sort_keys=True, indent=4)
中的f
表示一个数据待写入的 json 文件句柄;dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, encoding='utf-8', default=None, sort_keys=False, **kw)
;而dumps(str)直接给的是 str,也就是直接将字典转成 str,无需写入文件,类似一个数据格式的转换方法,将 python 字符串转成 json 字典。- 所以 dumps 是将 dict 转化成 str 格式,loads 是将 str 转化成 dict 格式。
dump 和 load 也是类似的功能,只是与文件操作结合起来了。
(3)中文存入 txt
f=open('net_saving_data.txt','w',encoding='utf-8');
for item in all_house:
# house_area=item['house_area'];
# price=item['price'];
output='\t'.join([str(item['house_area']),str(item['price']),str(item['build_year']),str(item['house_title'])]);
f.write(output);
f.write('\n');
f.close();
- 在 2.7.15 版本的 python 中,提示错误
TypeError: 'encoding' is an invalid keyword argument for this function
, 无法传入 encoding 的参数,但是在 3.7 版本可传入 encoding='utf-8' 参数,即可对 txt 进行中文写入。
!!NOTE
- 中文写入 txt、json 文件是无非就是open() 文件时,需要添加 utf-8,dump() 时,需要添加 ensure_ascii=False,防止 ascii 编码,但是刚开始因为 python 版本是 2.7.15,不是 3.7,导致存储不成功的时候,一直以为是代码的问题。所以最后发现就是版本的问题,也挺伤的。网上关于中文这个编码问题有很多,但是他们都没有强调 python 版本的问题!!!其他 3.xx 的版本没有试过。
- 读取网页数据的时候,查看网页的 charset,及 chardet 库对编码类型的查询,及时进行 decode 和 encode 的编码转化,应该就能避免很多编码问题了。其他的坑以后踩了再补吧。
感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮。本文欢迎各位转载,但是转载文章之后必须在文章页面中给出作者和原文连接。