Python urllib自定义Opener与Handler处理器详解

陆景行
陆景行
发布时间:2026-10-13 | 4人浏览过
原创

本文详解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源码获取加密算法再进行破解,难度极大。
  • 大多数网站的登录整体流程相似,但部分细节可能不同。因此,登录其他网站时,需根据具体情况做相应调整。

以上即为本文的全部内容,希望对各位的学习有所帮助,也欢迎大家多多支持本站。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表