urllib2/urllib.request

Python2.7: urllib2

Python3: urllib.request

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

构造一个请求对象.

  • url: 请求的有效URL.

  • data: 请求的附加数据.

    • Python3.3 之前, 请求的方法根据 data 判断.'GET' if data is None else 'POST'
    • data 的类型要对应 headers 中的 Content-Type 属性. 如果 data 不为空, 而且 headers 中又没有指定 Content-Type, 则默认为 application/x-www-form-urlencoded. 所以, 一般 HTTP POST 请求的数据要用 urllib.parse.urlencode() (python2 urllib.urlencode()) 来转换为 application/x-www-form-urlencoded 格式.
  • headers: 请求的头部. 如 {'Accept': 'text/html', 'Content-Type': 'multipart/form-data'}

  • origin_req_host

  • unverifiable

  • method: New in Python3.3, 请求的方法,如: HEAD, GET, POST. 在 Python3.3 之前,请求的方法由 data 决定 'GET' if data is None else 'POST'.

urllib.request.urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, cafile=None, capath=None, cadefault=False, context=None)

Open the URL url, which can be either a string or a Request object.

  • url: 请求的 URL,或构造好的请求对象 urllib.request.Request().
  • data: 请求的附加数据,同 urllib.request.Request()data 参数.
  • timeout: 请求的超时时间, 默认为 socket 的默认超时时间 _GLOBAL_DEFAULT_TIMEOUT.
  • cafile, capath: HTTPS 请求的 CA 证书. 主要作为参数传给 ssl.create_default_context()
  • context: ssl.SSLContext 实例

正常返回一个 HTTP 请求, 返回对象有以下方法:

  • getcode(): HTTP 的响应状态码.
  • geturl(): 当前返回内容的 URL,可以用来判断是否重定向.
  • info(): HTTP 的响应头部信息.
    • dict: 头部信息字典
    • get(name): 获取头部信息中名为 name 的值, 相当于 dict.get(name)
    • getheader(name): 同 get(name)

返回的body内容可以通过read()读取.

简单例子:

1
2
3
4
from urllib.request import Request, urlopen

request = Request('http://www.lizs.cc')
response = urlopen(Request, timeout=3)

注意, urlopen() 请求的返回对象如果不是 2xx 是会报错的. 如果想知道响应是否为 404 怎么办? 可以通过捕获 HTTP.Error 错误来获取.

1
2
3
4
5
6
7
8
9
10
from urllib.request import Request, urlopen, HTTPError

request = Request('http://www.lizs.cc')
try:
response = urlopen(Request, timeout=3)
except HTTPError, err_response:
response = err_response
print(response.getcode()) # 响应状态码
print(response.info()) # 响应的头部
print(response.read()) # 响应的内容(主体)

Handler 类

模块处理器类,用来创建 opener。

urllib.request.build_opener(*handlers)

创建 opener 对象.

-*handlers, 创建 opener 所需的Handler. 如: build_opener(handler), build_opener(handler1, handler2), build_opener(*[handler1, handler2])

  • 创建 opener 的时候会自动加载以下默认 Handler: ProxyHandler, UnknownHandler, HTTPHandler, HTTPDefaultErrorHandler, HTTPRedirectHandler, FTPHandler, FileHandler, HTTPErrorProcessor.

  • 如果提供的 *handler 中, 有默认Handler的子类(issubclass), 创建 opener 的时候将去掉相应的默认 Handler.

urllib.request.install_opener(opener)

opener 设置为默认 opener.

模块的一般使用步骤:

  • 确定 Handler。
  • 创建、安装 opener。
  • 使用 urlopen() 完成请求。

不创建 opener 直接 urlopen() 会使用默认的 opener (使用默认 Handler)。

自定义 Handler 处理 HTTPError

模块默认 Handler 对 HTTP 响应状态码不是 200 <= code < 300的,都 raise HTTPError 来处理的,有时候很不方便,我们可以自定义一个Handler来处理 HTTPError。

默认 Handler 中,HTTPDefaultErrorHandler 会 raise 所有 HTTPError。

1
2
3
class HTTPDefaultErrorHandler(BaseHandler):
def http_error_default(self, req, fp, code, msg, hdrs):
raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)

重新定义处理 Handler:

1
2
3
class MyHTTPErrorHandler(urllib.request.HTTPDefaultErrorHandler):
def http_error_default(self, req, fp, code, msg, hdrs):
return urllib.request.HTTPError(req.get_full_url(), code, msg, hdrs, fp)

使用自定义的 Handler 来 urlopen:

1
2
3
4
opener = urllib.request.build_opener(MyHTTPErrorHandler)
urllib.request.install_opener(opener)
request = urllib.request.Request('http://www.lizs.cc')
response = urllib.request.urlopen(request, timeout=3)

因为,issubclass(MyHTTPErrorHandler, HTTPDefaultErrorHandler) == True,所以,HTTPDefaultErrorHandler 被去掉。

也可以通过定义 HTTPErrorProcessor 的子类来处理。因为,HTTPErrorProcessor 规定了响应状态码不为 200 <= code < 300 都是 HTTPError。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class HTTPErrorProcessor(BaseHandler):
"""Process HTTP error responses."""
handler_order = 1000 # after all other processing

def http_response(self, request, response):
code, msg, hdrs = response.code, response.msg, response.info()

# According to RFC 2616, "2xx" code indicates that the client's
# request was successfully received, understood, and accepted.
if not (200 <= code < 300):
response = self.parent.error(
'http', request, response, code, msg, hdrs)

return response

https_response = http_response

定义 Handler 将 404 响应状态码归类到正常状态。

1
2
3
4
5
6
7
8
9
10
11
12
class MyHTTPErrorProcessor(urllib.request.HTTPErrorProcessor):

def http_response(self, request, response):
code, msg, hdrs = response.code, response.msg, response.info()

# According to RFC 2616, "2xx" code indicates that the client's
# request was successfully received, understood, and accepted.
if not (200 <= code < 300 or code == 404):
response = self.parent.error(
'http', request, response, code, msg, hdrs)

return response

当 HTTP 响应状态码为 200 <= code < 300 or code == 404 都不会 raise HTTPError.

1
2
3
4
opener = urllib.request.build_opener(MyHTTPErrorProcessor)
urllib.request.install_opener(opener)
request = urllib.request.Request('http://www.lizs.cc/404')
response = urllib.request.urlopen(request)

HTTP Basic Authorization

模块提供了 HTTPBasicAuthHandler(password_mgr=None) 来处理 HTTP Basic 认证。

  • password_mgr: 密码管理器,可以用 HTTPPasswordMgrWithDefaultRealm
1
2
3
4
5
6
7
8
9
10
uri = 'http://www.lizs.cc'  # 需要 Basic 认证的url
user = 'admin' # Basic 认证的用户名
passwd = '123456' # Basic 认证的密码
mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
mgr.add_password(None, uri, user, passwd)
handler = urllib.request.HTTPBasicAuthHandler(password_mgr=mgr)
opener = urllib.request.build_opener(handler)
urllib.request.install_opener(opener)
request = urllib.request.Request(uri)
response = urllib.request.urlopen(request)