urllib.request — 用于打开 URL 的可扩展库

源代码: Lib/urllib/request.py


urllib.request 模块定义了函数和类,有助于在一个复杂的世界中打开 URL(主要是 HTTP),包括基本和摘要认证、重定向、cookie 等。

参见

建议使用 Requests 包 获取更高级别的 HTTP 客户端接口。

警告

在 macOS 上,在使用了 os.fork() 的程序中使用此模块是不安全的,因为 macOS 的 getproxies() 实现使用了更高级别的系统 API。将环境变量 no_proxy 设置为 * 以避免此问题(例如 os.environ["no_proxy"] = "*")。

可用性:非 WASI。

此模块在 WebAssembly 上不起作用或不可用。有关更多信息,请参阅 WebAssembly 平台

urllib.request 模块定义了以下函数:

urllib.request.urlopen(url, data=None, [timeout, ]*, context=None)

打开 *url*,它可以是包含有效、正确编码的 URL 的字符串,也可以是 Request 对象。

*data* 必须是一个指定要发送到服务器的附加数据的对象,如果不需要此类数据,则为 None。有关详细信息,请参阅 Request

urllib.request 模块使用 HTTP/1.1 并在其 HTTP 请求中包含 Connection:close 头部。

可选的 *timeout* 参数指定阻塞操作(如连接尝试)的超时时间(以秒为单位)(如果未指定,将使用全局默认超时设置)。这实际上只适用于 HTTP、HTTPS 和 FTP 连接。

如果指定了 *context*,它必须是一个 ssl.SSLContext 实例,描述各种 SSL 选项。有关详细信息,请参阅 HTTPSConnection

此函数始终返回一个可以作为 context manager 工作的对象,并具有 *url*、*headers* 和 *status* 属性。有关这些属性的更多详细信息,请参阅 urllib.response.addinfourl

对于 HTTP 和 HTTPS URL,此函数返回一个经过轻微修改的 http.client.HTTPResponse 对象。除了上述三个新方法外,msg 属性包含与 reason 属性相同的信息 — 服务器返回的原因短语 — 而不是 HTTPResponse 文档中指定的响应头部。

对于 FTP、文件和数据 URL,此函数返回 urllib.response.addinfourl 对象。

协议错误时会引发 URLError

请注意,如果没有处理程序处理请求,可能会返回 None(尽管默认安装的全局 OpenerDirector 使用 UnknownHandler 以确保这种情况永远不会发生)。

此外,如果检测到代理设置(例如,当设置了 *_proxy 环境变量,如 http_proxy),ProxyHandler 会默认安装并确保请求通过代理处理。

Python 2.6 及更早版本中的传统 urllib.urlopen 函数已停用;urllib.request.urlopen() 对应于旧的 urllib2.urlopen。代理处理,曾经通过将字典参数传递给 urllib.urlopen 来完成,现在可以通过使用 ProxyHandler 对象来实现。

默认的 opener 会使用请求对象中的 fullurldataheadersmethod 参数引发一个 审计事件 urllib.Request

3.2 版中已更改: 增加了 *cafile* 和 *capath*。

现在如果可能(即如果 ssl.HAS_SNI 为真),HTTPS 虚拟主机将得到支持。

*data* 可以是可迭代对象。

3.3 版中已更改: 增加了 *cadefault*。

3.4.3 版中已更改: 增加了 *context*。

3.10 版中已更改: 如果未给出 *context*,HTTPS 连接现在会发送带有协议指示符 http/1.1 的 ALPN 扩展。自定义 *context* 应使用 set_alpn_protocols() 设置 ALPN 协议。

3.13 版中已更改: 移除了 *cafile*、*capath* 和 *cadefault* 参数:请改用 *context* 参数。

urllib.request.install_opener(opener)

安装一个 OpenerDirector 实例作为默认的全局 opener。只有当你希望 urlopen 使用该 opener 时才需要安装一个 opener;否则,只需调用 OpenerDirector.open() 而不是 urlopen()。代码不会检查真正的 OpenerDirector,任何具有适当接口的类都可以工作。

urllib.request.build_opener([handler, ...])

返回一个 OpenerDirector 实例,它按给定顺序链接处理程序。*handler* 可以是 BaseHandler 的实例,或者是 BaseHandler 的子类(在这种情况下,必须能够在不带任何参数的情况下调用构造函数)。以下类的实例将在 *handler* 之前,除非 *handler* 包含它们、它们的实例或它们的子类:ProxyHandler(如果检测到代理设置)、UnknownHandlerHTTPHandlerHTTPDefaultErrorHandlerHTTPRedirectHandlerFTPHandlerFileHandlerHTTPErrorProcessor

如果 Python 安装支持 SSL(即如果可以导入 ssl 模块),则还会添加 HTTPSHandler

一个 BaseHandler 子类也可以更改其 handler_order 属性来修改其在处理程序列表中的位置。

urllib.request.pathname2url(path, *, add_scheme=False)

将给定的本地路径转换为 file: URL。此函数使用 quote() 函数编码路径。

如果 *add_scheme* 为 false (默认值),则返回值省略 file: 方案前缀。将 *add_scheme* 设置为 true 以返回完整的 URL。

此示例显示了该函数在 Windows 上的使用

>>> from urllib.request import pathname2url
>>> path = 'C:\\Program Files'
>>> pathname2url(path, add_scheme=True)
'file:///C:/Program%20Files'

3.14 版中已更改: Windows 驱动器盘符不再转换为大写,并且不跟随驱动器盘符的 : 字符在 Windows 上不再引发 OSError 异常。

3.14 版中已更改: 以斜杠开头的路径将转换为带有授权部分的 URL。例如,路径 /etc/hosts 将转换为 URL ///etc/hosts

3.14 版中已更改: 添加了 *add_scheme* 参数。

urllib.request.url2pathname(url, *, require_scheme=False, resolve_host=False)

将给定的 file: URL 转换为本地路径。此函数使用 unquote() 解码 URL。

如果 *require_scheme* 为假(默认值),则给定值应省略 file: 方案前缀。如果 *require_scheme* 设置为真,则给定值应包含前缀;如果它不包含,则会引发 URLError

如果 URL 授权为空、localhost 或本地主机名,则会丢弃。否则,如果 *resolve_host* 设置为真,则使用 socket.gethostbyname() 解析授权并在匹配本地 IP 地址时丢弃(根据 RFC 8089 §3)。如果授权仍未处理,则在 Windows 上返回 UNC 路径,在其他平台上引发 URLError

此示例显示了该函数在 Windows 上的使用

>>> from urllib.request import url2pathname
>>> url = 'file:///C:/Program%20Files'
>>> url2pathname(url, require_scheme=True)
'C:\\Program Files'

3.14 版中已更改: Windows 驱动器盘符不再转换为大写,并且不跟随驱动器盘符的 : 字符在 Windows 上不再引发 OSError 异常。

3.14 版中已更改: 如果 URL 授权与本地主机名匹配,则会丢弃。否则,如果授权不为空或 localhost,则在 Windows 上返回 UNC 路径(与之前一样),在其他平台上引发 URLError

3.14 版中已更改: 如果存在,则丢弃 URL 查询和片段组件。

3.14 版中已更改: 添加了 *require_scheme* 和 *resolve_host* 参数。

urllib.request.getproxies()

此辅助函数返回一个方案到代理服务器 URL 映射的字典。它首先以不区分大小写的方式扫描所有操作系统中名为 <scheme>_proxy 的变量,如果找不到,则从 macOS 的系统配置和 Windows 的系统注册表中查找代理信息。如果同时存在小写和大写环境变量(且不一致),则优先使用小写。

备注

如果设置了环境变量 REQUEST_METHOD(通常表示您的脚本正在 CGI 环境中运行),则会忽略环境变量 HTTP_PROXY(大写 _PROXY)。这是因为该变量可以由客户端使用“Proxy:”HTTP 头部注入。如果您需要在 CGI 环境中使用 HTTP 代理,请明确使用 ProxyHandler,或者确保变量名是小写(或至少是 _proxy 后缀)。

提供了以下类:

class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)

这个类是 URL 请求的抽象。

*url* 应该是一个包含有效、正确编码的 URL 的字符串。

*data* 必须是一个指定要发送到服务器的附加数据的对象,如果不需要此类数据,则为 None。目前只有 HTTP 请求使用 *data*。支持的对象类型包括字节、类文件对象和字节类对象的可迭代对象。如果未提供 Content-LengthTransfer-Encoding 头部字段,HTTPHandler 将根据 *data* 的类型设置这些头部。Content-Length 将用于发送字节对象,而 Transfer-Encoding: chunked(如 RFC 7230,第 3.3.1 节所述)将用于发送文件和其他可迭代对象。

对于 HTTP POST 请求方法,*data* 应该是标准 application/x-www-form-urlencoded 格式的缓冲区。urllib.parse.urlencode() 函数接受一个映射或 2 元组序列,并以这种格式返回一个 ASCII 字符串。在用作 *data* 参数之前,它应该被编码为字节。

*headers* 应该是一个字典,并且将被视为调用了 add_header(),其中每个键和值作为参数。这通常用于“伪造”User-Agent 头部值,浏览器使用它来标识自己——某些 HTTP 服务器只允许来自常见浏览器的请求,而不是脚本。例如,Mozilla Firefox 可能将自己标识为 "Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11",而 urllib 的默认用户代理字符串是 "Python-urllib/2.6"(在 Python 2.6 上)。所有头部键都以驼峰式发送。

如果存在 *data* 参数,则应包含适当的 Content-Type 头部。如果未提供此头部且 *data* 不是 None,则将默认添加 Content-Type: application/x-www-form-urlencoded

接下来的两个参数仅对正确处理第三方 HTTP cookie 有意义

*origin_req_host* 应该是原始事务的请求主机,如 RFC 2965 所定义。它默认为 http.cookiejar.request_host(self)。这是用户发起的原始请求的主机名或 IP 地址。例如,如果请求是 HTML 文档中的图像,这应该是包含该图像的页面的请求主机。

*unverifiable* 应该指示请求是否不可验证,如 RFC 2965 所定义。它默认为 False。不可验证的请求是指用户没有批准其 URL 的请求。例如,如果请求是 HTML 文档中的图像,并且用户无法选择批准自动获取图像,则此项应为 true。

*method* 应该是一个字符串,指示将使用的 HTTP 请求方法(例如 'HEAD')。如果提供,其值存储在 method 属性中,并由 get_method() 使用。如果 *data* 为 None,则默认值为 'GET',否则为 'POST'。子类可以通过在类本身中设置 method 属性来指示不同的默认方法。

备注

如果数据对象无法多次传递其内容(例如,只能生成一次内容的文件或可迭代对象),并且请求因 HTTP 重定向或认证而重试,则请求将无法按预期工作。*data* 在头部之后立即发送到 HTTP 服务器。库不支持 100-continue 期望。

3.3 版中已更改: Request.method 参数已添加到 Request 类中。

3.4 版中已更改: 默认的 Request.method 现在可以在类级别设置。

3.6 版中已更改: 如果未提供 Content-Length 且 *data* 既不是 None 也不是字节对象,则不再引发错误。改为回退使用分块传输编码。

class urllib.request.OpenerDirector

OpenerDirector 类通过链接的 BaseHandler 打开 URL。它管理处理程序的链接和错误的恢复。

class urllib.request.BaseHandler

这是所有已注册处理程序的基类——并且只处理简单的注册机制。

class urllib.request.HTTPDefaultErrorHandler

一个类,它定义了 HTTP 错误响应的默认处理程序;所有响应都转换为 HTTPError 异常。

class urllib.request.HTTPRedirectHandler

一个处理重定向的类。

class urllib.request.HTTPCookieProcessor(cookiejar=None)

一个处理 HTTP Cookie 的类。

class urllib.request.ProxyHandler(proxies=None)

使请求通过代理。如果给出了 *proxies*,它必须是一个将协议名称映射到代理 URL 的字典。默认是从环境变量 <protocol>_proxy 读取代理列表。如果未设置代理环境变量,则在 Windows 环境中,代理设置从注册表的 Internet 设置部分获取,在 macOS 环境中,代理信息从系统配置框架中检索。

要禁用自动检测代理,请传入一个空字典。

环境变量 no_proxy 可用于指定不应通过代理访问的主机;如果设置,它应该是以逗号分隔的主机名后缀列表,可选地附加 :port,例如 cern.ch,ncsa.uiuc.edu,some.host:8080

备注

如果设置了变量 REQUEST_METHOD,则会忽略 HTTP_PROXY;请参阅 getproxies() 的文档。

class urllib.request.HTTPPasswordMgr

维护一个 (realm, uri) -> (user, password) 映射的数据库。

class urllib.request.HTTPPasswordMgrWithDefaultRealm

维护一个 (realm, uri) -> (user, password) 映射的数据库。如果其他领域不适用,则将 None 的领域视为包罗万象的领域,并对其进行搜索。

class urllib.request.HTTPPasswordMgrWithPriorAuth

HTTPPasswordMgrWithDefaultRealm 的变体,它还包含 uri -> is_authenticated 映射的数据库。可由 BasicAuth 处理程序用于确定何时立即发送身份验证凭据,而不是等待 401 响应。

在 3.5 版本加入。

class urllib.request.AbstractBasicAuthHandler(password_mgr=None)

这是一个混合类,有助于 HTTP 认证,包括对远程主机和代理的认证。如果给出 *password_mgr*,它应该与 HTTPPasswordMgr 兼容;有关必须支持的接口的信息,请参阅 HTTPPasswordMgr 对象 一节。如果 *passwd_mgr* 也提供 is_authenticatedupdate_authenticated 方法(参见 HTTPPasswordMgrWithPriorAuth 对象),则处理程序将使用给定 URI 的 is_authenticated 结果来确定是否随请求发送认证凭据。如果 is_authenticated 对 URI 返回 True,则发送凭据。如果 is_authenticatedFalse,则不发送凭据,然后如果收到 401 响应,则使用认证凭据重新发送请求。如果认证成功,则调用 update_authenticated 将 URI 的 is_authenticated 设置为 True,以便后续对 URI 或其任何超 URI 的请求将自动包含认证凭据。

3.5 版新增: 增加了 is_authenticated 支持。

class urllib.request.HTTPBasicAuthHandler(password_mgr=None)

处理与远程主机的认证。如果给出 *password_mgr*,它应该与 HTTPPasswordMgr 兼容;有关必须支持的接口的信息,请参阅 HTTPPasswordMgr 对象 一节。HTTPBasicAuthHandler 在遇到错误的认证方案时将引发 ValueError

class urllib.request.ProxyBasicAuthHandler(password_mgr=None)

处理与代理的认证。如果给出 *password_mgr*,它应该与 HTTPPasswordMgr 兼容;有关必须支持的接口的信息,请参阅 HTTPPasswordMgr 对象 一节。

class urllib.request.AbstractDigestAuthHandler(password_mgr=None)

这是一个混合类,有助于 HTTP 认证,包括对远程主机和代理的认证。如果给出 *password_mgr*,它应该与 HTTPPasswordMgr 兼容;有关必须支持的接口的信息,请参阅 HTTPPasswordMgr 对象 一节。

3.14 版中已更改: 增加了对 HTTP 摘要认证算法 SHA-256 的支持。

class urllib.request.HTTPDigestAuthHandler(password_mgr=None)

处理与远程主机的认证。如果给出 *password_mgr*,它应该与 HTTPPasswordMgr 兼容;有关必须支持的接口的信息,请参阅 HTTPPasswordMgr 对象 一节。当同时添加摘要认证处理程序和基本认证处理程序时,始终首先尝试摘要认证。如果摘要认证再次返回 40x 响应,则将其发送到基本认证处理程序进行处理。此处理程序方法在遇到除摘要或基本以外的认证方案时将引发 ValueError

3.3 版中已更改: 在不支持的认证方案上引发 ValueError

class urllib.request.ProxyDigestAuthHandler(password_mgr=None)

处理与代理的认证。如果给出 *password_mgr*,它应该与 HTTPPasswordMgr 兼容;有关必须支持的接口的信息,请参阅 HTTPPasswordMgr 对象 一节。

class urllib.request.HTTPHandler

一个处理打开 HTTP URL 的类。

class urllib.request.HTTPSHandler(debuglevel=0, context=None, check_hostname=None)

一个处理打开 HTTPS URL 的类。*context* 和 *check_hostname* 具有与 http.client.HTTPSConnection 中相同的含义。

3.2 版中已更改: 增加了 *context* 和 *check_hostname*。

class urllib.request.FileHandler

打开本地文件。

class urllib.request.DataHandler

打开数据 URL。

在 3.4 版本加入。

class urllib.request.FTPHandler

打开 FTP URL。

class urllib.request.CacheFTPHandler

打开 FTP URL,并维护打开的 FTP 连接缓存以最大程度地减少延迟。

class urllib.request.UnknownHandler

一个处理未知 URL 的通用类。

class urllib.request.HTTPErrorProcessor

处理 HTTP 错误响应。

请求对象

以下方法描述了 Request 的公共接口,因此所有方法都可以在子类中重写。它还定义了几个公共属性,客户端可以使用它们来检查已解析的请求。

Request.full_url

传递给构造函数的原始 URL。

3.4 版中已更改。

Request.full_url 是一个带有 setter、getter 和 deleter 的属性。获取 full_url 返回带有片段(如果存在)的原始请求 URL。

Request.type

URI 方案。

Request.host

URI 授权,通常是主机,但也可以包含由冒号分隔的端口。

Request.origin_req_host

请求的原始主机,不带端口。

Request.selector

URI 路径。如果 Request 使用代理,则选择器将是传递给代理的完整 URL。

Request.data

请求的实体正文,如果未指定则为 None

3.4 版中已更改: 更改 Request.data 的值现在会删除之前设置或计算的“Content-Length”头部。

Request.unverifiable

布尔值,表示请求是否不可验证,如 RFC 2965 所定义。

Request.method

要使用的 HTTP 请求方法。默认情况下,其值为 None,这意味着 get_method() 将正常计算要使用的方法。可以通过在 Request 子类中在类级别设置它来提供默认值(从而覆盖 get_method() 中的默认计算),或者通过 *method* 参数将值传递给 Request 构造函数来设置。

在 3.3 版本加入。

3.4 版中已更改: 现在可以在子类中设置默认值;以前只能通过构造函数参数设置。

Request.get_method()

返回一个字符串,指示 HTTP 请求方法。如果 Request.method 不是 None,则返回其值,否则如果 Request.dataNone,则返回 'GET',如果不是,则返回 'POST'。这仅对 HTTP 请求有意义。

3.3 版中已更改: get_method 现在会查看 Request.method 的值。

Request.add_header(key, val)

向请求添加另一个头部。目前,除 HTTP 处理程序外,所有处理程序都忽略头部,在 HTTP 处理程序中,它们被添加到发送到服务器的头部列表中。请注意,不能有多个同名头部,如果 *key* 冲突,则后面的调用将覆盖之前的调用。目前,这不会造成 HTTP 功能的损失,因为所有在多次使用时有意义的头部都有(特定于头部的)一种方式,使用一个头部实现相同的功能。请注意,使用此方法添加的头部也会添加到重定向请求中。

Request.add_unredirected_header(key, header)

添加一个不会添加到重定向请求的头部。

Request.has_header(header)

返回实例是否具有指定名称的头部(同时检查常规头部和非重定向头部)。

Request.remove_header(header)

从请求实例中删除指定名称的头部(同时从常规头部和非重定向头部中删除)。

在 3.4 版本加入。

Request.get_full_url()

返回构造函数中给定的 URL。

3.4 版中已更改。

返回 Request.full_url

Request.set_proxy(host, type)

通过连接到代理服务器来准备请求。*host* 和 *type* 将替换实例的那些属性,并且实例的选择器将是构造函数中给定的原始 URL。

Request.get_header(header_name, default=None)

返回给定头部的值。如果头部不存在,则返回默认值。

Request.header_items()

返回一个包含请求头部 (header_name, header_value) 元组的列表。

3.4 版中已更改: 自 3.3 版起已弃用的请求方法 add_data、has_data、get_data、get_type、get_host、get_selector、get_origin_req_host 和 is_unverifiable 已移除。

OpenerDirector 对象

OpenerDirector 实例具有以下方法:

OpenerDirector.add_handler(handler)

*handler* 应该是 BaseHandler 的一个实例。将搜索以下方法,并将其添加到可能的链中(请注意,HTTP 错误是一种特殊情况)。请注意,在以下内容中,*protocol* 应该替换为实际要处理的协议,例如 http_response() 将是 HTTP 协议响应处理程序。此外,*type* 应该替换为实际的 HTTP 代码,例如 http_error_404() 将处理 HTTP 404 错误。

  • <protocol>_open() — 表示处理程序知道如何打开 *protocol* URL。

    有关详细信息,请参阅 BaseHandler.<protocol>_open()

  • http_error_<type>() — 表示处理程序知道如何处理 HTTP 错误代码为 *type* 的 HTTP 错误。

    有关详细信息,请参阅 BaseHandler.http_error_<nnn>()

  • <protocol>_error() — 表示处理程序知道如何处理来自(非 http)*protocol* 的错误。

  • <protocol>_request() — 表示处理程序知道如何预处理 *protocol* 请求。

    有关详细信息,请参阅 BaseHandler.<protocol>_request()

  • <protocol>_response() — 表示处理程序知道如何后处理 *protocol* 响应。

    有关详细信息,请参阅 BaseHandler.<protocol>_response()

OpenerDirector.open(url, data=None[, timeout])

打开给定的 *url*(可以是请求对象或字符串),可选地传递给定的 *data*。参数、返回值和引发的异常与 urlopen() 的相同(它只是调用当前安装的全局 OpenerDirector 上的 open() 方法)。可选的 *timeout* 参数指定阻塞操作(如连接尝试)的超时时间(以秒为单位)(如果未指定,将使用全局默认超时设置)。超时功能实际上只适用于 HTTP、HTTPS 和 FTP 连接。

OpenerDirector.error(proto, *args)

处理给定协议的错误。这将使用给定参数(特定于协议)调用给定协议的已注册错误处理程序。HTTP 协议是一个特殊情况,它使用 HTTP 响应代码来确定特定的错误处理程序;请参阅处理程序类的 http_error_<type>() 方法。

返回值和引发的异常与 urlopen() 的相同。

OpenerDirector 对象分三个阶段打开 URL:

在每个阶段中调用这些方法的顺序由处理程序实例的排序决定。

  1. 每个具有名为 <protocol>_request() 的方法的处理程序都会调用该方法来预处理请求。

  2. 命名为 <protocol>_open() 的处理器被调用来处理请求。当处理器返回一个非 None 值(即一个响应),或者引发一个异常(通常是 URLError)时,此阶段结束。异常允许传播。

    实际上,上述算法首先尝试名为 default_open() 的方法。如果所有此类方法都返回 None,则算法将对名为 <protocol>_open() 的方法重复执行。如果所有此类方法都返回 None,则算法将对名为 unknown_open() 的方法重复执行。

    请注意,这些方法的实现可能涉及调用父 OpenerDirector 实例的 open()error() 方法。

  3. 每个具有名为 <protocol>_response() 方法的处理器都会调用该方法来后处理响应。

BaseHandler 对象

BaseHandler 对象提供了一些直接有用的方法,以及一些供派生类使用的方法。这些方法旨在直接使用

BaseHandler.add_parent(director)

添加一个 director 作为父级。

BaseHandler.close()

移除所有父级。

以下属性和方法应仅由 BaseHandler 的派生类使用。

备注

已采用的约定是:定义 <protocol>_request()<protocol>_response() 方法的子类命名为 *Processor;所有其他子类命名为 *Handler

BaseHandler.parent

一个有效的 OpenerDirector,可用于使用不同协议打开或处理错误。

BaseHandler.default_open(req)

此方法在 BaseHandler 定义,但子类如果想捕获所有 URL,则应定义它。

此方法如果实现,将由父 OpenerDirector 调用。它应返回一个文件类对象,如 OpenerDirectoropen() 方法的返回值所述,或者 None。它应该引发 URLError,除非发生真正异常的情况(例如,MemoryError 不应映射到 URLError)。

此方法将在任何特定于协议的 open 方法之前调用。

BaseHandler.<protocol>_open(req)

此方法在 BaseHandler 定义,但如果子类想要处理给定协议的 URL,则应定义它。

此方法如果定义,将由父 OpenerDirector 调用。返回值应与 default_open() 相同。

BaseHandler.unknown_open(req)

此方法在 BaseHandler 定义,但如果子类想要捕获所有没有特定注册处理器来打开的 URL,则应定义它。

此方法如果实现,将由 parent OpenerDirector 调用。返回值应与 default_open() 相同。

BaseHandler.http_error_default(req, fp, code, msg, hdrs)

此方法在 BaseHandler 定义,但如果子类打算为其他未处理的 HTTP 错误提供一个通用处理,则应重写它。它将由收到错误的 OpenerDirector 自动调用,通常不应在其他情况下调用。

OpenerDirector 将使用五个位置参数调用此方法

  1. 一个 Request 对象,

  2. 一个带有 HTTP 错误正文的文件类对象,

  3. 错误的三位数字代码,作为字符串,

  4. 用户可见的代码解释,作为字符串,以及

  5. 错误头,作为映射对象。

返回值和引发的异常应与 urlopen() 相同。

BaseHandler.http_error_<nnn>(req, fp, code, msg, hdrs)

nnn 应该是一个三位数的 HTTP 错误代码。此方法在 BaseHandler 中也未定义,但当发生代码为 nnn 的 HTTP 错误时,如果存在,则会在子类的实例上调用。

子类应重写此方法以处理特定的 HTTP 错误。

参数、返回值和引发的异常应与 http_error_default() 相同。

BaseHandler.<protocol>_request(req)

此方法在 BaseHandler 定义,但如果子类想要预处理给定协议的请求,则应定义它。

此方法如果定义,将由父 OpenerDirector 调用。req 将是一个 Request 对象。返回值应该是一个 Request 对象。

BaseHandler.<protocol>_response(req, response)

此方法在 BaseHandler 定义,但如果子类想要后处理给定协议的响应,则应定义它。

此方法如果定义,将由父 OpenerDirector 调用。req 将是一个 Request 对象。response 将是一个实现与 urlopen() 返回值相同接口的对象。返回值应实现与 urlopen() 返回值相同接口。

HTTPRedirectHandler 对象

备注

某些 HTTP 重定向需要此模块客户端代码的操作。如果发生这种情况,则会引发 HTTPError。有关各种重定向代码精确含义的详细信息,请参阅 RFC 2616

如果 HTTPRedirectHandler 收到一个不是 HTTP、HTTPS 或 FTP URL 的重定向 URL,则会作为安全考虑引发 HTTPError 异常。

HTTPRedirectHandler.redirect_request(req, fp, code, msg, hdrs, newurl)

响应重定向返回 RequestNone。当从服务器收到重定向时,http_error_30*() 方法的默认实现会调用此方法。如果应该发生重定向,则返回一个新的 Request,以允许 http_error_30*() 执行重定向到 newurl。否则,如果没有其他处理器应该尝试处理此 URL,则引发 HTTPError,或者如果无法处理但其他处理器可能可以处理,则返回 None

备注

此方法的默认实现并未严格遵循 RFC 2616,该 RFC 规定对 POST 请求的 301 和 302 响应不得在未经用户确认的情况下自动重定向。实际上,浏览器确实允许这些响应的自动重定向,将 POST 更改为 GET,并且默认实现再现了这种行为。

HTTPRedirectHandler.http_error_301(req, fp, code, msg, hdrs)

重定向到 Location:URI: URL。当收到 HTTP“永久移动”响应时,父 OpenerDirector 会调用此方法。

HTTPRedirectHandler.http_error_302(req, fp, code, msg, hdrs)

http_error_301() 相同,但用于“找到”响应。

HTTPRedirectHandler.http_error_303(req, fp, code, msg, hdrs)

http_error_301() 相同,但用于“查看其他”响应。

HTTPRedirectHandler.http_error_307(req, fp, code, msg, hdrs)

http_error_301() 相同,但用于“临时重定向”响应。它不允许将请求方法从 POST 更改为 GET

HTTPRedirectHandler.http_error_308(req, fp, code, msg, hdrs)

http_error_301() 相同,但用于“永久重定向”响应。它不允许将请求方法从 POST 更改为 GET

在 3.11 版本中新增。

HTTPCookieProcessor 对象

HTTPCookieProcessor 实例有一个属性

HTTPCookieProcessor.cookiejar

存储 cookie 的 http.cookiejar.CookieJar

ProxyHandler 对象

ProxyHandler.<protocol>_open(request)

ProxyHandler 将为构造函数中给定 proxies 字典中具有代理的每个 protocol 提供一个 <protocol>_open() 方法。该方法将通过调用 request.set_proxy() 来修改请求以通过代理,并调用链中的下一个处理器来实际执行协议。

HTTPPasswordMgr 对象

这些方法适用于 HTTPPasswordMgrHTTPPasswordMgrWithDefaultRealm 对象。

HTTPPasswordMgr.add_password(realm, uri, user, passwd)

uri 可以是单个 URI,也可以是 URI 序列。realmuserpasswd 必须是字符串。这会导致当给定 realm 和任何给定 URI 的超 URI 的身份验证时,使用 (user, passwd) 作为身份验证令牌。

HTTPPasswordMgr.find_user_password(realm, authuri)

获取给定领域和 URI 的用户/密码,如果存在。如果没有匹配的用户/密码,此方法将返回 (None, None)

对于 HTTPPasswordMgrWithDefaultRealm 对象,如果给定的 realm 没有匹配的用户/密码,则会搜索 None 领域。

HTTPPasswordMgrWithPriorAuth 对象

此密码管理器扩展了 HTTPPasswordMgrWithDefaultRealm 以支持跟踪应始终发送身份验证凭据的 URI。

HTTPPasswordMgrWithPriorAuth.add_password(realm, uri, user, passwd, is_authenticated=False)

realmuriuserpasswdHTTPPasswordMgr.add_password() 相同。is_authenticated 设置给定 URI 或 URI 列表的 is_authenticated 标志的初始值。如果 is_authenticated 指定为 True,则忽略 realm

HTTPPasswordMgrWithPriorAuth.find_user_password(realm, authuri)

HTTPPasswordMgrWithDefaultRealm 对象相同

HTTPPasswordMgrWithPriorAuth.update_authenticated(self, uri, is_authenticated=False)

更新给定 uri 或 URI 列表的 is_authenticated 标志。

HTTPPasswordMgrWithPriorAuth.is_authenticated(self, authuri)

返回给定 URI 的 is_authenticated 标志的当前状态。

AbstractBasicAuthHandler 对象

AbstractBasicAuthHandler.http_error_auth_reqed(authreq, host, req, headers)

通过获取用户/密码对并重新尝试请求来处理身份验证请求。authreq 应该是请求中包含领域信息的头名称,host 指定要进行身份验证的 URL 和路径,req 应该是一个(失败的)Request 对象,headers 应该是错误头。

host 可以是权威机构(例如 "python.org"),也可以是包含权威组件的 URL(例如 "https://pythonlang.cn/")。在这两种情况下,权威机构都不得包含用户信息组件(因此,"python.org""python.org:80" 是可以的,"joe:password@python.org" 不可以)。

HTTPBasicAuthHandler 对象

HTTPBasicAuthHandler.http_error_401(req, fp, code, msg, hdrs)

如果可用,使用身份验证信息重试请求。

ProxyBasicAuthHandler 对象

ProxyBasicAuthHandler.http_error_407(req, fp, code, msg, hdrs)

如果可用,使用身份验证信息重试请求。

AbstractDigestAuthHandler 对象

AbstractDigestAuthHandler.http_error_auth_reqed(authreq, host, req, headers)

authreq 应该是请求中包含领域信息的头名称,host 应该是要进行身份验证的主机,req 应该是一个(失败的)Request 对象,headers 应该就是错误头。

HTTPDigestAuthHandler 对象

HTTPDigestAuthHandler.http_error_401(req, fp, code, msg, hdrs)

如果可用,使用身份验证信息重试请求。

ProxyDigestAuthHandler 对象

ProxyDigestAuthHandler.http_error_407(req, fp, code, msg, hdrs)

如果可用,使用身份验证信息重试请求。

HTTPHandler 对象

HTTPHandler.http_open(req)

发送一个 HTTP 请求,它可以是 GET 或 POST,具体取决于 req.data

HTTPSHandler 对象

HTTPSHandler.https_open(req)

发送一个 HTTPS 请求,它可以是 GET 或 POST,具体取决于 req.data

FileHandler 对象

FileHandler.file_open(req)

如果不存在主机名,或者主机名是 'localhost',则在本地打开文件。

3.2 版本中已更改: 此方法仅适用于本地主机名。当给出远程主机名时,会引发 URLError

DataHandler 对象

DataHandler.data_open(req)

读取数据 URL。这种 URL 包含编码在 URL 本身中的内容。数据 URL 语法在 RFC 2397 中指定。此实现在 base64 编码数据 URL 中忽略空格,因此 URL 可能会在其源文件中换行。但尽管有些浏览器不介意 base64 编码数据 URL 末尾缺少填充,此实现在这种情况下会引发 ValueError

FTPHandler 对象

FTPHandler.ftp_open(req)

打开 req 指定的 FTP 文件。登录始终使用空用户名和密码完成。

CacheFTPHandler 对象

CacheFTPHandler 对象是具有以下附加方法的 FTPHandler 对象

CacheFTPHandler.setTimeout(t)

将连接超时设置为 t 秒。

CacheFTPHandler.setMaxConns(m)

将缓存连接的最大数量设置为 m

UnknownHandler 对象

UnknownHandler.unknown_open()

引发 URLError 异常。

HTTPErrorProcessor 对象

HTTPErrorProcessor.http_response(request, response)

处理 HTTP 错误响应。

对于 200 错误代码,响应对象会立即返回。

对于非 200 错误代码,这只是通过 OpenerDirector.error() 将任务传递给 http_error_<type>() 处理器方法。最终,如果没有其他处理器处理该错误,HTTPDefaultErrorHandler 将引发 HTTPError

HTTPErrorProcessor.https_response(request, response)

处理 HTTPS 错误响应。

行为与 http_response() 相同。

示例

除了下面的示例,如何使用 urllib 包获取互联网资源 中还提供了更多示例。

此示例获取 python.org 主页并显示其前 300 字节。

>>> import urllib.request
>>> with urllib.request.urlopen('https://pythonlang.cn/') as f:
...     print(f.read(300))
...
b'<!doctype html>\n<!--[if lt IE 7]>   <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9">   <![endif]-->\n<!--[if IE 7]>      <html class="no-js ie7 lt-ie8 lt-ie9">          <![endif]-->\n<!--[if IE 8]>      <html class="no-js ie8 lt-ie9">

请注意,urlopen 返回一个字节对象。这是因为 urlopen 无法自动确定从 HTTP 服务器接收到的字节流的编码。通常,程序会在确定或猜测出适当的编码后,将返回的字节对象解码为字符串。

以下 HTML 规范文档 https://html.whatwg.cn/#charset 列出了 HTML 或 XML 文档可能指定其编码信息的各种方式。

有关更多信息,请参阅 W3C 文档:https://www.w3.org/International/questions/qa-html-encoding-declarations

由于 python.org 网站在其 meta 标签中指定使用 *utf-8* 编码,因此我们将使用相同的编码来解码字节对象。

>>> with urllib.request.urlopen('https://pythonlang.cn/') as f:
...     print(f.read(100).decode('utf-8'))
...
<!doctype html>
<!--[if lt IE 7]>   <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9">   <![endif]-->
<!-

也可以不使用 上下文管理器 方法实现相同的结果。

>>> import urllib.request
>>> f = urllib.request.urlopen('https://pythonlang.cn/')
>>> try:
...     print(f.read(100).decode('utf-8'))
... finally:
...     f.close()
...
<!doctype html>
<!--[if lt IE 7]>   <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9">   <![endif]-->
<!--

在以下示例中,我们将数据流发送到 CGI 的 stdin,并读取它返回给我们的数据。请注意,此示例仅在 Python 安装支持 SSL 时才有效。

>>> import urllib.request
>>> req = urllib.request.Request(url='https:///cgi-bin/test.cgi',
...                       data=b'This data is passed to stdin of the CGI')
>>> with urllib.request.urlopen(req) as f:
...     print(f.read().decode('utf-8'))
...
Got Data: "This data is passed to stdin of the CGI"

上述示例中使用的 CGI 示例代码如下:

#!/usr/bin/env python
import sys
data = sys.stdin.read()
print('Content-type: text/plain\n\nGot Data: "%s"' % data)

以下是使用 Request 执行 PUT 请求的示例:

import urllib.request
DATA = b'some data'
req = urllib.request.Request(url='https://:8080', data=DATA, method='PUT')
with urllib.request.urlopen(req) as f:
    pass
print(f.status)
print(f.reason)

使用基本 HTTP 认证

import urllib.request
# Create an OpenerDirector with support for Basic HTTP Authentication...
auth_handler = urllib.request.HTTPBasicAuthHandler()
auth_handler.add_password(realm='PDQ Application',
                          uri='https://mahler:8092/site-updates.py',
                          user='klem',
                          passwd='kadidd!ehopper')
opener = urllib.request.build_opener(auth_handler)
# ...and install it globally so it can be used with urlopen.
urllib.request.install_opener(opener)
with urllib.request.urlopen('http://www.example.com/login.html') as f:
    print(f.read().decode('utf-8'))

build_opener() 默认提供了许多处理器,包括一个 ProxyHandler。默认情况下,ProxyHandler 使用名为 <scheme>_proxy 的环境变量,其中 <scheme> 是涉及的 URL 方案。例如,读取 http_proxy 环境变量以获取 HTTP 代理的 URL。

此示例将默认的 ProxyHandler 替换为一个使用编程方式提供的代理 URL 的处理器,并使用 ProxyBasicAuthHandler 添加代理授权支持。

proxy_handler = urllib.request.ProxyHandler({'http': 'http://www.example.com:3128/'})
proxy_auth_handler = urllib.request.ProxyBasicAuthHandler()
proxy_auth_handler.add_password('realm', 'host', 'username', 'password')

opener = urllib.request.build_opener(proxy_handler, proxy_auth_handler)
# This time, rather than install the OpenerDirector, we use it directly:
with opener.open('http://www.example.com/login.html') as f:
   print(f.read().decode('utf-8'))

添加 HTTP 标头

使用 Request 构造函数的 *headers* 参数,或者

import urllib.request
req = urllib.request.Request('http://www.example.com/')
req.add_header('Referer', 'https://pythonlang.cn/')
# Customize the default User-Agent header value:
req.add_header('User-Agent', 'urllib-example/0.1 (Contact: . . .)')
with urllib.request.urlopen(req) as f:
    print(f.read().decode('utf-8'))

OpenerDirector 会自动为每个 Request 添加一个 *User-Agent* 标头。要更改此设置

import urllib.request
opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
with opener.open('http://www.example.com/') as f:
   print(f.read().decode('utf-8'))

另外,请记住,当 Request 传递给 urlopen() (或 OpenerDirector.open())时,会添加一些标准标头(*Content-Length*、*Content-Type* 和 *Host*)。

这是一个使用 GET 方法检索包含参数的 URL 的示例会话:

>>> import urllib.request
>>> import urllib.parse
>>> params = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>> url = "http://www.musi-cal.com/cgi-bin/query?%s" % params
>>> with urllib.request.urlopen(url) as f:
...     print(f.read().decode('utf-8'))
...

以下示例改用 POST 方法。请注意,urlencode 输出的参数在发送到 urlopen 作为数据之前会编码为字节。

>>> import urllib.request
>>> import urllib.parse
>>> data = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>> data = data.encode('ascii')
>>> with urllib.request.urlopen("http://requestb.in/xrbl82xr", data) as f:
...     print(f.read().decode('utf-8'))
...

以下示例使用显式指定的 HTTP 代理,覆盖环境设置:

>>> import urllib.request
>>> proxies = {'http': 'http://proxy.example.com:8080/'}
>>> opener = urllib.request.build_opener(urllib.request.ProxyHandler(proxies))
>>> with opener.open("https://pythonlang.cn") as f:
...     f.read().decode('utf-8')
...

以下示例完全不使用代理,覆盖环境设置。

>>> import urllib.request
>>> opener = urllib.request.build_opener(urllib.request.ProxyHandler({}}))
>>> with opener.open("https://pythonlang.cn/") as f:
...     f.read().decode('utf-8')
...

旧版接口

以下函数和类是从 Python 2 模块 urllib(而不是 urllib2)移植过来的。它们将来可能会在某个时候被弃用。

urllib.request.urlretrieve(url, filename=None, reporthook=None, data=None)

将 URL 指示的网络对象复制到本地文件。如果 URL 指向本地文件,除非提供了文件名,否则不会复制对象。返回一个元组 (filename, headers),其中 filename 是可以在其中找到对象的本地文件名,headersurlopen() 返回的对象(对于远程对象)的 info() 方法返回的任何内容。异常与 urlopen() 相同。

第二个参数(如果存在)指定要复制到的文件位置(如果不存在,位置将是生成名称的临时文件)。第三个参数(如果存在)是一个可调用对象,它将在建立网络连接时被调用一次,此后在读取每个块后被调用一次。可调用对象将传递三个参数;已传输的块数、块大小(以字节为单位)和文件的总大小。在不返回文件大小的旧版 FTP 服务器上,第三个参数可能为 -1

以下示例说明了最常见的用法场景

>>> import urllib.request
>>> local_filename, headers = urllib.request.urlretrieve('https://pythonlang.cn/')
>>> html = open(local_filename)
>>> html.close()

如果 *url* 使用 http: 方案标识符,则可以给出可选的 *data* 参数来指定 POST 请求(通常请求类型为 GET)。*data* 参数必须是标准 application/x-www-form-urlencoded 格式的字节对象;请参阅 urllib.parse.urlencode() 函数。

urlretrieve() 在检测到可用数据量少于预期量(即 *Content-Length* 标头报告的大小)时,将引发 ContentTooShortError。例如,当下载中断时可能会发生这种情况。

“Content-Length”被视为下限:如果有更多数据可读,urlretrieve 会读取更多数据,但如果可用数据较少,则会引发异常。

在这种情况下,您仍然可以检索下载的数据,它存储在异常实例的 content 属性中。

如果没有提供 *Content-Length* 标头,urlretrieve 无法检查已下载数据的大小,并直接返回它。在这种情况下,您只能假定下载成功。

urllib.request.urlcleanup()

清理之前调用 urlretrieve() 可能留下的临时文件。

urllib.request 限制

  • 目前,仅支持以下协议:HTTP(0.9 和 1.0 版本)、FTP、本地文件和数据 URL。

    3.4 版本中已更改: 增加了对数据 URL 的支持。

  • urlretrieve() 的缓存功能已被禁用,直到有人找到时间正确处理过期时间标头。

  • 应该有一个函数来查询某个特定 URL 是否在缓存中。

  • 为了向后兼容,如果一个 URL 看起来指向一个本地文件但无法打开,则会使用 FTP 协议重新解释该 URL。这有时会导致令人困惑的错误消息。

  • urlopen()urlretrieve() 函数在等待网络连接建立时可能会导致任意长时间的延迟。这意味着在不使用线程的情况下,很难使用这些函数构建交互式 Web 客户端。

  • urlopen()urlretrieve() 返回的数据是服务器返回的原始数据。这可能是二进制数据(例如图像)、纯文本或(例如)HTML。HTTP 协议在回复头中提供类型信息,可以通过查看 *Content-Type* 头来检查。如果返回的数据是 HTML,您可以使用 html.parser 模块来解析它。

  • 处理 FTP 协议的代码无法区分文件和目录。这在尝试读取指向不可访问文件的 URL 时可能导致意外行为。如果 URL 以 / 结尾,则假定它引用目录并将相应处理。但是,如果尝试读取文件导致 550 错误(表示找不到 URL 或无法访问,通常是由于权限原因),则路径将视为目录,以处理 URL 指定目录但缺少尾部 / 的情况。当您尝试获取因读取权限而无法访问的文件时,这可能会导致误导性结果;FTP 代码将尝试读取它,因 550 错误而失败,然后对不可读文件执行目录列表。如果需要细粒度控制,请考虑使用 ftplib 模块。

urllib.response — urllib 使用的响应类

urllib.response 模块定义了函数和类,它们定义了一个最小的文件类接口,包括 read()readline()。此模块定义的函数由 urllib.request 模块内部使用。典型的响应对象是 urllib.response.addinfourl 实例。

class urllib.response.addinfourl
url

检索到的资源的 URL,通常用于确定是否发生了重定向。

headers

EmailMessage 实例的形式返回响应头。

status

在 3.9 版本中新增。

服务器返回的状态码。

geturl()

从 3.9 版本开始已弃用: 已弃用,转而使用 url

info()

从 3.9 版本开始已弃用: 已弃用,转而使用 headers

code

从 3.9 版本开始已弃用: 已弃用,转而使用 status

getcode()

从 3.9 版本开始已弃用: 已弃用,转而使用 status