写在前面
最近跟静觅大神学习了维护代理池
就借此机会整理一下
整体思路
代理池主要分为4个模块:存储模块、获取模块、检测模块、接口模块
- 存储模块:使用Redis有序集合,用来做代理的去重和状态标识
- 获取模块:定时从代理网站获取代理,将获取的代理传递给存储模块,并保存到数据库
- 检测模块:定时通过存储模块获取所有代理,并对代理进行检测,根据不同的检测结果对代理设置不同的标识
- 接口模块:通过Web API提供服务接口,接口通过连接数据库并通过Web形式返回可用代理
接下来,就一一实现这些模块吧。
存储模块
这里我们使用Redis的有序集合,集合的每一个元素都是不重复的。另外,有序集合的每一个元素都有一个分数字段。
对于代理池来说,这个分数可以作为判断一个代理是否可用的标志,100为最高分,代表最可用;0为最低分,代表不可用。
如果要获取代理,可以从代理池中随机获取分数最高的代理。
分数的设置规则:新获取的代理的分数为10,如果测试可行,分数立即置为100,检测到不可用就将分数减1,分数减至0后代理移除。
具体代码实现如下(ippool_save.py)
MAX_SCORE = 100 #最高分
MIN_SCORE = 0 #最低分
INITIAL_SCORE = 10 #初始分数
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
REDIS_PASSWORD = None
REDIS_KEY = 'proxies' #键名
import redis
from random import choice
class PoolEmptyError():
def __str__(self):
return PoolEmptyError
class RedisClient(object):
def __init__(self,host=REDIS_HOST,port=REDIS_PORT,password=REDIS_PASSWORD):
'''
初始化
:param host:地址
:param port: 端口号
:param password: 密码
'''
self.db = redis.StrictRedis(host=host,port=port,password=password,decode_responses=True)
def add(self,proxy,score=INITIAL_SCORE):
'''
添加代理,设置初始分数
:param proxy: 代理
:param score: 分数
:return: 添加结果
'''
if not self.db.zscore(REDIS_KEY,proxy):
return self.db.zadd(REDIS_KEY,{
proxy:score})
def random(self):
'''
随即获取有效代理,首先尝试获取最高分数代理,如果最高分数不存在,则按照排名获取
:return:
'''
result = self.db.zrangebyscore(REDIS_KEY,MAX_SCORE,MAX_SCORE)
if len(result):
return choice(result)
else:
result = self.db.zrevrange(REDIS_KEY,0,100)
if len(result):
return choice(result)
else:
raise PoolEmptyError
def decrease(self, proxy):
'''
代理值减一分,分数小于最小值,则代理删除
:param proxy: 代理
:return: 修改后的代理分数
'''
score = self.db.zscore(REDIS_KEY,proxy)
if score and score>MIN_SCORE:
print("代理",proxy,"当前分数",score,"减1")
return self.db.zincrby(REDIS_KEY,-1,proxy)
else:
print("代理",proxy,"当前分数",score,"移除")
return self.db.zrem(REDIS_KEY,proxy)
def exists(self,proxy):
'''
判断是否存在
:param proxy: 代理
:return: 是否存在
'''
return not self.db.zscore(REDIS_KEY,proxy)