37

[译] urllib.parse 文档:这里有关于 URL 的一切

 3 years ago
source link: https://mp.weixin.qq.com/s/clStQz395nkwTys0ccCl5Q
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

MVFjY3e.gif

本模块定义了一个标准接口,既可以把 统一资源定位符 (URL)解析为若干部分(通信协议,网络地址和路径等),也可以把各个部分重新组合成URL,还可以利用“基本URL”把相对路径转化为绝对路径。

本模块设计之初就考虑到要兼容一系列和URL相关的RFC标准。目前能够支持的URL协议包括: file, ftp, gopher, hdl,http, https, imap, mailto, mms, nntp, prospero, rsync, rtsp, rtspu, sftp, shttp, sip, sips, snews, svn, svn+ssh, telnet, wais, ws, wss

urllib.parse定义的函数主要分为两类: URL解析和URL转义 。下面详细介绍一下本模块的细节。

1

URL 解析

URL解析函数聚焦于将URL分割为若干部分,以及将各个部分拼接为URL。

urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)

本函数将URL解析为6个部分,返回一个包含6个元素的 named tuple 。这么处理符合URL的通用结构:

scheme://netloc/path;parameters?query#fragment

每个元组的元素都是一个字符串(也有可能为空字符串)。这些结构并不会再进行更细致的划分(例如网络地址整个作为一个字符串),并且不会还原%的转义。除了path开头的斜杠,各个部分之间的分割符号并不会在解析结果中出现。举例来说:

>>> from urllib.parse import urlparse

>>> o = urlparse('http://www.cwi.nl:80/%7Eguido/Python.html')

>>> o

ParseResult(scheme='http', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html',

params='', query='', fragment='')

>>> o.scheme

'http'

>>> o.port

80

>>> o.geturl()

'http://www.cwi.nl:80/%7Eguido/Python.html'

根据  RFC1808  定义的语法规则,urlparse模块仅能识别以‘//’开头的网络地址。其他的输入均会被当作相对URL从而解析为路径部分。

>>> from urllib.parse import urlparse

>>> urlparse('//www.cwi.nl:80/%7Eguido/Python.html')

ParseResult(scheme='', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html',

params='', query='', fragment='')

>>> urlparse('www.cwi.nl/%7Eguido/Python.html')

ParseResult(scheme='', netloc='', path='www.cwi.nl/%7Eguido/Python.html',

params='', query='', fragment='')

>>> urlparse('help/Python.html')

ParseResult(scheme='', netloc='', path='help/Python.html', params='',

query='', fragment='')

通过  scheme  参数传入的地址协议仅会在URL不包含网络协议的时候才会用到。除了缺省的空字符(特殊情况下可以自动转化为b'')之外,该入参应该同urlstring保持类型一致(文本或者字节)。

如果  allow_fragments  入参为false,返回结果中的fragment部分将不会有具体值,而是 仅返回一个空字符串 。URL中的该部分会被解析为path或者query的一部分。

以named tuple形式出现的返回值,既可以通过索引读取,也可以通过别名读取。

属性

索引

值(如果不存在)

scheme

0

URL方案说明符

scheme parameter

netloc

1

网络位置部分

空字符串

path

2

分层路径

空字符串

params

3

最后路径元素的参数

空字符串

query

4

查询组件

空字符串

fragment

5

片段识别

空字符串

username

用户名

None

password

密码

None

hostname

主机名(小写)

None

port

端口号为整数(如果存在)

None


如果URL中出现了非法的端口地址,在读取获取解析结果中的port值时会抛出ValueError。稍后会有更多详细的说明。

如果netloc部分的方括号不匹配也会抛出ValueError。

如果netloc在NFKC规范(使用IDNA编码)中包含/, ?, #, @或者:,将会抛出ValueError异常。但是如果显式的这样传入这种值来拼装URL,不需要解析的情况下,不会抛异常。

作为named tuple的子类,解析结果中的某些特有方法和属性可能有特殊用途。举个例子,_replace()将会返回另一个替换指定部分之后的解析结果。

>>> from urllib.parse import urlparse
>>> u = urlparse('//www.cwi.nl:80/%7Eguido/Python.html')
>>> u
ParseResult(scheme='', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html',
            params='', query='', fragment='')
>>> u._replace(scheme='http')
ParseResult(scheme='http',    netloc='www.cwi.nl:80', path='/%7Eguido/ Python.html',
            params='', query='', fragment='')

urllib.parse.parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None)

该函数用于解析application/x-www-form-urlencoded类型的query字符串。返回值为字典类型,其中字典的key是唯一的,字典的value是list类型。

keep_blank_values 用于决定通过%转义的空格是否当作空字符串处理。当入参值为true的时候,保留作为空字符串。缺省值为false,此时空格会被忽略,当作不存在。

strict_parsing用于决定如何处理解析错误。缺省状态下为false,此时将会忽略异常。如果置为true,遇到错误会抛出ValueError异常。

encoding和errors的含义和bytes.decode()类似,用于决定如何将含有%的转义字符解析为Unicode字符。

max_num_fields用于决定最多可以读取多少字段。设置之后,如果发现多于设置的值,将会抛出ValueError异常。

使用urllib.parse.urlencode()函数(入参doseq设置为True)可以将结果再次转换为query字符串。

urllib.parse.parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None)

该函数用于解析application/x-www-form-urlencoded类型的字符串数据。返回值为name,value组合的list(同parse_qs的区别在于返回值类型)。

keep_blank_values   用于决定通过%转义的空格是否当作空字符串处理。当入参值为true的时候,保留作为空字符串。缺省值为false,此时空格会被忽略,当作不存在。

strict_parsing用于决定如何处理解析错误。缺省状态下为false,此时将会忽略异常。如果置为true,遇到错误会抛出ValueError异常。

encoding和errors的含义和bytes.decode()类似,用于决定如何将含有%的转义字符解析为Unicode字符。

max_num_fields 用于决定最多可以读取多少字段。设置之后,如果发现多于设置的值,将会抛出ValueError异常。

使用urllib.parse.urlencode()函数可以将结果再次转换为query字符串。

urllib.parse.urlunparse(parts)

将urlparse()返回的tuple重新组合成一个URL。parts参数接受任何包含6个元素的可迭代对象。返回结果同原始URL相比可能会有细微差别,但是保证含义是一致的,尤其是在原始URL包含非必需的分隔符时(举例来说,RFC明确指出“?”是有效的query字符串)。

urllib.parse.urlsplit(urlstring, scheme='', allow_fragments=True)

和urlparse()有些类似,区别在于本函数不会分割URL中的params部分。如果你觉得params是path的一部分(参考RFC 2396),此时应该使用本函数,而不是urlparse()。本函数的设计初衷为了能够单独处理path和params。函数的返回值为包含5个元素的named tuple:

(addressing scheme, network location, path, query, fragment identifier)

返回值是named tuple类型,既可以通过索引读取,也可以通过别名读取:

别名 索引 值 缺省值 scheme 0 URL的网络协议 协议规范 netloc 1 网络地址 空字符串 path 2 地址路径 空字符串 query 3 查询参数 空字符串 fragment 4 片段参数 空字符串 username 5 用户名 None password 密码 None hostname 主机地址(小写) None port 存在的情况下为整数端口 None

如果URL中出现了非法的端口地址,在读取获取解析结果中的port值时会抛出ValueError。更多的说明可以翻阅 **解析结果的构成**

如果netloc部分的方括号不匹配也会抛出ValueError。

如果netloc在NFKC规范(使用IDNA编码)中包含/, ?, #, @或者:,将会抛出ValueError异常。但是如果显式的这样传入URL的各个部分,不需要解析的情况下,不会抛异常。    如果netloc部分的方括号不匹配也会抛出ValueError。      如果URL中出现了非法的端口地址,在读取获取解析结果中的port值时会抛出ValueError。更多的说明可以翻阅解析结果的构成。

urllib.parse.urlunsplit(parts)

将urlsplite()返回的tuple重新组合成一个URL。parts参数接受任何包含5个元素的可迭代对象。返回结果同原始URL相比可能会有细微差别,但是保证含义是一致的,尤其是在原始URL包含非必需的分隔符时(举例来说,RFC明确说明“?”是有效的query字符串)。

urllib.parse.urljoin(base, url, allow_fragments=True)

将基地址和url组合成一个绝对URL。需要注意的是,本函数会使用scheme, netloc以及(部分的)path,来补全相对URL中缺失的部分。举个例子:

>>> from urllib.parse import urljoin

>>> urljoin('http://www.cwi.nl/%7Eguido/Python.html', 'FAQ.html')

'http://www.cwi.nl/%7Eguido/FAQ.html

入参allow_fragments的含义同urlparse()一致。

注意: 即使url是一个绝对URL(以//或者scheme://开头),url中的host以及scheme也会被替换。举个例子:

>>> urljoin('http://www.cwi.nl/%7Eguido/Python.html',

'//www.python.org/%7Eguido')

'http://www.python.org/%7Eguido'

如果你不希望这样处理,可以使用urlsplit()以及urlunsplit()预先处理url,去掉scheme和netloc部分。

urllib.parse.urldefrag(url)

如果url中包含fragment,本函数将会返回一个不带有fragment的url,以及截取的fragment。如果url中不包含fragment,本函数将返回原始url和一个空字符串。

返回值是一个named tuple类型,既可以通过索引读取,也可以通过别名读取:

别名 索引 值 缺省值 url 0 不含fragment的url 空字符串 fragment 1 片段参数 空字符串

更多的说明可以翻阅解析结果的构成

urllib.parse.unwrap(url)

本函数用于从一个被包裹的URL(形如<URL:scheme://host/path>,<scheme://host/path>, URL:scheme://host/path or scheme://host/path)中摘取出实际URL。如果url没有被包裹,则返回原始值。

解析ASCII编码

URL解析函数设计之初是仅仅是为了处理字符类型。在实践中,往往需要处理ASCII编码和转义的URL。因此,本模块的URL解析函数都可以处理bytes,bytearray以及str类型的对象。

如果入参是str类型,返回值也会是str。如果入参是bytes或者bytearray,结果就会只有bytes数据。

如果试图在一个函数里面混合使用字符串和字节类型会抛出TypeError异常,如果试图使用不是ASCII类型的字节会抛出UnicodeDecodeError异常。

为了方便的将结果在字符串和字节之间转换,所有的URL解析函数的返回值要么带有encode()方法(字符串类型的返回值),要么带有decode() 方法(字节类型的返回值)。这些函数的使用方式和str(), bytes() 一样( 唯一的细微区别 在于默认的编码形式是‘ascii’,而不是‘utf-8’)。encode() 方法返回bytes类型,decode() 方法返回str类型。

如果调用方期望处理没有正确转义的URL(可能含有非ASCII字符),需要在调用URL解析函数之前自己将字节类型转化为字符。

上述文档介绍的细节仅适用于URL解析函数。URL转义函数在处理字节时有自己的一套规则,感兴趣的可以参考URL转义函数的文档。

解析结果的数据结构

urlparse(), urlsplit() 以及urldefrag() 函数的返回对象都是tuple的子类。这些子类独有的一些特性在介绍函数的时候提到过了,例如上一部分刚刚介绍过的编码和解码都是作为附加的方法出现的,另外还有解析结构还有一些方法如下:

urllib.parse.SplitResult.geturl()

该方法返回重新组合的url字符串,它和原始url的区别在于,它会将scheme转为小写,并去掉原来为空的一些部分:空parameter、空query以及空fragment。

对于urldefrag()函数而言,只会去掉空的fragment。对于urlsplit()和urlparse(),上面提到的差别都会生效。

多次将本函数的返回值传入解析函数,得到的结果将不会有任何变化。

>>> from urllib.parse import urlsplit

>>> url = 'HTTP://www.Python.org/doc/#'

>>> r1 = 1urlsplit(url)

>>> r1.geturl()

'http://www.Python.org/doc/'

>>> r2 = urlsplit(r1.geturl())

>>> r2.geturl()

'http://www.Python.org/doc/'

以str类型的处理为例,下面介绍几个解析结构的具体实现:

class urllib.parse.DefragResult(url, fragment)

urldefrag()返回结果的具体实现,结果包含str类型的数据。其encode()方法会返回一个DefrageResultBytes实例。

class urllib.parse.ParseResult(scheme, netloc, path, params, query, fragment)

urlparse()返回结果的具体实现,结果包含str类型的数据。其encode()方法会返回一个 ParseResultBytes 实例。

class urllib.parse.SplitResult(scheme, netloc, path, query, fragment)

urlsplit()返回结果的具体实现,结果包含str类型的数据。其encode()方法会返回一个 SplitResultBytes实例。

以bytes类型的处理为例,下面介绍几个解析结构的具体实现:

class urllib.parse.DefragResultBytes(url, fragment)

urldefrag()返回结果的具体实现,结果包含str类型的数据。其decode()方法会返回一个DefragResult实例。

class urllib.parse.ParseResultBytes(scheme, netloc, path, params, query, fragment)

urlparse()返回结果的具体实现,结果包含str类型的数据。其decode()方法会返回一个ParseResult实例。

class urllib.parse.SplitResultBytes(scheme, netloc, path, query, fragment)

urlsplit()返回结果的具体实现,结果包含str类型的数据。其decode()方法会返回一个 SplitResult实例。

2

URL转义

URL转义函数是为了使得编程数据能够安全的使用,主要分为转义特殊字符和编码非ASCII字符两个部分,另外还有对应的逆向操作。

urllib.parse.quote(string, safe='/', encoding=None, errors=None)

以%xx的形式转义特殊字符,但是字母、数字以及   _ . - ~  这几个字符是不会被转义的。默认情况下,该函数是为了转义URL中的path部分。当然,可以通过safe参数,明确指定哪些ASCII字符不希望被转义,其缺省值为"/"。

string入参既可以是str类型,也可以是bytes类型。

encoding和errors的含义和str.encode()类似,用于决定如何处理非ASCII字符。encoding缺省值为‘utf-8’。errors缺省值为‘strict’,即严格模式——如果遇到不支持的字符将会抛出UnicodeEncodeError异常。如果string入参为bytes类型,那么encoding和errors入参将不能够支持自定义,否则会抛出TypeError异常。

需要指出的是,quote(string, safe, encoding, errors)和quotefrombytes(string.encode(encoding, errors), safe)含义是一致的。

示例:quote('/El Niño/')会返回'/El%20Ni%C3%B1o/'。

urllib.parse.quote_plus(string, safe='', encoding=None, errors=None)

本函数和quote()类似,区别在于会用加号来转义空格,这么做主要是因为通常需要将query部分附加到URL上的时候需要转义HTML数据。除非通过safe参数明确指出加号不需要转义,否则该函数会自动转义加号。另外,safe入参的缺省值去掉了‘/’。

示例:quote_plus('/El Niño/') 会返回 '%2FEl+Ni%C3%B1o%2F'

urllib.parse.quote_from_byte(bytes, safe='/')

本函数和quote()类似,但是仅接受bytes类型的入参,不接受str类型,并且不支持string到bytes的转码。

示例:quotefrombytes(b'a&\xef') 会返回 'a%26%EF'

urllib.parse.unquote(string, encoding='utf-8', errors='replace')

本函数可以将%xx形式的转义字符还原为单个字符。encoding和errors的含义和bytes.decode()类似,用于决定如何将百分号的转义字符还原为Unicode字符。

string入参必须为str类型。

encoding缺省值为‘utf-8’。errors缺省值为‘replace’,意味着无效的内容会被占位符替代。

示例:unquote('/El%20Ni%C3%B1o/') 会返回 '/El Niño/'

urllib.parse.unquote_plus(string, encoding='utf-8', errors='replace')

本函数和unquote()类似,区别在于还原HTML内容的时候会使用空格替换加号。

string入参必须为str类型。

示例:unquote_plus('/El+Ni%C3%B1o/') 会返回 '/El Niño/'

urllib.parse.unquote_to_bytes(string)

本函数会将%xx形式的转义字符还原,返回值为bytes类型。

string入参既可以是str类型,也可以是bytes类型。如果是str类型,非ASCII字符会被还原为UTF-8的字节序。

示例:unquotetobytes('a%26%EF') 会返回 b'a&\xef'

urllib.parse.urlencode(query, doseq=False, safe='', encoding=None, errors=None, quote via=quote plus)

本函数可以将映射对象或者两元素类型的tuple(其具体值既可以是str,也可以是bytes),转义为ASCII类型的文本。如果期望将返回值用于urlopen()来传递POST数据,需要先将结果转为bytes类型,否则会抛出TypeError异常。

返回值是串通过&符号连接的key=value组合,其中无论是key还是value都已通过入参quotevia转义。和标准的GET请求(application/x-www-form-urlencoded)兼容,默认情况下,转义时使用的是quoteplus()函数,这就意味着空格会被转义为加号、‘/‘会被转义为%2F。另一个可以用于quote_via的转义函数是quote(),此时会将空格转义为%20,并保留‘/’不转义。如果想要更好的控制转义规则,建议使用quote函数,并显式的知名safe入参。

当入参query为两元素类型的tuple时,每个tuple成员里面的第一个元素会被当作key,第二个元素会被当作value。其中value元素可以有多个,此时如果doseq入参为True,该函数会迭代value,生成多个key=value的组合,将这些组合通过&分割符全部添加到返回值里面。最终的返回值里面的参数顺序同tuple顺序保持一致。

safe、encoding以及errors入参都将透传给quote_via(当然,只有query入参为str类型,encoding和errors才会真正向下透传)。

parseqs()和parseqsl()可以逆向本函数的编码过程,将一个query字符串转换为Python的数据结构。

---------- ------------------------------------------------------

相关文档:

RFC 3986-统一资源标识符: 该标准为当前在用的标准。任何urllib.parse模块的变动都需要参考该标准。某些同标准不一致的地方主要是为了向后兼容,并和浏览器的实际实现保持一致。

RFC 2732-URL中的IPV6地址格式 该标准具体说明了如何解析带有IPV6的URL

RFC 2396-统一资源标识符--通用格式: 该标准介绍了统一资源名(URN)和统一资源定位符(URL)的通用格式。

RFC 2367-mailto的URL协议: 该标准解释了mailto的URL协议

RFC 1808-相对URL: 该标准包含如何将拼接绝对URL和相对URL的详细说明,以及一系列的错误示例来展示如何处理边界值。

RFC 1738-统一资源定位符(URL): 该文档介绍了URL的格式及其含义。

UF3m2qq.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK