urllib.parse — 将 URL 解析为组件

源代码: Lib/urllib/parse.py


此模块定义了一个标准接口,用于将统一资源定位符 (URL) 字符串分解为组件(寻址方案、网络位置、路径等),将组件组合回 URL 字符串,以及将“相对 URL”转换为给定“基本 URL”的绝对 URL。

该模块的设计符合关于相对统一资源定位符的互联网 RFC。它支持以下 URL 方案:fileftpgopherhdlhttphttpsimapmailtommsnewsnntpprosperorsyncrtsprtspsrtspusftpshttpsipsipssnewssvnsvn+sshtelnetwaiswswss

urllib.parse 模块定义的函数分为两大类:URL 解析和 URL 编码。以下部分将详细介绍这些内容。

此模块的函数使用已弃用的术语 netloc(或 net_loc),该术语是在 RFC 1808 中引入的。但是,此术语已被 RFC 3986 废弃,后者引入了术语 authority 来代替它。为了向后兼容,继续使用 netloc

URL 解析

URL 解析函数侧重于将 URL 字符串拆分为其组件,或将 URL 组件组合成 URL 字符串。

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

将 URL 解析为六个组件,返回一个包含 6 个项目的 命名元组。这对应于 URL 的一般结构:scheme://netloc/path;parameters?query#fragment。每个元组项都是一个字符串,可能为空。组件不会被分解成更小的部分(例如,网络位置是一个字符串),并且 % 转义不会被扩展。上面显示的分隔符不是结果的一部分,但路径组件中的前导斜杠除外,如果存在,则会保留该斜杠。例如

>>> from urllib.parse import urlparse
>>> urlparse("scheme://netloc/path;parameters?query#fragment")
ParseResult(scheme='scheme', netloc='netloc', path='/path;parameters', params='',
            query='query', fragment='fragment')
>>> o = urlparse("https://docs.pythonlang.cn:80/3/library/urllib.parse.html?"
...              "highlight=params#url-parsing")
>>> o
ParseResult(scheme='http', netloc='docs.python.org:80',
            path='/3/library/urllib.parse.html', params='',
            query='highlight=params', fragment='url-parsing')
>>> o.scheme
'http'
>>> o.netloc
'docs.python.org:80'
>>> o.hostname
'docs.python.org'
>>> o.port
80
>>> o._replace(fragment="").geturl()
'https://docs.pythonlang.cn:80/3/library/urllib.parse.html?highlight=params'

根据 RFC 1808 中的语法规范,urlparse 仅在 netloc 由 '//' 正确引入时才识别它。否则,假定输入是相对 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 未指定方案时使用。它应该是与 urlstring 相同的类型(文本或字节),但始终允许使用默认值 '',并在适当时自动转换为 b''

如果 allow_fragments 参数为 false,则不识别片段标识符。相反,它们将被解析为路径、参数或查询组件的一部分,并且返回值中的 fragment 将设置为一个空字符串。

返回值是一个 命名元组,这意味着可以通过索引或作为命名属性访问其项目,这些属性是

属性

索引

如果不存在时的值

scheme

0

URL 方案说明符

scheme 参数

netloc

1

网络位置部分

空字符串

path

2

层次路径

空字符串

params

3

最后一个路径元素的参数

空字符串

query

4

查询组件

空字符串

fragment

5

片段标识符

空字符串

username

用户名

password

密码

hostname

主机名(小写)

port

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

如果在 URL 中指定了无效端口,则读取 port 属性将引发 ValueError。有关结果对象的更多信息,请参见 结构化解析结果 部分。

netloc 属性中不匹配的方括号将引发 ValueError

在 NFKC 规范化(由 IDNA 编码使用)下分解为 /?#@: 中的任何一个的 netloc 属性中的字符将引发 ValueError。如果在解析之前对 URL 进行分解,则不会引发错误。

与所有命名元组一样,子类还有一些特别有用的方法和属性。其中一个方法是 _replace()_replace() 方法将返回一个新的 ParseResult 对象,该对象将指定的字段替换为新值。

>>> 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='')

警告

urlparse() 不执行验证。有关详细信息,请参见 URL 解析安全性

在 3.2 版更改: 添加了 IPv6 URL 解析功能。

版本 3.3 中的变化: 现在将解析所有 URL 方案的片段(除非 allow_fragments 为 false),这与 RFC 3986 一致。以前,存在一个支持片段的方案允许列表。

版本 3.6 中的变化: 超出范围的端口号现在会引发 ValueError,而不是返回 None

版本 3.8 中的变化: 在 NFKC 规范化下影响网络位置解析的字符现在会引发 ValueError

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

解析作为字符串参数(类型为 application/x-www-form-urlencoded 的数据)给定的查询字符串。数据以字典形式返回。字典键是唯一的查询变量名称,值是每个名称的值列表。

可选参数 keep_blank_values 是一个标志,指示是否应将百分比编码查询中的空白值视为空白字符串。值为 true 表示应将空白保留为空白字符串。默认值 false 表示将忽略空白值,并将其视为未包含。

可选参数 strict_parsing 是一个标志,指示如何处理解析错误。如果为 false(默认值),则会静默忽略错误。如果为 true,则错误会引发 ValueError 异常。

可选的 encodingerrors 参数指定如何将百分比编码的序列解码为 Unicode 字符,如 bytes.decode() 方法所接受的那样。

可选参数 max_num_fields 是要读取的最大字段数。如果设置,则在读取的字段数超过 max_num_fields 时引发 ValueError

可选参数 separator 是用于分隔查询参数的符号。默认为 &

使用 urllib.parse.urlencode() 函数(将 doseq 参数设置为 True)将此类字典转换为查询字符串。

版本 3.2 中的变化: 添加了 encodingerrors 参数。

版本 3.8 中的变化: 添加了 max_num_fields 参数。

版本 3.10 中的变化: 添加了 separator 参数,默认值为 &。Python 3.10 之前的 Python 版本允许使用 ;& 作为查询参数分隔符。此行为已更改为仅允许使用单个分隔符键,默认分隔符为 &

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

解析作为字符串参数(类型为 application/x-www-form-urlencoded 的数据)给定的查询字符串。数据以名称-值对列表的形式返回。

可选参数 keep_blank_values 是一个标志,指示是否应将百分比编码查询中的空白值视为空白字符串。值为 true 表示应将空白保留为空白字符串。默认值 false 表示将忽略空白值,并将其视为未包含。

可选参数 strict_parsing 是一个标志,指示如何处理解析错误。如果为 false(默认值),则会静默忽略错误。如果为 true,则错误会引发 ValueError 异常。

可选的 encodingerrors 参数指定如何将百分比编码的序列解码为 Unicode 字符,如 bytes.decode() 方法所接受的那样。

可选参数 max_num_fields 是要读取的最大字段数。如果设置,则在读取的字段数超过 max_num_fields 时引发 ValueError

可选参数 separator 是用于分隔查询参数的符号。默认为 &

使用 urllib.parse.urlencode() 函数将此类对列表转换为查询字符串。

版本 3.2 中的变化: 添加了 encodingerrors 参数。

版本 3.8 中的变化: 添加了 max_num_fields 参数。

版本 3.10 中的变化: 添加了 separator 参数,默认值为 &。Python 3.10 之前的 Python 版本允许使用 ;& 作为查询参数分隔符。此行为已更改为仅允许使用单个分隔符键,默认分隔符为 &

urllib.parse.urlunparse(parts)

urlparse() 返回的元组构造 URL。parts 参数可以是任何六项可迭代对象。如果最初解析的 URL 具有不必要的定界符(例如,带有空查询的 ?;RFC 规定这些是等效的),则这可能会导致略有不同但等效的 URL。

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

这与 urlparse() 类似,但不从 URL 中分离参数。如果需要更新的 URL 语法,允许将参数应用于 URL 的 path 部分的每个段(请参阅 RFC 2396),则通常应使用此函数而不是 urlparse()。需要一个单独的函数来分离路径段和参数。此函数返回一个 5 项 命名元组

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

返回值是一个 命名元组,可以通过索引或作为命名属性访问其项

属性

索引

如果不存在时的值

scheme

0

URL 方案说明符

scheme 参数

netloc

1

网络位置部分

空字符串

path

2

层次路径

空字符串

query

3

查询组件

空字符串

fragment

4

片段标识符

空字符串

username

用户名

password

密码

hostname

主机名(小写)

port

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

如果在 URL 中指定了无效端口,则读取 port 属性将引发 ValueError。有关结果对象的更多信息,请参见 结构化解析结果 部分。

netloc 属性中不匹配的方括号将引发 ValueError

在 NFKC 规范化(由 IDNA 编码使用)下分解为 /?#@: 中的任何一个的 netloc 属性中的字符将引发 ValueError。如果在解析之前对 URL 进行分解,则不会引发错误。

根据更新 RFC 3986 的 WHATWG 规范,将从 URL 中删除前导 C0 控制字符和空格字符。将从 URL 的任何位置删除 \n\r 和制表符 \t 字符。

警告

urlsplit() 不执行验证。有关详细信息,请参阅 URL 解析安全性

版本 3.6 中的变化: 超出范围的端口号现在会引发 ValueError,而不是返回 None

版本 3.8 中的变化: 在 NFKC 规范化下影响网络位置解析的字符现在会引发 ValueError

版本 3.10 中的变化: 从 URL 中删除了 ASCII 换行符和制表符。

版本 3.12 中的变化: 从 URL 中删除了前导 WHATWG C0 控制字符和空格字符。

urllib.parse.urlunsplit(parts)

urlsplit() 返回的元组的元素组合成一个完整的 URL 字符串。parts 参数可以是任何五项可迭代对象。如果最初解析的 URL 具有不必要的定界符(例如,带有空查询的 ?;RFC 规定这些是等效的),则这可能会导致略有不同但等效的 URL。

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

通过将“基本 URL”(base)与另一个 URL(url)组合来构造完整的(“绝对”)URL。非正式地,这将使用基本 URL 的组件,特别是寻址方案、网络位置和(部分)路径,来提供相对 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 的主机名和/或方案。例如

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

如果您不希望出现这种行为,请使用 urlsplit()urlunsplit() 预处理 url,删除可能的 schemenetloc 部分。

版本 3.5 中的变化: 行为已更新,以匹配 RFC 3986 中定义的语义。

urllib.parse.urldefrag(url)

如果 url 包含片段标识符,则返回 url 的修改版本,其中没有片段标识符,并将片段标识符作为单独的字符串。如果 url 中没有片段标识符,则返回未修改的 url 和一个空字符串。

返回值是一个 命名元组,可以通过索引或作为命名属性访问其项

属性

索引

如果不存在时的值

url

0

没有片段的 URL

空字符串

fragment

1

片段标识符

空字符串

有关结果对象的更多信息,请参阅 结构化解析结果 部分。

版本 3.2 中的变化: 结果是一个结构化对象,而不是简单的 2 元组。

urllib.parse.unwrap(url)

从包装的 URL(即格式为 <URL:scheme://host/path><scheme://host/path>URL:scheme://host/pathscheme://host/path 的字符串)中提取 url。如果 url 不是包装的 URL,则不加更改地返回它。

URL 解析安全性

urlsplit()urlparse() API 不对输入执行验证。它们可能不会对其他应用程序认为无效的输入引发错误。它们也可能在某些其他地方可能不被视为 URL 的输入上成功。它们的目的是为了实用功能,而不是为了纯粹性。

它们可能不会在异常输入上引发异常,而是返回一些为空字符串的组件部分。或者组件可能包含的内容比它们应该包含的内容更多。

我们建议在可能将这些 API 的值用于任何具有安全隐患的地方的用户进行防御性编码。在信任返回的组件部分之前,请在代码中进行一些验证。该 scheme 是否有意义?那是一个合理的 path 吗?那个 hostname 有什么奇怪的地方吗?等等。

构成 URL 的内容没有得到普遍的良好定义。不同的应用程序有不同的需求和期望的约束。例如,现行的 WHATWG 规范 描述了面向用户的 Web 客户端(如 Web 浏览器)的要求。而 RFC 3986 则更为通用。这些函数结合了两者的某些方面,但不能声称符合其中任何一个。API 和对特定行为有期望的现有用户代码早于这两个标准,这导致我们对更改 API 行为非常谨慎。

解析 ASCII 编码的字节

URL 解析函数最初设计为仅对字符串进行操作。在实践中,能够将正确引用和编码的 URL 作为 ASCII 字节序列进行操作非常有用。因此,此模块中的 URL 解析函数除了 str 对象外,还对 bytesbytearray 对象进行操作。

如果传入 str 数据,则结果也将仅包含 str 数据。如果传入 bytesbytearray 数据,则结果将仅包含 bytes 数据。

尝试在单个函数调用中将 str 数据与 bytesbytearray 混合使用将导致引发 TypeError,而尝试传入非 ASCII 字节值将触发 UnicodeDecodeError

为了支持在 strbytes 之间更轻松地转换结果对象,URL 解析函数的所有返回值都提供 encode() 方法(当结果包含 str 数据时)或 decode() 方法(当结果包含 bytes 数据时)。这些方法的签名与相应的 strbytes 方法的签名相匹配(除了默认编码为 'ascii' 而不是 'utf-8')。每个方法都生成一个对应类型的值,该值包含 bytes 数据(对于 encode() 方法)或 str 数据(对于 decode() 方法)。

需要对可能包含非 ASCII 数据的、可能未正确引用的 URL 进行操作的应用程序需要在调用 URL 解析方法之前自行将字节解码为字符。

本节中描述的行为仅适用于 URL 解析函数。URL 引用函数在生成或使用字节序列时使用自己的规则,如各个 URL 引用函数的文档中所述。

版本 3.2 中的变化: URL 解析函数现在接受 ASCII 编码的字节序列

结构化解析结果

urlparse()urlsplit()urldefrag() 函数的结果对象是 tuple 类型的子类。这些子类添加了这些函数文档中列出的属性、上一节中描述的编码和解码支持,以及一个额外的方法

urllib.parse.SplitResult.geturl()

以字符串形式返回原始 URL 的重新组合版本。这可能与原始 URL 不同,因为方案可能会标准化为小写,并且可能会删除空组件。具体来说,将删除空的 parameters、queries 和 fragment identifiers。

对于 urldefrag() 结果,只会删除空的 fragment identifiers。对于 urlsplit()urlparse() 结果,将对此方法返回的 URL 进行所有注意到的更改。

如果通过原始解析函数传递回来,此方法的结果将保持不变

>>> from urllib.parse import urlsplit
>>> url = 'HTTP://www.Python.org/doc/#'
>>> r1 = urlsplit(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)

包含 str 数据的 urldefrag() 结果的具体类。encode() 方法返回一个 DefragResultBytes 实例。

3.2 版新增。

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

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

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

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

以下类提供了对 bytesbytearray 对象进行操作时解析结果的实现

class urllib.parse.DefragResultBytes(url, fragment)

包含 bytes 数据的 urldefrag() 结果的具体类。decode() 方法返回一个 DefragResult 实例。

3.2 版新增。

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

包含 bytes 数据的 urlparse() 结果的具体类。decode() 方法返回一个 ParseResult 实例。

3.2 版新增。

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

包含 bytes 数据的 urlsplit() 结果的具体类。decode() 方法返回一个 SplitResult 实例。

3.2 版新增。

URL 引用

URL 引用函数专注于获取程序数据,并通过引用特殊字符和适当地编码非 ASCII 文本,使其安全地用作 URL 组件。如果上述 URL 解析函数尚未涵盖此任务,它们还支持反转这些操作,以从 URL 组件的内容重新创建原始数据。

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

使用 %xx 转义序列替换 string 中的特殊字符。字母、数字和字符 '_.-~' 永远不会被引用。默认情况下,此函数用于引用 URL 路径部分。可选的 safe 参数指定了不应被引用的其他 ASCII 字符——其默认值为 '/'

string 可以是 strbytes 对象。

版本 3.7 中的变化: 将 URL 字符串的引用从 RFC 2396 移至 RFC 3986。“~” 现在包含在未保留字符集中。

可选的 encodingerrors 参数指定如何处理非 ASCII 字符,与 str.encode() 方法接受的方式相同。encoding 默认为 'utf-8'errors 默认为 'strict',这意味着不受支持的字符会引发 UnicodeEncodeError。如果 stringbytes,则不得提供 encodingerrors,否则将引发 TypeError

请注意,quote(string, safe, encoding, errors) 等效于 quote_from_bytes(string.encode(encoding, errors), safe)

示例:quote('/El Niño/') 生成 '/El%20Ni%C3%B1o/'

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

quote() 类似,但还会将空格替换为加号,这是在构建要放入 URL 的查询字符串时引用 HTML 表单值所必需的。除非原始字符串中的加号包含在 safe 中,否则它们也会被转义。它也没有将 safe 默认为 '/'

示例:quote_plus('/El Niño/') 生成 '%2FEl+Ni%C3%B1o%2F'

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

quote() 类似,但接受 bytes 对象而不是 str,并且不执行字符串到字节的编码。

示例:quote_from_bytes(b'a&\xef') 生成 'a%26%EF'

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

%xx 转义序列替换为其等效的单字符。可选的 encodingerrors 参数指定如何将百分比编码的序列解码为 Unicode 字符,与 bytes.decode() 方法接受的方式相同。

string 可以是 strbytes 对象。

encoding 默认为 'utf-8'errors 默认为 'replace',这意味着无效序列将被占位符字符替换。

示例:unquote('/El%20Ni%C3%B1o/') 生成 '/El Niño/'

版本 3.9 中的变化: string 参数支持字节和字符串对象(以前仅支持字符串)。

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 可以是 strbytes 对象。

如果它是 str,则 string 中未转义的非 ASCII 字符将编码为 UTF-8 字节。

示例:unquote_to_bytes('a%26%EF') 生成 b'a&\xef'

urllib.parse.urlencode(query, doseq=False, safe='', encoding=None, errors=None, quote_via=quote_plus)

将映射对象或包含 strbytes 对象的二元组序列转换为百分号编码的 ASCII 文本字符串。如果生成的字符串将用作 urlopen() 函数的 POST 操作的 *data*,则应将其编码为字节,否则会导致 TypeError

生成的字符串是由 '&' 字符分隔的一系列 key=value 对,其中 *key* 和 *value* 都使用 *quote_via* 函数进行引用。默认情况下,使用 quote_plus() 对值进行引用,这意味着空格被引用为 '+' 字符,而 '/' 字符被编码为 %2F,这遵循 GET 请求的标准(application/x-www-form-urlencoded)。可以作为 *quote_via* 传递的另一个函数是 quote(),它将空格编码为 %20 并且不编码 '/' 字符。要最大限度地控制引用的内容,请使用 quote 并为 *safe* 指定一个值。

当使用二元组序列作为 *query* 参数时,每个元组的第一个元素是键,第二个元素是值。值元素本身可以是一个序列,在这种情况下,如果可选参数 *doseq* 的计算结果为 True,则会为该键的值序列中的每个元素生成由 '&' 分隔的单个 key=value 对。编码字符串中的参数顺序将与序列中参数元组的顺序相匹配。

*safe*、*encoding* 和 *errors* 参数将传递给 *quote_via*(仅当查询元素是 str 时,才会传递 *encoding* 和 *errors* 参数)。

为了反转此编码过程,此模块中提供了 parse_qs()parse_qsl(),用于将查询字符串解析为 Python 数据结构。

有关如何使用 urllib.parse.urlencode() 方法生成 URL 查询字符串或 POST 请求数据的更多信息,请参阅 urllib 示例

3.2 版更改: query 支持字节和字符串对象。

3.5 版更改: 添加了 *quote_via* 参数。

另请参阅

WHATWG - URL 生活标准

URL 标准工作组,定义了 URL、域、IP 地址、application/x-www-form-urlencoded 格式及其 API。

RFC 3986 - 统一资源标识符

这是当前标准 (STD66)。urllib.parse 模块的任何更改都应符合此标准。可以观察到某些偏差,这些偏差主要是为了向后兼容以及满足主要浏览器中常见的某些事实上的解析要求。

RFC 2732 - URL 中的 IPv6 地址的格式。

这指定了 IPv6 URL 的解析要求。

RFC 2396 - 统一资源标识符 (URI):通用语法

描述统一资源名称 (URN) 和统一资源定位符 (URL) 的通用语法要求的文档。

RFC 2368 - mailto URL 方案。

mailto URL 方案的解析要求。

RFC 1808 - 相对统一资源定位符

此请求注释 (RFC) 包括用于连接绝对 URL 和相对 URL 的规则,包括大量“异常示例”,这些示例规定了边界情况的处理方式。

RFC 1738 - 统一资源定位符 (URL)

这指定了绝对 URL 的正式语法和语义。