Handler处理器和自定义opener

来源:互联网 发布:公务员 紧缺职位 知乎 编辑:程序博客网 时间:2024/05/27 20:51

Handler处理器和自定义opener

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

global _openerif 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 = _openerreturn opener.open(url, data, timeout)

我们采用urlopen()的方式去请求,其实是有些局限性的,比如我们需要打开debug模式,或通过代理模式去请求,就不行了。如果要实现debug模式或代理请求的话,我们需要自己定义Handler和opener。

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

简单的自定义Handler和opener

import urllib.requestdef 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)

HTTPHandler的debug模式

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

import urllib.requestdef 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)

在运行的时候,会直接输入log信息。如图:

image


ProxyHandler的代理模式

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

import urllib.requestdef 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)

ProxyBasicAuthHandler代理授权验证

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

HTTPError: HTTP Error 407: Proxy Authentication Required

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

import urllib.requestdef 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)

HTTPBasicAuthHandler处理器(web客户端授权)

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

HTTPError: HTTP Eeeor 401: Unauthorized

对于这种情况,我们可以通过HTTPBasicAuthHandler处理器来处理。

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

具体代码如下:

import urllib.requestdef 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)

备注:如果我们急需要web客户端验证,有需要代理,那怎么办。实际上build_open()方法,可以传递多个handler对象。实现多个handler的处理需要。

阅读全文
0 0
原创粉丝点击