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)

我们采用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)

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)

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

image


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)

ProxyBasicAuthHandler代理授权验证

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

HTTPError: HTTP Error 407: Proxy Authentication Required

遇到上述问题,我们需要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)

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

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

HTTPError: HTTP Eeeor 401: Unauthorized

对于这种情况,我们可以通过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)

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值