黑马程序员技术交流社区

标题: 【上海校区】Handler处理器和自定义opener [打印本页]

作者: 不二晨    时间: 2019-3-8 10:02
标题: 【上海校区】Handler处理器和自定义opener
Handler处理器和自定义opener

在我们使用urllib库请求是都是使用urlopen()方法实现的。实际上它的底层是使用HTTPHandler个Opener来实现的。如:urlopen()源码:

global _opener

if cafile or capath or cadefault:
    ...
    https_handler = HTTPSHandler(context=context)
    opener = build_opener(https_handler)
elif context:
    https_handler = HTTPSHandler(context=context)
    opener = build_opener(https_handler)
elif _opener is None:
    _opener = opener = build_opener()
else:
    opener = _opener
return opener.open(url, data, timeout)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
我们采用urlopen()的方式去请求,其实是有些局限性的,比如我们需要打开debug模式,或通过代理模式去请求,就不行了。如果要实现debug模式或代理请求的话,我们需要自己定义Handler和opener。

在urllib库中,给我们提供了一些Handler,如:HTTPHandler,HTTPSHandler,ProxyHandler,BaseHandler,AbstractHTTPHandler,FileHandler,FTPHandler,分别用于处理HTTP,HTTPS,Proxy代理等。

简单的自定义Handler和opener


import urllib.request


def common_handler(url, headers):
    """
    通过使用HTTPHandler发送请求
    """
    # 创建HTTPHandler对象
    handlers = urllib.request.HTTPHandler()
    # 创建一个Opener对象
    opener = urllib.request.build_opener(handlers)
    # 获取一个请求
    req = urllib.request.Request(url, headers=headers)
    # 通过opener请求访问服务器,并返回一个响应对象
    resp = opener.open(req)
    with open('common_handler_baidu.html', 'wb') as f:
        f.write(resp.read())

if __name__ == '__main__':
    url = 'http://www.baidu.com'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36'}

    common_handler(url, headers)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
HTTPHandler的debug模式

HTTPHandler的debug模式,是通过在HTTPHandler的参数中传入debuglevel=1,1表示打开debug模式。0表示关闭,默认是0。代码如下:

import urllib.request


def debug_handler(url, headers):
    # 给HTTPHandler的构造方法中,添加有个参数,debuglevel=1,表示打开debug模式。
    handlers = urllib.request.HTTPHandler(debuglevel=1)
    opener = urllib.request.build_opener(handlers)
    req = urllib.request.Request(url, headers=headers)
    resp = opener.open(req)
    with open('debug_handler_baidu.html', 'wb') as f:
        f.write(resp.read())

if __name__ == '__main__':
    url = 'http://www.baidu.com'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36'}

    debug_handler(url, headers)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
在运行的时候,会直接输入log信息。如图:



ProxyHandler的代理模式

在urllib库中,我们使用ProxyHandler来进行代理请求。具体代码如下:


import urllib.request

def proxy_hander(url, headers):
    # 通过ProxyHandler来做代理请求,参数是一个dict类型。key是http,value是指ip和端口。
    handlers = urllib.request.ProxyHandler({'http': '124.88.67.81:80'})  # ip是网上查找的公共ip,有可能失效,不能访问
    opener = urllib.request.build_opener(handlers)
    req = urllib.request.Request(url, headers=headers)
    resp = opener.open(req)
    with open('proxy_handler_baidu.html', 'wb') as f:
        f.write(resp.read())

if __name__ == '__main__':
    url = 'http://www.baidu.com'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36'}

    proxy_hander(url, headers)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ProxyBasicAuthHandler代理授权验证

如果我们是使用一个需要授权验证的ip做代理,直接使用ProxyHandler代理会报一个HTTP 407的错误,如下:

HTTPError: HTTP Error 407: Proxy Authentication Required
1
遇到上述问题,我们需要ProxyBasicAuthHandler来处理代理请求。除此之外,我们还需要HTTPPasswordMgrWithDefaultRealm构建一个密码的管理对象,保存需要处理的用户名和密码。具体看下面示例:

import urllib.request


def proxyauth_handler(url, headers):
    # 代理的ip和端口
    server_ip = '192.168.199.107:80'    # 在测试是,请更换代理的ip,该ip已失效
    # 代理ip的用户名,如 admin
    user = 'admin'  
    # 代理ip密码,如 admin
    password = 'admin'
    # 创建一个密码管理对象
    passwordMgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()

    # 将ip,用户名,密码保存到密码管理器中
    # 第一个参数realm是与远程服务器相关的域信息,一般没人管它都是写None
    passwordMgr.add_password(None, server_ip, user, password)
    # 获取ProxyBasicAuthHandler对象
    handler = urllib.request.ProxyBasicAuthHandler(passwordMgr)
    # 获取opener对象
    opener = urllib.request.build_opener(handler)

    # 获取请求对象
    req = urllib.request.Request(url, headers=headers)
    # 通过opener请求服务器,获取一个响应对象
    resp = opener.open(req)
    with open('proxyauth_handler_baidu.html', 'wb') as f:
        f.write(resp.read())


if __name__ == '__main__':
    url = 'http://www.baidu.com'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36'}

    auth_proxy_handler(url, headers)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
HTTPBasicAuthHandler处理器(web客户端授权)

有些web服务器在访问时,需要进行用户身份验证,爬虫直接访问会报出HTTP 401错误,表示访问身份没有授权。

HTTPError: HTTP Eeeor 401: Unauthorized
1
对于这种情况,我们可以通过HTTPBasicAuthHandler处理器来处理。

HTTPBasicAuthHandler处理器和ProxyBasicAuthHandler处理器的用法是一样的,也是通过ip(或url),用户名,密码,通过密码管理对象保存,通过HTTPBasicAuthHandler返回opener对象。

具体代码如下:

import urllib.request


def httpauth_handler(url, headers):
    # 授权账户用户名
    user = 'admin'
    # 授权账户密码
    password = 'admin'
    # 获取密码管理者对象
    passwordMgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
    # 将密码保存到密码管理者
    passwordMgr.add_password(None, url, user, password)
    # 将密码管理者传给HTTPBasicAuthHandler处理器处理,返回一个处理器对象
    handler = urllib.request.HTTPBasicAuthHandler(passwordMgr)
    # 传入handler,构建一个opener对象
    opener = urllib.request.build_opener(handler)
    # 获取一个请求对象
    req = urllib.request.Request(url, headers=headers)
    # 通过opener请求服务器,获取响应对象
    resp = opener.open(req)
    # 将响应对象返回的是数据读取到文件
    with open('httpauth_handler.html', 'wb') as f:
        f.write(resp.read())


if __name__ == '__main__':
    url = 'http://www.baidu.com'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36'}
    httpauth_handler(url, headers)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
备注:如果我们急需要web客户端验证,有需要代理,那怎么办。实际上build_open()方法,可以传递多个handler对象。实现多个handler的处理需要。
---------------------
【转载,仅作分享,侵删】
作者:张行之
来源:CSDN
原文:https://blog.csdn.net/qq_33689414/article/details/78553450
版权声明:本文为博主原创文章,转载请附上博文链接!


作者: 不二晨    时间: 2019-3-11 15:25
奈斯,感谢分享




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2