python 该如何处理 json 中的中文

2015-02-23 12:10:11 +08:00
 wozhapen

我是一个python小白,最近在模拟微信的web协议,无聊练练,然后碰到中文乱码的问题,看文档问谷歌,弄了一天了也无果,所以请教大家。

相关描述

我借助的是requests来作get、post请求,创建了一个session全程使用,我这次请求返回的是一个json,
当我打印原文(response.text)的时候中文显示如下:


36氪(36Kr.com)是中国领先的科技新媒体,我们报道最新的互联网科技新闻以及最有潜力的互联网创业企业。

进行json解析后(response.json())貌似已经变成unicode编码的ascii,打印的结果中文是这样的:


u'36\xe6\xb0\xaa(36Kr.com)\xe6\x98\xaf\xe4\xb8\xad\xe5\x9b\xbd\xe9\xa2\x86\xe5\x85\x88\xe7\x9a\x84\xe7\xa7\x91\xe6\x8a\x80\xe6\x96\xb0\xe5\xaa\x92\xe4\xbd\x93\xef\xbc\x8c\xe6\x88\x91\xe4\xbb\xac\xe6\x8a\xa5\xe9\x81\x93\xe6\x9c\x80\xe6\x96\xb0\xe7\x9a\x84\xe4\xba\x92\xe8\x81\x94\xe7\xbd\x91\xe7\xa7\x91\xe6\x8a\x80\xe6\x96\xb0\xe9\x97\xbb\xe4\xbb\xa5\xe5\x8f\x8a\xe6\x9c\x80\xe6\x9c\x89\xe6\xbd\x9c\xe5\x8a\x9b\xe7\x9a\x84\xe4\xba\x92\xe8\x81\x94\xe7\xbd\x91\xe5\x88\x9b\xe4\xb8\x9a\xe4\xbc\x81\xe4\xb8\x9a\xe3\x80\x82'

json解析后是一个dict,当我单独打印键值的时候中文显示是:


36氪(36Kr.com)是中国领先的科技新媒体,我们报道最新的互联网科技新闻以及最有潜力的互联网创业企业。

问题来了

{'connection': 'close', 'content-type': 'text/plain', 'content-length': '14315', 'content-encoding': 'deflate'}


为了解决这个问题,我特地看了微信的web前端js关于那一段的请求处理,表示水平有限没发现什么。

请大家帮忙解释一下上述原因,或者给个处理中文的思路!!

14869 次点击
所在节点    Python
38 条回复
lincanbin
2015-02-23 12:14:39 +08:00
print userinfo['NickName'].encode('iso8859-1')

用PHP之类的语言的话就不需要考虑编码问题,人生苦短,不要用Python。
fish267
2015-02-23 12:18:46 +08:00
方法一: python3 解除编码烦恼。
方法二:
def unicode_init(obj, encoding = 'utf-8'):
if isinstance(obj, basestring):
if not isinstance(obj, unicode):
obj = unicode(obj, encodeing)
return obj
zwzmzd
2015-02-23 12:24:02 +08:00
dict里面的中文用unicode形式存储,传输之前用json.dumps导出标准json,各个套件跟着规范走不会有问题
wozhapen
2015-02-23 12:28:49 +08:00
@lincanbin 可行。。谢谢。。
哈哈,春节用python练手。。
funagi
2015-02-23 12:32:52 +08:00
试试
```
response = session.get('http://xxxx')
print(response.encoding)
response.encoding = 'utf-8'
print(response.json())
```
wozhapen
2015-02-23 12:33:12 +08:00
@fish267 好的,我尝试python3,
方法二昨天已试过不行。。
wozhapen
2015-02-23 12:34:57 +08:00
@zwzmzd 我是从微信那边获取的数据,很显然我无法事先处理。。仍然谢谢你。。
wozhapen
2015-02-23 12:39:41 +08:00
@funagi 太棒了!!可行。。
Sylv
2015-02-23 13:00:29 +08:00
这种情况是因为数据源的编码声明不规范,导致 reuqests 无法判断出返回数据的正确编码,从而使用了它的默认编码 iso8859-1 来将数据转换为 unicode,没使用正确的编码 utf-8,于是就出现乱码了。
解决办法一就是手动设置返回数据的正确编码:response.encoding = 'utf-8'。这样结果就是正确的 unicode 类型字符串。
或者将错误的 unicode 用同样的 iso8859-1 编码转换回去原本的 utf-8 编码的 str 类型字符串:data.encode('iso8859-1')。
a2z
2015-02-23 13:02:30 +08:00
前几天刚入这个坑:
Python内部数据结构标准内码是unicode
json.loads, json.dumps之类的只能接受unicode字符串,有些没有特殊字符的utf8之类可以侥幸通过
requests.text会自动把网页解码unicode,输入到json模块的时候不用.encode(),那样画蛇添足

你显示,保存的时候再用encode转换成其他格式比如utf8
billlee
2015-02-23 13:13:26 +08:00
```python
data_ugly = response.json()
Signature = data_ugly['Signature'].encode('iso8859-1').decode('utf-8')`
```

估计换 python 3 是没用的,可以查查响应头的 Content-Type 里的 charset 是不是 utf-8. 如果不是,那就是你访问的网站没有处理好编码问题;如果是,那就是 requests 对编码的处理 有问题。
popbones
2015-02-23 13:31:49 +08:00
学python必经之路
wozhapen
2015-02-23 13:37:18 +08:00
@Sylv 谢谢。
wozhapen
2015-02-23 13:42:15 +08:00
@a2z 你的解释可能是对的,但是我有试过打印的时候encode('utf-8'),不行的。。
wozhapen
2015-02-23 13:52:39 +08:00
@billlee 恩恩,你的解决方式跟一楼类似。
碰到这个问题,我第一时间就是看头部,我在描述里也贴出了是'content-type': 'text/plain',编码未知,然后我就不知道该怎么处理了。。
codegear
2015-02-23 14:30:11 +08:00
Python中实际上有两种字符串,分别是str类型和unicode类型,这两者都是basestring的派生类。str实际上相当于string, 而unicode则是标准的字符串,相当于wstring。
其中I/O读入的基本都是str类型,也就是说Python不关心这些字节代表什么含义。但是如果需要做真正的字符串操作的时候,建议使用unicode类型,这样确保不存在编码问题。
JSON理论上应该可用ASCII完全表示,其中的宽字符用类似\u1111的形式表达。但是现在有很多不规范的JSON出现,例如s="""{"标题": "Hello, world"}"""。此时就需要你自己确定这部分内容用字节表达时,究竟用了什么编码,如果是UTF-8,那么就首先s_u = s.decode("UTF-8")变成unicode字符串。

另一方面,只要保证这段字符串的编码和Python运行时环境的编码保持一致,也是可以直接loads(str类型变量)的。例如Linux下如果LANG是UTF-8,那么python屁颠屁颠跑着的时候就可以直接把UTF-8编码的JSON串塞进去。
codegear
2015-02-23 14:31:29 +08:00
貌似偏题了,sorry,请无视
jas0ndyq
2015-02-23 15:11:48 +08:00
python编码着实坑
mhycy
2015-02-23 18:16:35 +08:00
不要尝试在交互式解析器或者命行环境中直接输出文本,一个比一个坑
最可靠的做法是把文本保存成一个文件然后再查看。

如果进行比较,先把输入的字节码转成UTF8(解析成UTF8)字符串,然后再进行对比
wozhapen
2015-02-23 20:31:53 +08:00
@mhycy 谢谢指导,我昨天试过保存在文本中也是乱码。

我试过把如下unicode编码的字节码
```
u'36\xe6\xb0\xaa(36Kr.com)\xe6\x98\xaf\xe4\xb8\xad\xe5\x9b\xbd\xe9\xa2\x86\xe5\x85\x88\xe7\x9a\x84\xe7\xa7\x91\xe6\x8a\x80\xe6\x96\xb0\xe5\xaa\x92\xe4\xbd\x93\xef\xbc\x8c\xe6\x88\x91\xe4\xbb\xac\xe6\x8a\xa5\xe9\x81\x93\xe6\x9c\x80\xe6\x96\xb0\xe7\x9a\x84\xe4\xba\x92\xe8\x81\x94\xe7\xbd\x91\xe7\xa7\x91\xe6\x8a\x80\xe6\x96\xb0\xe9\x97\xbb\xe4\xbb\xa5\xe5\x8f\x8a\xe6\x9c\x80\xe6\x9c\x89\xe6\xbd\x9c\xe5\x8a\x9b\xe7\x9a\x84\xe4\xba\x92\xe8\x81\x94\xe7\xbd\x91\xe5\x88\x9b\xe4\xb8\x9a\xe4\xbc\x81\xe4\xb8\x9a\xe3\x80\x82'
```
转成utf-8得到如下不想要的结果(貌似是简单的把单字节加上‘\xc2’变成双字节)
```
'36\xc3\xa6\xc2\xb0\xc2\xaa(36Kr.com)\xc3\xa6\xc2\x98\xc2\xaf\xc3\xa4\xc2\xb8\xc2\xad\xc3\xa5\xc2\x9b\xc2\xbd\xc3\xa9\xc2\xa2\xc2\x86\xc3\xa5\xc2\x85\xc2\x88\xc3\xa7\xc2\x9a\xc2\x84\xc3\xa7\xc2\xa7\xc2\x91\xc3\xa6\xc2\x8a\xc2\x80\xc3\xa6\xc2\x96\xc2\xb0\xc3\xa5\xc2\xaa\xc2\x92\xc3\xa4\xc2\xbd\xc2\x93\xc3\xaf\xc2\xbc\xc2\x8c\xc3\xa6\xc2\x88\xc2\x91\xc3\xa4\xc2\xbb\xc2\xac\xc3\xa6\xc2\x8a\xc2\xa5\xc3\xa9\xc2\x81\xc2\x93\xc3\xa6\xc2\x9c\xc2\x80\xc3\xa6\xc2\x96\xc2\xb0\xc3\xa7\xc2\x9a\xc2\x84\xc3\xa4\xc2\xba\xc2\x92\xc3\xa8\xc2\x81\xc2\x94\xc3\xa7\xc2\xbd\xc2\x91\xc3\xa7\xc2\xa7\xc2\x91\xc3\xa6\xc2\x8a\xc2\x80\xc3\xa6\xc2\x96\xc2\xb0\xc3\xa9\xc2\x97\xc2\xbb\xc3\xa4\xc2\xbb\xc2\xa5\xc3\xa5\xc2\x8f\xc2\x8a\xc3\xa6\xc2\x9c\xc2\x80\xc3\xa6\xc2\x9c\xc2\x89\xc3\xa6\xc2\xbd\xc2\x9c\xc3\xa5\xc2\x8a\xc2\x9b\xc3\xa7\xc2\x9a\xc2\x84\xc3\xa4\xc2\xba\xc2\x92\xc3\xa8\xc2\x81\xc2\x94\xc3\xa7\xc2\xbd\xc2\x91\xc3\xa5\xc2\x88\xc2\x9b\xc3\xa4\xc2\xb8\xc2\x9a\xc3\xa4\xc2\xbc\xc2\x81\xc3\xa4\xc2\xb8\xc2\x9a\xc3\xa3\xc2\x80\xc2\x82'
```
********
当然,对于与已知字符串比较的话,实际上可以构造出已知字符串的unicode编码的字节码,然后进行比较,其实我想知道的是更人性化的比较方式。
谢谢你的回答。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/172276

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX