仅仅记录一下cookie池的搭建方法。一个池子无非是要保证池中元素的质量和数量。
这里保证数量用的是Python的时间调度模块sched, 实现一个定时检查,当池中数量少于一个阈值后,启动生成cookie。
保证质量就要具体情况具体分析了,不过cookied的质量主要受时间影响。所以可以以时间为分数为cookie打分。redis 的有序集合恰恰就是干这个的。我们可以将生成的cookie存入redis中,然后通过time.time()时间戳打分。并且通过zsort有序集合,我们每次可以取到时间戳最小的元素,即最先最老生成的cookie。这样保证了最先被删除的是存在时间最长的cookie。具体代码如下:
class CookieHandler(object):
# redis_url 可以写在配置文件里
def __init__(self):
self.redis_url = settings.redis_url
pool = redis.ConnectionPool.from_url(settings.redis_url)
self.client = redis.Redis(connection_pool=pool)
self.limit = 50
# 初始化一个sched
self.s = sched.scheduler(time.time, time.sleep)
self.key = 'cookie'
def save_cookie_to_redis(self, cookie):
self.client.zadd(self.key, cookie, time.time())
# 每次取时间最长的cookie
def selete_cookie_from_redis(self):
if self.client.zrange(self.key, 0, 1)[0]:
return self.client.zrange(self.key, 0, 1)[0]
else:
logging.warning('>>>>>>>>>redis cookie pool is empty<<<<<<<<
return False
def delete(self, cookie):
self.client.zrem(self.key, cookie)
# 检查池中数量,小于50启动生成
def check(self):
l = self.client.zcard(self.key)
if l < 50:
logging.info('>>>>>>>>redis cookie pool count now: {}<<<<<<<<
for i in range(self.limit - l):
create_cookie(i)
elif l == 50:
logging.info('>>>>>>>>redis cookie pool is powering: {}<<<<<<<<
def perform(self, inc):
self.s.enter(inc, 0, self.perform, (inc,))
self.check()
def schedule(self, inc):
self.s.enter(0, 0, self.perform, (inc,))
self.s.run()
在使用的时候,可以先向redis中存入适量cookie, 然后启动检查。至于如何生成cookie,现在的打码平台做这种事情非常容易,直接调用他们的api即可。
cookie池如何在爬虫中使用呢。很简单,在你想要使用cookie的地方初始化CookieHandler即可。
c = CookieHandler()
if c.select_cookie_from_redis():
cookie = c.select_select_cookie_from_redis()
如何判断cookie失效呢,这就要看具体的项目了,可以是状态码,也可以是某个特定元素。
if response.status == 400:
c.delete(response.request.cookies)
retry
我测试了下,池中初始数量50,设置inc=300, 每隔inc时间,启动检查,池中的数量可以稳定在45左右。当然了,也要看项目。可能有时候cookie的生成速度就赶不上消耗速度。