Python urllib自定义Opener与Handler处理器详解
本文详解Python中urllib模块的自定义Opener构建原理。通过HTTPHandler、ProxyHandler及HTTPCookieProcessor处理器,实现代理IP切换与Cookie持久化。涵盖Debug调试、免费与私密代理选择策略,以及基于CookieJar的模拟登录流程,帮助开发者突破基础urlopen的功能限制。
自定义Opener构建原理
此前我们频繁使用的urlopen函数,实际上是模块内部预先构建好的一个特殊opener实例。
然而,默认的urlopen()方法并不支持代理、Cookie等高级HTTP/HTTPS功能。若需启用这些功能,需进行如下配置:
首先,利用相应的Handler处理器创建具备特定功能的处理器对象;
其次,调用urllib.request.build_opener()方法,基于上述处理器构建自定义的opener对象;
最后,使用该自定义opener对象调用open()方法来发送网络请求。
若希望程序内所有请求均使用此自定义opener,可调用urllib.request.install_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代理设置策略
接下来介绍ProxyHandler处理器(用于IP代理设置)。
许多网站会监控特定时间段内IP的访问频率(通过流量统计或系统日志)。若某IP访问次数异常高,疑似非正常人类行为,网站可能会封锁该IP。
因此,我们通常配置代理服务器,并定期更换代理IP。即使原IP被封禁,仍可通过更换IP继续执行爬取任务。
在urllib.request中,通过ProxyHandler来配置代理服务器。以下代码演示了如何使用自定义opener来应用代理:
代理IP获取与随机选择
#!/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的处理。
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.cookiejar模块与urllib.request模块的HTTPCookieProcessor处理器类。
http.cookiejar模块:主要提供用于存储Cookie的对象。
HTTPCookieProcessor处理器:主要处理这些Cookie对象,并构建相应的Handler对象。
深入解析http.cookiejar库。
该模块主要包含以下对象: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方法登录人人网。
CookieJar实战与模拟登录
#!/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源码获取加密算法再进行破解,难度极大。
- 大多数网站的登录整体流程相似,但部分细节可能不同。因此,登录其他网站时,需根据具体情况做相应调整。
以上即为本文的全部内容,希望对各位的学习有所帮助,也欢迎大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









