On this page
20.5. urllib —pass URL 打开任意资源
Note
urllib模块已拆分为多个部分,并在 Python 3 中重命名为urllib.request
,urllib.parse
和urllib.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 参数或为负数)可能直到数据流结束才读取;通常情况下,没有很好的方法来确定已从套接字读取了整个流。
- 打开以 URL 表示的网络对象以进行读取。如果 URL 没有方案标识符,或者它以
除了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 *]]]])
第二个参数(如果存在)指定要复制到的文件位置(如果不存在,该位置将是具有生成名称的临时文件)。第三个参数(如果存在)是可调用的,它将在构建网络连接时被调用一次,此后每个块读取一次。可调用对象将被传递三个参数。到目前为止已传输的块数,块大小(以字节为单位)以及文件的总大小。第三个参数在旧的 FTP 服务器上可能是-1
,这些 FTP 服务器不会响应检索请求而返回文件大小。
如果* url 使用http:
方案标识符,则可以提供可选的 data *参数以指定POST
请求(通常,请求类型为GET
)。 * data 参数必须采用标准 application/x-www-form-urlencoded *格式;请参见下面的urlencode()Function。
- context *参数可以设置为ssl.SSLContext实例,以配置urlretrieve()构建 HTTPS 连接时使用的 SSL 设置。
在版本 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,程序员可以创建URLopener或FancyURLopener的子类,然后在调用所需函数之前将该类的实例分配给
urllib._urlopener
变量。例如,应用程序可能想要指定与URLopener定义不同的* User-Agent *Headers。这可以pass以下代码完成:
- 公共Functionurlopen()和urlretrieve()创建FancyURLopener类的实例,并使用它执行其请求的操作。要覆盖此Function,程序员可以创建URLopener或FancyURLopener的子类,然后在调用所需函数之前将该类的实例分配给
import urllib
class AppURLopener(urllib.FancyURLopener):
version = "App/1.7"
urllib._urlopener = AppURLopener()
urllib.
urlcleanup
( )- 清除以前调用urlretrieve()可能构建的缓存。
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 *默认为
'/'
。
- 类似于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 数据结构。
- 将 Map 对象或两个元素的 Tuples 序列转换为“百分比编码”字符串,适合作为可选的* data 参数传递给上面的urlopen()。这对于将表单字段的字典传递给
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 系统注册表中查找代理信息。如果小写和大写环境变量都存在(并且不同意),则首选小写。
- 此辅助函数将方案字典返回到代理服务器 URLMap。它以不区分大小写的方式在环境中扫描所有 os 的名称为
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。
- class *
默认情况下,URLopener类发送urllib/VVV
的* User-Agent Headers,其中 VVV 是urllib版本号。应用程序可以pass将URLopener或FancyURLopener子类化并将类属性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 的内容并将其放在 filename 中。返回值是一个由本地文件名和包含响应 Headers(对于远程 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
构造函数的参数与URLopener的参数相同。
Note
执行基本身份验证时,FancyURLopener实例将调用其prompt_user_passwd()方法。默认实现是在控制终端上向用户询问所需的信息。如果需要,子类可以重写此方法以支持更适当的行为。
FancyURLopener类提供了另一种方法,应重载以提供适当的行为:
prompt_user_passwd
(* host , realm *)- 返回在指定安全领域中给定主机上对用户进行身份验证所需的信息。返回值应该是一个 Tuples
(user, password)
,可以用于基本身份验证。
- 返回在指定安全领域中给定主机上对用户进行身份验证所需的信息。返回值应该是一个 Tuples
实现会在终端上提示 Importing 此信息。应用程序应重写此方法,以在本地环境中使用适当的交互模型。
-
- exception *
urllib.
ContentTooShortError
(* msg * [,* content *])
- 当urlretrieve()函数检测到下载的数据量小于预期的量(由* Content-Length *Headers 提供)时,将引发此异常。
content
属性存储下载的(并假定为截断的)数据。
- exception *
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()