文章目录
- 简介
- 用法
- 函数原型
- 源代码
- 其他
- 转义整个字符串
- 参考文献
简介
常用 urllib.parse.urlencode
进行 URL 的 get 请求参数拼接。
import urllib.parse
url = 'http://www.baidu.com/s'
query = {
'wd': 'Python3标准库',
'ie': 'UTF-8'
}
print(url + '?' + urllib.parse.urlencode(query))
# http://www.baidu.com/s?wd=Python3%E6%A0%87%E5%87%86%E5%BA%93&ie=UTF-8
用法
import urllib.parse
query = {} # 空dict
print(urllib.parse.urlencode(query))
query = {'a': 1, 'b': 2} # dict
print(urllib.parse.urlencode(query))
query = (('a', 1), ('b', 2)) # 二元素的tuple序列
print(urllib.parse.urlencode(query))
query = (('a', [1, 2]), ('b', [2, 3])) # 值是序列,且doseq为True,单独转换
print(urllib.parse.urlencode(query, doseq=True))
query = {b'a': b'1', b'b': b'2'} # 字节类型
print(urllib.parse.urlencode(query))
#
# a=1&b=2
# a=1&b=2
# a=1&a=2&b=2&b=3
# a=1&b=2
建议使用 dict
函数原型
def urlencode(query, doseq=False, safe='', encoding=None, errors=None, quote_via=quote_plus)
参数 | 描述 |
query | 查询参数 |
doseq | 序列元素是否单独转换 |
safe | 安全默认值 |
encoding | 编码 |
errors | 错误默认值 |
quote_via | 查询参数的成份是str时,safe, encoding, errors传递给的指定函数 默认为 |
源代码
def quote(string, safe='/', encoding=None, errors=None):
"""quote('abc def') -> 'abc%20def'
URL的每个部分,如路径信息、查询等,若遇到保留关键字必须用引号括起来。
RFC 2396 统一资源标识符(URI)的通用语法列出了以下保留关键字。
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
"$" | ","
每个字段都保留在URL中,但不是所有字符都保留在字段中。(Each of these characters is reserved in some component of a URL, but not necessarily in all of them.)
默认情况下,quote()用于URL的path部分。因此,它不会对'/'进行编码。此字符是保留的,但在典型的用法中,quote函数会在使用现有斜杠字符作为保留字符的path部分上调用。
string和safe可以是str或bytes对象。如果字符串是字节对象,则不能指定encoding和errors。
可选的encoding和errors指定如何处理string。encode方法接受非ASCII字符。默认情况下,encoding='utf-8',errors='strict'(不支持的字符会引发UnicodeEncodeError)。
"""
if isinstance(string, str):
if not string:
return string
if encoding is None:
encoding = 'utf-8'
if errors is None:
errors = 'strict'
string = string.encode(encoding, errors)
else:
if encoding is not None:
raise TypeError("quote() doesn't support 'encoding' for bytes")
if errors is not None:
raise TypeError("quote() doesn't support 'errors' for bytes")
return quote_from_bytes(string, safe)
def quote_plus(string, safe='', encoding=None, errors=None):
"""类似quote(),可以将' '替换为'+'。原始字符串中的加号将进行转义,除非它们包含在safe中。safe没有默认为'/'。
"""
# 检查' '是否在字符串中,字符串可以是str或bytes。如果没有空格,常规的引用会有正确的结果。
if ((isinstance(string, str) and ' ' not in string) or
(isinstance(string, bytes) and b' ' not in string)):
return quote(string, safe, encoding, errors)
if isinstance(safe, str):
space = ' '
else:
space = b' '
string = quote(string, safe + space, encoding, errors)
return string.replace(' ', '+')
def urlencode(query, doseq=False, safe='', encoding=None, errors=None,
quote_via=quote_plus):
"""将一个dict或二元素的tuple编码为一个URL查询字符串。
如果query中所有值都是序列,并且doseq为True,那么每个序列元素都被转换为一个单独的参数
如果query是一个二元素的tuple序列,则输出中参数的顺序将与输入中参数的顺序匹配。
查询参数的成份可以是字符串类型,也可以是字节类型。
当查询参数的成份是str时,safe, encoding, errors传递给指定的函数quote_via。
"""
if hasattr(query, "items"): # 有items属性的话(即dict)直接取出
query = query.items()
else:
# 查询参数为字符串或序列时
try:
# 有内容但序列第一个元素不为tuple时报错
if len(query) and not isinstance(query[0], tuple):
raise TypeError
# 所有类型的零长度序列都将成功到这,小问题。由于最初的实现允许空dict,为保持一致性,保留这种行为
except TypeError:
ty, va, tb = sys.exc_info()
raise TypeError("not a valid non-string sequence "
"or mapping object").with_traceback(tb)
l = []
if not doseq:
for k, v in query:
if isinstance(k, bytes):
k = quote_via(k, safe)
else:
k = quote_via(str(k), safe, encoding, errors)
if isinstance(v, bytes):
v = quote_via(v, safe)
else:
v = quote_via(str(v), safe, encoding, errors)
l.append(k + '=' + v)
else:
for k, v in query:
if isinstance(k, bytes):
k = quote_via(k, safe)
else:
k = quote_via(str(k), safe, encoding, errors)
if isinstance(v, bytes):
v = quote_via(v, safe)
l.append(k + '=' + v)
elif isinstance(v, str):
v = quote_via(v, safe, encoding, errors)
l.append(k + '=' + v)
else:
try:
# Is this a sufficient test for sequence-ness?
x = len(v)
except TypeError:
# not a sequence
v = quote_via(str(v), safe, encoding, errors)
l.append(k + '=' + v)
else:
# loop over the sequence
for elt in v:
if isinstance(elt, bytes):
elt = quote_via(elt, safe)
else:
elt = quote_via(str(elt), safe, encoding, errors)
l.append(k + '=' + elt)
return '&'.join(l)
其他
查询字符串 a=1&a=2
有什么用?服务器会拿最后的值作为a的值。
import tornado.web
import tornado.ioloop
import tornado.httpserver
from tornado.options import define, options, parse_command_line
define("port", default=8888, help="运行端口", type=int)
class TestHandler(tornado.web.RequestHandler):
def get(self):
print(self.get_argument('a'))
if __name__ == "__main__":
parse_command_line()
print("http://localhost:{}/?a=1&a=2".format(options.port))
app = tornado.web.Application(
handlers=[
(r"/", TestHandler),
],
)
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
转义整个字符串
类似 UrlEncode编码/UrlDecode解码 的效果
from urllib.parse import quote_plus
print(quote_plus('https://www.baidu.com/'))
# https%3A%2F%2Fwww.baidu.com%2F
参考文献