二、urllib进阶

Handler处理器 和 自定义Opener

  • opener是 urllib.request.OpenerDirector 的实例,我们之前一直都在使用的urlopen,它是一个特殊的opener(也就是模块帮我们构建好的)。
  • 但是基本的urlopen()方法不支持代理、cookie等其他的HTTP/HTTPS高级功能。所以要支持这些功能:

   使用相关的 Handler处理器 来创建特定功能的处理器对象;

      然后通过 urllib.request.build_opener()方法使用这些处理器对象,创建自定义opener对象;

   使用自定义的opener对象,调用open()方法发送请求。

  • 如果程序里所有的请求都使用自定义的opener,可以使用urllib.resquest.install_opener() 将自定义的 opener 对象 定义为 全局opener,表示如果之后凡是调用urlopen,都将使用这个opener(根据自己的需求来选择)

简单的自定义opener()

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 from urllib import request
 5 
 6 # 构建一个HTTPHandler处理器对象,支持处理HTTP的请求
 7 #http_handler = request.HTTPHandler()
 8 
 9 # 在HTTPHandler增加参数"debuglevel=1"将会自动打开Debug log 模式,
10 # 程序在执行的时候会打印收发包的信息
11 http_handler = request.HTTPHandler(debuglevel=1)
12 
13 # 调用build_opener()方法构建一个自定义的opener对象,参数是构建的处理器对象
14 opener = request.build_opener(http_handler)
15 
16 request = request.Request("http://www.baidu.com/")
17 
18 response = opener.open(request)
19 
20 print(response.read())

这种方式发送请求得到的结果,和使用urllib2.urlopen()发送HTTP/HTTPS请求得到的结果是一样的。

如果在 HTTPHandler()增加 debuglevel=1参数,还会将 Debug Log 打开,这样程序在执行的时候,会把收包和发包的报头在屏幕上自动打印出来,方便调试,有时可以省去抓包的工作。

ProxyHandler处理器(代理设置)

使用代理IP,这是爬虫/反爬虫的第二大招,通常也是最好用的。

很多网站会检测某一段时间某个IP的访问次数(通过流量统计,系统日志等),如果访问次数多的不像正常人,它会禁止这个IP的访问。

所以我们可以设置一些代理服务器,每隔一段时间换一个代理,就算IP被禁止,依然可以换个IP继续爬取。

urllib.request中通过ProxyHandler来设置使用代理服务器,下面代码说明如何使用自定义opener来使用代理:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 from urllib import request
 5 
 6 # 代理开关,表示是否启用代理
 7 proxyswitch = False
 8 
 9 
10 # 构建一个Handler处理器对象,参数是一个字典类型,包括代理类型和代理服务器IP+PROT 免费代理网上搜
11 #开放代理
12 httpproxy_handler = request.ProxyHandler({"http" : "124.88.67.54:80"})
13 
14 
15 #私密代理 账号密码拼接
16 #  httpproxy_handler = request.ProxyHandler({'http':账号':'密码@'IP':'port'})
17 
18 
19 # 构建了一个没有代理的处理器对象
20 nullproxy_handler = request.ProxyHandler({})
21 
22 if proxyswitch:
23     opener = request.build_opener(httpproxy_handler)
24 else:
25     opener = request.build_opener(nullproxy_handler)
26 
27 # 构建了一个全局的opener,之后所有的请求都可以用urlopen()方式去发送,也附带Handler的功能
28 request.install_opener(opener)
29 
30 requests = request.Request("http://www.baidu.com/")
31 response = request.urlopen(requests)
32 
33 #print response.read().decode("gbk")
34 print (response.read().decode('utf8'))
35 '''
36 字节--decode(解码)--字符串(unicode)
37 '''

但是,这些免费开放代理一般会有很多人都在使用,而且代理有寿命短,速度慢,匿名度不高,HTTP/HTTPS支持不稳定等缺点。

所以,专业爬虫工程师或爬虫公司会使用高品质的私密代理,这些代理通常需要找专门的代理供应商购买,再通过用户名/密码授权使用。

HTTPPasswordMgrWithDefaultRealm()

HTTPPasswordMgrWithDefaultRealm()类将创建一个密码管理对象,用来保存 HTTP 请求相关的用户名和密码,主要应用两个场景:

  1. 验证代理授权的用户名和密码 (ProxyBasicAuthHandler())
  2. 验证Web客户端的的用户名和密码 (HTTPBasicAuthHandler())

ProxyBasicAuthHandler(代理授权验证)

如果我们使用之前的代码来使用私密代理,会报 HTTP 407 错误,表示代理没有通过身份验证:

urllib2.HTTPError: HTTP Error 407: Proxy Authentication Required

所以我们需要改写代码,通过:

  • HTTPPasswordMgrWithDefaultRealm():来保存私密代理的用户密码
  • ProxyBasicAuthHandler():来处理代理的身份验证。
 1 import urllib.request
 2 
 3 # 用户名
 4 user = ""
 5 # 密码
 6 passwd = ""
 7 # Web服务器 IP
 8 webserver = ""
 9 
10 # 1. 构建一个密码管理对象,用来保存需要处理的用户名和密码
11 passwdmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
12 
13 # 2. 添加账户信息,第一个参数realm是与远程服务器相关的域信息,一般没人管它都是写None,后面三个参数分别是 Web服务器、用户名、密码
14 passwdmgr.add_password(None, webserver, user, passwd)
15 
16 # 3. 构建一个HTTP基础用户名/密码验证的HTTPBasicAuthHandler处理器对象,参数是创建的密码管理对象
17 httpauth_handler = urllib.request.HTTPBasicAuthHandler(passwdmgr)
18 
19 # 4. 通过 build_opener()方法使用这些代理Handler对象,创建自定义opener对象,参数包括构建的 proxy_handler
20 opener = urllib.request.build_opener(httpauth_handler)
21 
22 # 5. 可以选择通过install_opener()方法定义opener为全局opener
23 urllib.request.install_opener(opener)
24 
25 # 6. 构建 Request对象
26 request = urllib.request.Request("http://")
27 
28 # 7. 定义opener为全局opener后,可直接使用urlopen()发送请求
29 response = urllib.request.urlopen(request)
30 
31 # 8. 打印响应内容
32 print(response.read())

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏用户2442861的专栏

Maven

在使用 Maven 之前,我们必须要了解一下 Maven 到底是怎样管理 jar 包的,这就是 Maven 仓库要干的活了。

771
来自专栏网络

摸金Redis漏洞

摘要:漏洞可以参考乌云案例 ? 1.Redis漏洞基本信息漏洞名称:Redis服务器远程执行漏洞漏洞详情:Redis因配置不当可以无密码登录,导致未授权访问。 ...

2745
来自专栏JavaEdge

SpringBoot+Security 发送短信验证码在core模块下properties包中创建SmsCodeProperties在ValidateCodeProperties中new一个SmsCo

2906
来自专栏北京马哥教育

如何使用logrotate管理Linux的日志文件

日志文件包含系统内部执行情况的有用信息。在排除故障或服务器性能分析时往往需要检查日志。对于繁忙的服务器,日志文件可能会在短时间内变得非常大。这将成为一个问题,...

3154
来自专栏LIN_ZONE

php项目,别人无法访问自己(windows 系统)上Apache服务器原因(转载)

2.windows默认带防火墙的,进入 控制面板-系统和安全-Windows 防火墙-允许的程序(win10系统的是:进入 控制面板-允许应用或功能通过Wind...

623
来自专栏云计算教程系列

使用Apache或Nginx加密Tomcat流量

Tomcat是由Apache软件基金会下属的Jakarta项目开发的一个Servlet容器,按照Sun Microsystems提供的技术规范,实现了对Serv...

1506
来自专栏黑泽君的专栏

linux下如何删除文件夹?

直接rm就可以了,不过要加两个参数-rf 即:rm -rf 目录名字 -r 就是向下递归,不管有多少级目录,一并删除; -f 就是直接强行删除,不作任何提示的意...

2161
来自专栏云计算教程系列

如何在Ubuntu 16.04上安装Icinga和Icinga Web

Icinga是一个灵活而强大的开源监控系统,用于监控网络主机和服务的运行状况。它可用于监视Web worker集群的负载和正常运行时间,存储设备上的可用磁盘空间...

2274
来自专栏前端之心

如何搭建主从架构的 DNS 服务器

前面我们介绍了如何搭建 DNS 服务器以及如何往 DNS 服务器添加反向解析记录,本文将在前面的基础上告诉大家如何搭建主从架构的 DNS 服务器。

5432
来自专栏农夫安全

文件上传漏洞超级大汇总-最终篇

12、Ecshop本地文件包含获取shell 1. 首先注册用户,如下图: ? 1. 找到我的留言,尝试上传test.php,会返回错误信息发现有文件大小限制,...

5758

扫码关注云+社区