python / 2.7.15 / all / library-urllib.html

20.5. urllib —pass URL 打开任意资源

Note

urllib模块已拆分为多个部分,并在 Python 3 中重命名为urllib.requesturllib.parseurllib.error。将您的源转换为 Python 3 时,2to3工具将自动适应导入。另外请注意,Python 3 中的urllib.request.urlopen()函数等效于urllib2.urlopen(),并且已删除了urllib.urlopen()

该模块提供了一个高级界面,用于在 www 上获取数据。特别地,urlopen()函数类似于内置函数open(),但是接受通用资源定位符(URL)而不是文件名。适用一些限制-它只能打开 URL 进行读取,而没有搜索操作可用。

See also

推荐使用Requests package作为更高级别的 HTTPClient 端界面。

在版本 2.7.9 中更改:对于 HTTPS URI,默认情况下urllib执行所有必要的证书和主机名检查。

Warning

对于 2.7.9 之前的 Python 版本,urllib 不会try验证 HTTPS URI 的服务器证书。使用风险自负!

20.5.1. 高级界面

  • urllib. urlopen(* url * [,* data * [,代理 [,* context *]]])
    • 打开以 URL 表示的网络对象以进行读取。如果 URL 没有方案标识符,或者它以file:作为方案标识符,则将打开本地文件(不包含universal newlines);否则,将打开本地文件。否则,它将打开网络上某个服务器的套接字。如果无法构建连接,则会引发IOError异常。如果一切顺利,则返回类似文件的对象。这支持以下方法:read()readline()readlines()fileno()close()info()getcode()geturl()。它还对iterator协议具有适当的支持。一个警告:read()方法(如果Ellipsis了 size 参数或为负数)可能直到数据流结束才读取;通常情况下,没有很好的方法来确定已从套接字读取了整个流。

除了info()getcode()geturl()方法外,这些方法与文件对象具有相同的接口-请参见本手册的File Objects部分。 (但是,它不是内置文件对象,因此无法在需要 true 的内置文件对象的少数地方使用.)

info()方法返回包含与 URL 关联的元信息的mimetools.Message类的实例。当方法为 HTTP 时,这些 Headers 是服务器在检索到的 HTML 页面的顶部返回的 Headers(包括 Content-Length 和 Content-Type)。当该方法是 FTP 时,如果服务器(如现在通常)响应 FTP 检索请求而传递了文件长度,则将出现 Content-LengthHeaders。如果可以猜测 MIME 类型,则将显示 Content-TypeHeaders。当该方法为本地文件时,返回的 Headers 将包括代表文件的最后修改时间的日期,提供文件大小的 Content-Length 以及包含对文件类型的猜测的 Content-Type。另请参见mimetools模块的说明。

geturl()方法返回页面的真实 URL。在某些情况下,HTTP 服务器会将 Client 端重定向到另一个 URL。 urlopen()函数透明地处理此问题,但是在某些情况下,调用者需要知道 Client 端重定向到的 URL。 geturl()方法可用于获取此重定向的 URL。

getcode()方法返回与响应一起发送的 HTTP 状态代码,如果 URL 不是 HTTP URL,则返回None

如果* url 使用http:方案标识符,则可以提供可选的 data *参数以指定POST请求(通常,请求类型为GET)。 * data 参数必须采用标准 application/x-www-form-urlencoded *格式;请参见下面的urlencode()Function。

urlopen()函数与不需要身份验证的代理透明地一起工作。在 Unix 或 Windows 环境中,在启动 Python 解释器之前,将 http_proxy ftp_proxy环境变量设置为标识代理服务器的 URL。例如('%'是命令提示符):

% http_proxy="http://www.someproxy.com:3128"
% export http_proxy
% python
...

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

在 Windows 环境中,如果未设置代理环境变量,则将从注册表的“ Internet 设置”部分获取代理设置。

在 Mac OS X 环境中,urlopen()将从 OS X 系统配置框架检索代理信息,该信息可pass“网络系统偏好设置”面板进行 Management。

或者,可选的* proxies *参数可用于显式指定代理。它必须是将代理名称 Map 到代理 URL 的字典,其中空字典不会使用任何代理,并且None(默认值)会导致使用环境代理设置,如上所述。例如:

# Use http://www.someproxy.com:3128 for HTTP proxying
proxies = {'http': 'http://www.someproxy.com:3128'}
filehandle = urllib.urlopen(some_url, proxies=proxies)
# Don't use any proxies
filehandle = urllib.urlopen(some_url, proxies={})
# Use proxies from environment - both versions are equivalent
filehandle = urllib.urlopen(some_url, proxies=None)
filehandle = urllib.urlopen(some_url)

当前不支持需要身份验证才能使用的代理;这被认为是实施限制。

  • context *参数可以设置为ssl.SSLContext实例,以配置urlopen()构建 HTTPS 连接时使用的 SSL 设置。

在版本 2.3 中进行了更改:添加了代理支持。

在 2.6 版中进行了更改:将getcode()添加到返回的对象中,并支持 no_proxy环境变量。

在版本 2.7.9 中更改:添加了* context *参数。默认情况下,所有必要的证书和主机名检查均已完成。

自 2.6 版起弃用:urlopen()函数已在 Python 3 中删除,以urllib2.urlopen()的形式删除。

  • urllib. urlretrieve(* url * [,* filename * [,* reporthook * [,* data * [,* context *]]]])
    • 如有必要,将 URL 表示的网络对象复制到本地文件。如果 URL 指向本地文件,或者存在对象的有效缓存副本,则不会复制该对象。返回一个 Tuples(filename, headers),其中* filename 是可以在其中找到对象的本地文件名,而 headers *则是由urlopen()返回的对象的info()方法(对于远程对象,可能已缓存)。exception 与urlopen()相同。

第二个参数(如果存在)指定要复制到的文件位置(如果不存在,该位置将是具有生成名称的临时文件)。第三个参数(如果存在)是可调用的,它将在构建网络连接时被调用一次,此后每个块读取一次。可调用对象将被传递三个参数。到目前为止已传输的块数,块大小(以字节为单位)以及文件的总大小。第三个参数在旧的 FTP 服务器上可能是-1,这些 FTP 服务器不会响应检索请求而返回文件大小。

如果* url 使用http:方案标识符,则可以提供可选的 data *参数以指定POST请求(通常,请求类型为GET)。 * data 参数必须采用标准 application/x-www-form-urlencoded *格式;请参见下面的urlencode()Function。

在版本 2.5 中进行了更改:当urlretrieve()检测到可用数据量小于预期量(这是* Content-Length *Headers 报告的大小)时,它将引发ContentTooShortError。例如,当下载break时,可能会发生这种情况。

  • Content-Length *被视为下限:如果要读取的数据更多,urlretrieve()将读取更多的数据,但是如果可用的数据较少,则会引发异常。

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

如果未提供* Content-Length *Headers,则urlretrieve()无法检查其已下载数据的大小,只能返回它。在这种情况下,您只需要假设下载成功即可。

在版本 2.7.9 中更改:添加了* context *参数。默认情况下,所有必要的证书和主机名检查均已完成。

  • urllib. _urlopener
    • 公共Functionurlopen()urlretrieve()创建FancyURLopener类的实例,并使用它执行其请求的操作。要覆盖此Function,程序员可以创建URLopenerFancyURLopener的子类,然后在调用所需函数之前将该类的实例分配给urllib._urlopener变量。例如,应用程序可能想要指定与URLopener定义不同的* User-Agent *Headers。这可以pass以下代码完成:
import urllib

class AppURLopener(urllib.FancyURLopener):
    version = "App/1.7"

urllib._urlopener = AppURLopener()
  • urllib. urlcleanup ( )

20.5.2. 实用Function

  • urllib. quote(* string * [,* safe *])
    • 使用%xx转义符替换* string 中的特殊字符。字母,数字和字符'_.-'都不会被引用。默认情况下,此函数用于引用 URL 的路径部分。可选的 safe *参数指定了不应加引号的其他字符-其默认值为'/'

示例:quote('/~connolly/')产生'/%7econnolly/'

  • urllib. quote_plus(* string * [,* safe *])

    • 类似于quote(),但也需要用加号替换空格,这是在构建查询字符串以进入 URL 时引用 HTML 表单值所必需的。原始字符串中的加号会转义,除非它们包含在* safe 中。它也没有 safe *默认为'/'
  • urllib. unquote(* string *)

    • %xx转义字符替换为单字符等效字符。

示例:unquote('/%7Econnolly/')产生'/~connolly/'

  • urllib. unquote_plus(* string *)

    • 类似于unquote(),但也可以用空格替换加号,这是取消引用 HTML 表单值所需的。
  • urllib. urlencode(* query * [,* doseq *])

    • 将 Map 对象或两个元素的 Tuples 序列转换为“百分比编码”字符串,适合作为可选的* data 参数传递给上面的urlopen()。这对于将表单字段的字典传递给POST请求很有用。结果字符串是由'&'个字符分隔的一系列key=value对,其中 key value 都使用上面的quote_plus()引用。当一个由两个元素组成的 Tuples 序列用作 query 参数时,每个 Tuples 的第一个元素是键,第二个是值。值元素本身可以是一个序列,在这种情况下,如果可选参数 doseq *的求值为True,则为键值序列的每个元素生成由'&'分隔的单个key=value对。编码字符串中参数的 Sequences 将与序列中参数 Tuples 的 Sequences 匹配。 urlparse模块提供函数parse_qs()parse_qsl(),这些函数用于将查询字符串解析为 Python 数据结构。
  • urllib. pathname2url(* path *)

    • 将路径名* path *从路径的本地语法转换为 URL 的路径组件中使用的形式。这不会产生完整的 URL。返回值将已经使用quote()函数引用。
  • urllib. url2pathname(* path *)

    • 将路径组件* path 从百分比编码的 URL 转换为路径的本地语法。这不接受完整的 URL。此函数使用unquote()解码 path *。
  • urllib. getproxies ( )

    • 此辅助函数将方案字典返回到代理服务器 URLMap。它以不区分大小写的方式在环境中扫描所有 os 的名称为<scheme>_proxy的变量,如果找不到该变量,则从 Mac OS X 的 Mac OSX 系统配置和 Windows 的 Windows 系统注册表中查找代理信息。如果小写和大写环境变量都存在(并且不同意),则首选小写。

Note

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

Note

urllib 还公开了某些 Util Function,例如 splittype,splithost 和其他将 URL 解析为各种组件的Function。但是建议使用urlparse来解析 URL,而不是直接使用这些函数。 Python 3 并未从urllib.parse模块公开这些帮助函数。

20.5.3. URL Opener 对象

    • class * urllib. URLopener([代理 [,上下文 [,*** x509 *]]])
    • 用于打开和读取 URL 的 Base Class。除非您需要使用http:ftp:file:以外的方案来支持打开对象,否则您可能要使用FancyURLopener

默认情况下,URLopener类发送urllib/VVV的* User-Agent Headers,其中 VVV urllib版本号。应用程序可以pass将URLopenerFancyURLopener子类化并将类属性version设置为子类定义中的适当字符串值来定义自己的 User-Agent *Headers。

可选的* proxies *参数应该是字典 Map 方案名称到代理 URL,其中空的字典会完全关闭代理。它的默认值为None,在这种情况下,将使用环境代理设置(如果存在),如上面的urlopen()的定义中所述。

  • context *参数可以是ssl.SSLContext实例。如果提供,它将定义打开程序用于构建 HTTPS 连接的 SSL 设置。

使用https:方案时,在* x509 中收集的其他关键字参数可用于 Client 端的身份验证。支持关键字 key_file cert_file *来提供 SSL 密钥和证书。两者都需要支持 Client 端身份验证。

如果服务器返回错误代码,则URLopener个对象将引发IOError异常。

在版本 2.7.9 中更改:添加了* context *参数。默认情况下,所有必要的证书和主机名检查均已完成。

  • open(* fullurl * [,* data *])

    • 使用适当的协议打开* fullurl *。该方法设置缓存和代理信息,然后使用其 Importing 参数调用相应的 open 方法。如果无法识别该方案,则调用open_unknown()。 * data 参数的含义与urlopen() data *参数相同。
  • open_unknown(* fullurl * [,* data *])

    • 可覆盖的接口,用于打开未知的 URL 类型。
  • retrieve(* url * [,* filename * [,* reporthook * [,* data *]]])

    • 检索* url 的内容并将其放在 filename 中。返回值是一个由本地文件名和包含响应 Headers(对于远程 URL)或None(对于本地 URL)的mimetools.Message对象组成的 Tuples。然后,调用者必须打开并阅读 filename 的内容。如果未提供 filename 并且 URL 指向本地文件,则返回 Importing 文件名。如果 URL 是 nonlocal 的,并且未提供 filename ,则文件名是tempfile.mktemp()的输出,其后缀与 ImportingURL 的最后一个路径部分的后缀相匹配。如果给出 reporthook *,它必须是一个接受三个数字参数的函数。从网络读取每个数据块后,将调用该方法。 * reporthook *对于本地 URL 被忽略。

如果* url 使用http:方案标识符,则可以提供可选的 data *参数以指定POST请求(通常,请求类型为GET)。 * data 参数必须采用标准 application/x-www-form-urlencoded *格式;请参见下面的urlencode()Function。

  • version

    • 指定打开器对象的用户代理的变量。若要使urllib告知服务器它是特定的用户代理,请在调用基本构造函数之前,在子类中将其设置为类变量或在构造函数中进行设置。
  • 类别 urllib. FancyURLopener(* ... *)

    • FancyURLopener子类URLopener为以下 HTTP 响应代码提供默认处理:301、302、303、307 和 401.对于上面列出的 30x 响应代码,* Location Headers 用于获取实际的 URL。对于 401 响应代码(需要身份验证),将执行基本的 HTTP 身份验证。对于 30 倍的响应代码,递归以 maxtries *属性的值为界,默认值为 10.

对于所有其他响应代码,将调用方法http_error_default(),您可以在子类中覆盖该方法以适当地处理错误。

Note

根据 RFC 2616的字母,未经用户确认,不得自动重定向 POST 请求的响应 301 和 302.实际上,浏览器确实允许自动重定向这些响应,将 POST 更改为 GET,并且urllib重现此行为。

构造函数的参数与URLopener的参数相同。

Note

执行基本身份验证时,FancyURLopener实例将调用其prompt_user_passwd()方法。默认实现是在控制终端上向用户询问所需的信息。如果需要,子类可以重写此方法以支持更适当的行为。

FancyURLopener类提供了另一种方法,应重载以提供适当的行为:

  • prompt_user_passwd(* host realm *)
    • 返回在指定安全领域中给定主机上对用户进行身份验证所需的信息。返回值应该是一个 Tuples(user, password),可以用于基本身份验证。

实现会在终端上提示 Importing 此信息。应用程序应重写此方法,以在本地环境中使用适当的交互模型。

    • exception * urllib. ContentTooShortError(* msg * [,* content *])
    • urlretrieve()函数检测到下载的数据量小于预期的量(由* Content-Length *Headers 提供)时,将引发此异常。 content属性存储下载的(并假定为截断的)数据。

2.5 版的新Function。

20.5.4. urllib 限制

Note

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

  • urlretrieve()的缓存Function已被禁用,直到我找到时间来对 Expiration 时间 Headers 进行适当的处理。

  • 应该有一个查询缓存中是否有特定 URL 的Function。

  • 为了向后兼容,如果 URL 似乎指向本地文件,但无法打开该文件,则使用 FTP 协议重新解释 URL。有时这可能会导致混淆的错误消息。

  • urlopen()urlretrieve()函数在 await 构建网络连接时可能会导致任意长的延迟。这意味着不使用线程就很难使用这些Function构建交互式 WebClient 端。

  • urlopen()urlretrieve()返回的数据是服务器返回的原始数据。这可以是二进制数据(例如图像),纯文本或(例如)HTML。 HTTP 协议在回复 Headers 中提供类型信息,可以pass查看* Content-Type *Headers 来检查类型信息。如果返回的数据是 HTML,则可以使用模块htmllib对其进行解析。

  • 处理 FTP 协议的代码无法区分文件和目录。try读取指向不可访问文件的 URL 时,这可能导致意外行为。如果 URL 以/结尾,则假定引用目录,并将对其进行相应处理。但是,如果try读取文件导致 550 错误(意味着通常出于权限原因而导致找不到 URL 或无法访问该 URL),则该路径将被视为目录,以便处理指定目录时的情况pass URL,但尾部的/已被保留。当您try获取其读取权限使其无法访问的文件时,这可能会导致误导结果。 FTP 代码将try读取它,并以 550 错误失败,然后对不可读文件执行目录列表。如果需要细粒度的控制,请考虑使用ftplib模块,子类FancyURLopener或更改* _urlopener *以满足您的需求。

  • 该模块不支持使用需要身份验证的代理。这可能会在将来实现。

  • 尽管urllib模块包含用于解析和解析 URL 字符串的(未记录的)例程,但是建议的 URL 操作接口在模块urlparse中。

20.5.5. Examples

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

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

下面的示例改为使用POST方法:

>>> import urllib
>>> params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>> f = urllib.urlopen("http://www.musi-cal.com/cgi-bin/query", params)
>>> print f.read()

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

>>> import urllib
>>> proxies = {'http': 'http://proxy.example.com:8080/'}
>>> opener = urllib.FancyURLopener(proxies)
>>> f = opener.open("http://www.python.org")
>>> f.read()

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

>>> import urllib
>>> opener = urllib.FancyURLopener({})
>>> f = opener.open("http://www.python.org/")
>>> f.read()