Python Handler处理器和自定义Opener原理详解


Posted in Python onMarch 05, 2020

我们之前一直都在使用的urlopen,这是一个特殊的opener(也就是模块帮我们构建好的)。

但是基本的urlopen()方法不支持代理、cookie等其他的HTTP/HTTPS高级功能。所以要支持这些功能:

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

2.然后通过urllib.request.build_opener()方法,创建自定义opener对象

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

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

简单的自定义opener()

#!/usr/bin/python3
# -*- coding:utf-8 -*-
__author__ = 'mayi'
import urllib.request
# 构建一个HTTPHandler处理器对象,支持处理HTTP请求。
http_handler = urllib.request.HTTPHandler()
# # 构建一个HTTPSHandler处理器对象,支持处理HTTPS请求
# https_handler = urllib.request.HTTPSHandler()
# 调用urllib.request.build_opener()方法,创建支持处理HTTP请求的opener对象
opener = urllib.request.build_opener(http_handler)
# 构建Request请求
request = urllib.request.Request("http://www.baidu.com/")
# 调用自定义opener对象的open()方法,发送request请求
response = opener.open(request)
# 获取服务器响应内容
html = response.read()
print(html)

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

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

# 仅需要修改的代码部分:
# 构建一个HTTPHandler 处理器对象,支持处理HTTP请求,同时开启Debug Log,debuglevel 值默认 0
http_handler = urllib.request.HTTPHandler(debuglevel = 1)
# 构建一个HTTPHSandler 处理器对象,支持处理HTTPS请求,同时开启Debug Log,debuglevel 值默认 0
https_handler = urllib.request.HTTPSHandler(debuglevel = 1)

ProxyHandler处理器(IP代理设置)

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

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

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

#!/usr/bin/python3
# -*- coding:utf-8 -*-
__author__ = 'mayi'
 
"""
ProxyHandler处理器(代理设置)
很多网站会检测某一段时间某个IP的访问次数(通过流量统计,系统日志等),如果
访问次数多的不像正常人,它会禁止这个IP的访问。
所以我们可能通过设置一些代理服务器,每隔一段时间换一个代理IP,就算IP被禁
止,我们依然可以换个IP继续爬取。
"""
 
import urllib.request
 
# 构建了两个代理Handler,一个有代理IP,一个没有代理IP
http_proxy_handler = urllib.request.ProxyHandler({"http":"222.33.192.238:8118"})
null_proxy_handler = urllib.request.ProxyHandler({})
 
# 定义一个代理开关
proxy_switch = True
 
# 根据代理开关是否拱形,使用不同的代理模式
# 通过urllib.request.build_opener()方法使用这些代理Handler对象,创建自定义opener对象
if proxy_switch:
  opener = urllib.request.build_opener(http_proxy_handler)
else:
  opener = urllib.request.build_opener(null_proxy_handler)
 
request = urllib.request.Request("http://www.baidu.com/")
# 1. 如果这么写,只有使用opener.open()方法发送请求才使用自定义的代理,而urlopen()则不使用自定义代理。
response = opener.open(request)
# 2. 如果这么写,就是将opener应用到全局,之后所有的,不管是opener.open()还是urlopen() 发送请求,都将使用自定义代理。
# urllib.request.install_opener(opener)
# response = urlopen(request)
html = response.read()
 
print(html)

免费的开放代理获取基本没有什么成本,我们可以在一些代理网站上收集这些免费代理,测试后如果可以用,就把它收集起来用在爬虫上面。

免费代理网站举例:

  • 西刺免费代理IP

  • 快代理免费代理

  • Proxy360代理

  • 全网代理IP

如果代理IP足够多,就可以让程序随机获取一个代理IP去访问网站。

import random
proxy_list = [
  {"http" : "1.85.220.77:8118"},
  {"http" : "110.73.6.57:8123"},
  {"http" : "171.39.4.8:8123"},
  {"http" : "122.244.53.133:808"},
  {"http" : "171.39.75.81:8123"}
]
# 随机选择一个代理
proxy = random.choice(proxy_list)

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

所以,要根据自己的需求,选择是否需要使用高品质的私密代理(通常需要找专门的代理供应商购买,再通过用户名/密码授权使用)。

Cookie

Cookie是指某些网站服务器为了辨别用户身份和进行Session跟踪,而储存在用户浏览器上的文本文件,Cookie可以保持登录信息到用户下次与服务器的会话。

Cookie原理

HTTP是无状态的面向连接的协议,为了保持连接状态,引入了Cookie机制,Cookie是HTTP消息头中的一种属性,包括:

  • Cookie名字(Name)
  • Cookie的值(Value)
  • Cookie的过期时间(Expires/Max-Age)
  • Cookie作用路径(Path)
  • Cookie所在域名(Domain),

使用Cookie进行安全连接(Secure)。

前两个参数是Cookie应用的必要条件,另外,还包括Cookie大小(Size,不同浏览器对Cookie个数及大小限制是有差异的)。
Cookie由变量名和值组成,根据Netscape公司的规定,Cookie格式如下:

Set-Cookie: NAME=VALUE;Expires=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE

http.cookiejar库和HTTPCookieProcessor处理器

在Python3.x处理Cookie,一般是通过http.cookjar模块和urllib.request模块的HTTPCookieProcessor处理器类一起使用。

http.cookjar模块:主要作用是提供用于存储cookie的对象

HTTPCookieProcessor处理器:主要作用是处理这些cookie对象,并构建handler对象。

http.cookjar库

该模块主要的对象有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。

  • CookieJar:管理HTTP cookie值、存储HTTP请求生成的cookie、向传出的HTTP请求添加cookie的对象。整个cookie都存储在内存中,对CookieJar实例进行垃圾回收后cookie也将丢失。
  • FileCookieJar(filename, delayload = None, policy = None):从CookieJar派生而来,用来创建FileCookieJar实例,检索cookie信息并将cookie存储到文件中。filename是存储cookie的文件名。delayload为True时支持延迟访问访问文件,即只有在需要时才读取文件或文件中存储数据。
  • MozillaCookieJar(filename, delayload = None, policy = None):从FileCookieJar派生而来,创建与Mozilla浏览器cookies.txt兼容的FileCookieJar实例。
  • LWPCookieJar(filename, delayload = None, policy = None):从FileCookieJar派生而来,创建与libwww-perl标准的Set-Cookie3文件格式兼容的FileCookieJar实例。

其实大多数情况下,我们只用CookieJar(),如果需要和本地文件交互,就用MozillaCookiejar()或LWPCookieJar()

案例:利用http.cookiejar和post登录人人网

#!/usr/bin/python3
# -*- coding:utf-8 -*-
__author__ = 'mayi'
 
"""
利用http.cookiejar和post登录人人网
url = "http://www.renren.com/PLogin.do"
"""
 
import urllib
import urllib.request
import http.cookiejar
 
# 构建一个CookieJar对象实例来保存cookie
cookie = http.cookiejar.CookieJar()
# 使用HTTPCookieProcessor()来创建cookie处理器对象,参数为CookieJar()对象
cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
# 通过build_opener()来构建opener
opener = urllib.request.build_opener(cookie_handler)
# 设置User-Agent头:addheaders接受一个列表,里面每个元素都是一个headers信息的元组,opener将附带headers信息
opener.addheaders = [('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36')]
# 需要登录的账户和密码
email = input("请输入您的账户:")
password = input("请输入您的密码:")
data = {"email": email, "password": password}
# 通过urlencode()转码
postdata = urllib.parse.urlencode(data)
postdata = postdata.encode(encoding = "utf-8") # str转bytes
# 构建Request请求对象,包含需要发送的用户名和密码
request = urllib.request.Request("http://www.renren.com/PLogin.do", data = postdata)
# 通过opener发送这个请求,并获取登录后的Cookie值
opener.open(request)
# opener包含用户登录后的Cookie值,可以直接访问那些登录后才可以访问的页面
response = opener.open("http://www.renren.com/413928886/profile")
# 获取页面内容
html = response.read()
# 将页面内容存储至本地磁盘
fo = open("renren.html", "wb")
fo.write(html)
fo.close()

模拟登录要注意几点:

  • 登录一般都会先有一个HTTP GET,用于获取一些信息及获得Cookie,然后再HTTP POST登录。
  • HTTP POST登录的链接有可能是动态的,从GET返回的信息中获取。
  • password(密码)有些是明文发送,有些是加密后发送。有些网站甚至采用动态加密的,同时包括了很多其他数据的加密信息,只能通过查看JS源码获得加密算法,再去破解加密,非常困难。
  • 大多数网站的登录整体流程是类似的,可能部分细节不一样,所以其他网站登录时,需根据具体情况,作对应的修改。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python之模拟鼠标键盘动作具体实现
Dec 30 Python
Python求两个list的差集、交集与并集的方法
Nov 01 Python
Python re模块介绍
Nov 30 Python
Python利用字典将两个通讯录文本合并为一个文本实例
Jan 16 Python
urllib和BeautifulSoup爬取维基百科的词条简单实例
Jan 17 Python
Python实现带参数与不带参数的多重继承示例
Jan 30 Python
python 读入多行数据的实例
Apr 19 Python
Python的argparse库使用详解
Oct 09 Python
tensorflow 限制显存大小的实现
Feb 03 Python
使用python的pyplot绘制函数实例
Feb 13 Python
django models里数据表插入数据id自增操作
Jul 15 Python
PyQt5多线程防卡死和多窗口用法的实现
Sep 15 Python
Python使用进程Process模块管理资源
Mar 05 #Python
Python json模块与jsonpath模块区别详解
Mar 05 #Python
Python如何用filter函数筛选数据
Mar 05 #Python
Python API len函数操作过程解析
Mar 05 #Python
Python通过Tesseract库实现文字识别
Mar 05 #Python
Python爬虫实现模拟点击动态页面
Mar 05 #Python
python实现图片横向和纵向拼接
Mar 05 #Python
You might like
PHP print类函数使用总结
2010/06/25 PHP
PHP静态文件生成类实例
2014/11/29 PHP
在WordPress中使用wp_count_posts函数来统计文章数量
2016/01/05 PHP
php mailer类调用远程SMTP服务器发送邮件实现方法
2016/03/04 PHP
php使用高斯算法实现图片的模糊处理功能示例
2016/11/11 PHP
PHP常量DIRECTORY_SEPARATOR原理及用法解析
2020/11/10 PHP
如何实现动态删除javascript函数
2007/05/27 Javascript
js querySelector和getElementById通过id获取元素的区别
2012/04/20 Javascript
TextArea设置MaxLength属性最大输入值的js代码
2012/12/21 Javascript
提高JavaScript执行效率的23个实用技巧
2017/03/01 Javascript
Bootstrap响应式导航由768px变成992px的实现代码
2017/06/15 Javascript
清空元素html("") innerHTML="" 与 empty()的区别和应用(推荐)
2017/08/14 Javascript
javascript+html5+css3自定义弹出窗口效果
2017/10/26 Javascript
基于jQuery使用Ajax动态执行模糊查询功能
2018/07/05 jQuery
微信小程序自定义底部导航带跳转功能
2018/11/27 Javascript
微信小程序通过一个json实现分享朋友圈图片
2019/09/03 Javascript
基于Vue.js与WordPress Rest API构建单页应用详解
2019/09/16 Javascript
详解如何在Vue项目中发送jsonp请求
2019/10/25 Javascript
uniapp 仿微信的右边下拉选择弹出框的实现代码
2020/07/12 Javascript
vue el-upload上传文件的示例代码
2020/12/21 Vue.js
[01:48]完美圣典齐天大圣至宝宣传片
2016/12/17 DOTA
Pyramid添加Middleware的方法实例
2013/11/27 Python
python实现bitmap数据结构详解
2014/02/17 Python
深入解读Python解析XML的几种方式
2016/02/16 Python
python实现简单淘宝秒杀功能
2018/05/03 Python
Python3使用xml.dom.minidom和xml.etree模块儿解析xml文件封装函数的方法
2019/09/23 Python
Python函数的定义方式与函数参数问题实例分析
2019/12/26 Python
Python request post上传文件常见要点
2020/11/20 Python
用HTML5制作烟火效果的教程
2015/05/12 HTML / CSS
html5 canvas合成海报所遇问题及解决方案总结
2017/08/03 HTML / CSS
新大陆软件面试题
2016/11/24 面试题
小学生元旦广播稿
2014/02/21 职场文书
大学生党员承诺书
2014/05/20 职场文书
2017大学生寒假社会实践心得体会
2016/01/14 职场文书
成功的商业计划书这样写才最靠谱
2019/07/12 职场文书
Nginx进程管理和重载原理详解
2021/04/22 Servers