Python 系列学习二十:urllib 库之 urlencode 和 quote 操作

前言

打算写一系列文章来记录自己学习 Python 3 的点滴;

本篇文章主要介绍利用 python 库 urllib 来对 URL 进行 urlencode、quote 等操作;

背景

通常,我们在做 POST 请求的时候,需要使用 x-www-form-urlencoded 的协议进行数据提交,那么该协议对应的标准是什么呢?数据格式如何呢?

假设,我们需要提交如下的 form data,

1
2
3
'spam': 1, 
'eggs': 2,
'bacon': 0

那么 x-www-form-urlencoded 协议要求,必须将上面的参数进行如下的转换,

  1. 将 key-value 参数转换成参数类型,如下

    1
    spam=1&eggs=2&bacon=0
  2. 将敏感字符进行转义(escape),常见的需要被转义的字符有 “、&、{ … 字符,上面的例子进行转义过后,输出如下,

    1
    spam=1%26eggs=2%26bacon=0

    最后,将转义后的内容作为 payload 放入 request boy 中进行 submit

最后,将转换过后的内容放入 request body 中进行 form submit,这就是 x-www-form-urlencoded 协议;

工具

那么要怎样能够达到上面的目的呢,那么可以使用 urllib.urlencode 和 urllib.quote 方法来写祝我们;

urlencode

通常,form data 参数会以 json 的方式组织,比如,

1
2
3
4
5
{
'spam': 1,
'eggs': 2,
'bacon': 0
}

那么,要满足 x-www-form-urlencoded 协议的要求,我们首先需要将其转换为参数类型的方式,这样,urlencode 可以非常方便的帮我们完成,

1
2
params = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
print(params)

得到结果如下,

1
spam=1&eggs=2&bacon=0

总结,urlencode 方法就是将 json 转换成参数化格式的字符串,以满足 x-www-form-urlencoded 的要求;

quote

quote 方法的目的就是将敏感字符使用%xx的方式对其进行转义,这个过程称作 escape;要注意的是,默认情况下,字母数字和特殊字符_.-将不会进行转义;

下面,我们来对 urlencode 转义后的结果进行 quote 操作,

1
2
params = urllib.parse.quote('spam=1&eggs=2&bacon=0')
print(params)

输出结果,

1
spam%3D1%26eggs%3D2%26bacon%3D0

咦!哪里不对,对的,=号去哪了呢?上面的格式不是参数化的格式,这里我们需要使用safe参数来指定哪些敏感字符不应该转义,所以,上面的代码应该改成如下,

1
2
params = urllib.parse.quote('spam=1&eggs=2&bacon=0', safe='=')
print(params)

输出结果,

1
spam=1%26eggs=2%26bacon=0

那么,就可以将 quote 以后的参数,作为 payload 放入 request body 中以 x-www-form-urlencoded 协议的格式要求进行 submit 了;

例子

1
2
3
4
5
6
params = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
logger.debug(params)
params_1 = urllib.parse.quote(params)
logger.debug('%s and de-quote: %s', params_1, urllib.parse.unquote(params_1))
params_2 = urllib.parse.quote(params, safe='=')
logger.debug('%s and de-quote: %s', params_2, urllib.parse.unquote(params_2))

输出,

1
2
3
2018-05-22 16:13:28,980 DEBUG [root] <downloader_test.py, test_quote_and_urlencode, 0424>: spam=1&eggs=2&bacon=0
2018-05-22 16:13:28,981 DEBUG [root] <downloader_test.py, test_quote_and_urlencode, 0426>: spam%3D1%26eggs%3D2%26bacon%3D0 and de-quote: spam=1&eggs=2&bacon=0
2018-05-22 16:13:28,981 DEBUG [root] <downloader_test.py, test_quote_and_urlencode, 0428>: spam=1%26eggs=2%26bacon=0 and de-quote: spam=1&eggs=2&bacon=0

Reference

https://docs.python.org/3/library/urllib.parse.html