`
xuanzhui
  • 浏览: 197031 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

用quote_plus和urlencode做url编码

阅读更多

1.

py2需要

import urllib

 

 py3需要

import urllib.parse

 

以下不特殊说明显示的都是py3的结果,编码之后的字符串可以到一些站长网站去解码校验

2.

quote_plus用于对字符串编码

>>> quote_plus('中文')
'%E4%B8%AD%E6%96%87'

 

可适用场景,get方式的请求参数需要传入urlencoded json字符串

>>> d = {'a':'a','b':u'b'}
>>> d
{'a': 'a', 'b': 'b'}
>>> dstr = json.dumps(d)
>>> dstr
'{"a": "a", "b": "b"}'
>>> quote_plus(dstr)
'%7B%22a%22%3A+%22a%22%2C+%22b%22%3A+%22b%22%7D'

最后得到的dstr就是可以串联到请求url后面的字符串,

此处用json.dumps(),而不用str(),是因为json.dumps会将单引号转化成json标准的双引号,同时对于py2,如果出现了u'a'这样的unicode字符串,也会自动去除前缀u。

 

其实此处quote的作用就是对 { " }和空格之类的做编码,所以对于中文,json.dumps()会处理成类似\u4e2d 这样的字符串,再进行quote也只是%5Cu4e2d,因为 \ 对应的编码是 %5C,至于这样编码的字符串可不可以处理可能还得看服务端。

 

>>> zw = {'zw':'中文'}
>>> json.dumps(zw)
'{"zw": "\\u4e2d\\u6587"}'
>>> quote_plus(json.dumps(zw))
'%7B%22zw%22%3A+%22%5Cu4e2d%5Cu6587%22%7D'

 

如果需要统一成UTF-8的格式,py3其实是很容易的

>>> d
{'a': 'a', 'b': '中文'}
>>> quote_plus(str(d).replace("'", '"'))
'%7B%22a%22%3A+%22a%22%2C+%22b%22%3A+%22%E4%B8%AD%E6%96%87%22%7D'

 

但是并不适用于py2,以下直接给出兼容的function(只考虑dict value可能是中文的情况,并且统一unicode编码)

def dict_to_quote_str(dict_param):
	# encode出来的字符串是\xe3d4这样的,所以再quote
	tmp_dict = {k: quote_plus(v.encode('utf-8')) for (k, v) in d.items()}
	tmp_str = json.dumps(tmp_dict)
	if sys.version_info[0] == 3:
		return urllib.parse.quote_plus(tmp_str, safe='/%')
	else:
		return urllib.quote_plus(tmp_str, safe='/%')
    

  

分步试验过程

>>> d
{'a': 'a', 'b': '中文'}
>>> tmp_dict = {k: v.encode('utf-8') for (k, v) in d.items()}
>>> tmp_dict
{'a': b'a', 'b': b'\xe4\xb8\xad\xe6\x96\x87'}
>>> tmp_dict = {k: quote_plus(v.encode('utf-8')) for (k, v) in d.items()}
>>> tmp_dict
{'a': 'a', 'b': '%E4%B8%AD%E6%96%87'}
>>> jstr = json.dumps(tmp_dict)
>>> jstr
'{"a": "a", "b": "%E4%B8%AD%E6%96%87"}'
>>> quote_plus(jstr, safe='/%')
'%7B%22a%22%3A+%22a%22%2C+%22b%22%3A+%22%E4%B8%AD%E6%96%87%22%7D'

 

3.

urlencode可以将dict转成k1=v1&k2=v2这样的字符串

>>> d
{'a': 'a', 'b': '中文'}
>>> urlencode(d)
'a=a&b=%E4%B8%AD%E6%96%87'

 

 但是到了py2继续歇菜,表现在两点:

1)如果是使用unicode定义dict的value,urlencode无法解析,出现UnicodeEncodeError

2)如果直接像py3那样定义dict的value,urlencode的结果就跟系统有关了,Windows里面得到的就是gbk编码的

 (以下为py2运行环境)

 首先考虑第一种情况

>>> d={'a': 'a', 'b': u'中文'}
>>> d
{'a': 'a', 'b': u'\u4e2d\u6587'}
>>> urlencode({k:v.encode('utf-8') for k,v in d.items()})
'a=a&b=%E4%B8%AD%E6%96%87'

 对于第二种情况

>>> d={'a': 'a', 'b': '中文'}
>>> d
{'a': 'a', 'b': '\xd6\xd0\xce\xc4'}
>>> dd={k:v.decode('gbk') for k,v in d.items()}
>>> dd
{'a': u'a', 'b': u'\u4e2d\u6587'}
>>> urlencode({k:v.decode('gbk').encode('utf-8') for k,v in d.items()})
'a=a&b=%E4%B8%AD%E6%96%87'

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics