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 编码即为 0000000001000001; 但英文字母其实只用一个字节就够了, 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 编码的字符串,
{"name": "xiaoming"}
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 的编码转化, 应该就能避免很多编码问题了. 其他的坑以后踩了再补吧.
来源: https://www.cnblogs.com/mingjiatang/p/9527345.html