中国智慧团建网站,做火锅加盟哪个网站好,富连网网站开发,竞价外包代运营公司前言:
本篇是要结合上篇一起看的姊妹篇:爬虫工作量由小到大的思维转变---#xff1c;第三十九章 Scrapy-redis 常用的那个RetryMiddleware#xff1e;-CSDN博客
IP代理池的管理对于确保爬虫的稳定性和数据抓取的匿名性至关重要。围绕Scrapy-Redis框架和一个具体的IP代理池中…前言:
本篇是要结合上篇一起看的姊妹篇:爬虫工作量由小到大的思维转变---第三十九章 Scrapy-redis 常用的那个RetryMiddleware-CSDN博客
IP代理池的管理对于确保爬虫的稳定性和数据抓取的匿名性至关重要。围绕Scrapy-Redis框架和一个具体的IP代理池中间件代码在分布式爬虫中如何使用Redis实现IP代理池的管理这篇文章进行探讨一下 (当然,还有更好的方案,希望大家反驳我)
正文:
IP代理池与Scrapy-Redis的结合
源代码
import random
import time
import redisclass RedisProxyMiddleware(object):def __init__(self, redis_host, redis_port, redis_db, proxy_key, batch_size, max_failures, lock_key):# 初始化Redis连接self.redis redis.StrictRedis(hostredis_host, portredis_port, dbredis_db)# Redis 代理池keyself.proxy_key proxy_key# 每次从Redis获取代理的数量self.batch_size batch_size# 代理IP允许的最大失败次数self.max_failures max_failures# 代理IP锁的keyself.lock_key lock_key# 本地缓存代理IP的集合self.cached_proxies set()classmethoddef from_crawler(cls, crawler):settings crawler.settings# 创建中间件实例并返回return cls(redis_hostsettings.get(REDIS_HOST),redis_portsettings.get(REDIS_PORT),redis_dbsettings.get(REDIS_DB),proxy_keysettings.get(REDIS_PROXY_KEY),batch_sizesettings.get(BATCH_SIZE),max_failuressettings.get(MAX_FAILURES),lock_keysettings.get(REDIS_PROXY_LOCK_KEY))def process_request(self, request, spider):# 如果请求中没有代理IP或者请求中的代理IP已经被加入到了代理锁if proxy not in request.meta or self.redis.sismember(self.lock_key, request.meta[proxy]):# 如果缓存的代理IP数量小于批量大小则尝试获取新的代理IPif len(self.cached_proxies) self.batch_size:self.fetch_proxies(spider)# 如果本地缓存中有代理IP从中随机选择一个if self.cached_proxies:request.meta[proxy] random.choice(list(self.cached_proxies))def fetch_proxies(self, spider):# 尝试获取代理锁如果获取锁成功则进行代理IP的刷新if self.acquire_lock(spider):try:spider.logger.debug(代理锁已获取准备提取新的代理IP。)fetched_proxies self.redis.srandmember(self.proxy_key, self.batch_size)if fetched_proxies:# 清空本地代理IP缓存并添加新获取的代理IPself.cached_proxies.clear()self.cached_proxies.update(fetched_proxies)spider.logger.debug(已提取{}个新的代理IP。.format(len(fetched_proxies)))else:spider.logger.warning(无法获取到新的代理IP继续使用现有的代理IP。)finally:# 无论提取代理IP成功与否都释放代理锁self.release_lock(spider)spider.logger.debug(代理锁已释放。)else:# 如果没有获取到代理锁则等待等待时间应根据实际情况调整spider.logger.debug(代理锁正被其他实例占用等待重试。)time.sleep(5)def acquire_lock(self, spider):# 尝试加锁用于控制代理IP的获取status self.redis.set(self.lock_key, 1, nxTrue, ex60) # 锁的有效期设为60秒if status:spider.logger.debug(代理锁已加锁。)else:spider.logger.debug(代理锁加锁失败锁已存在。)return statusdef release_lock(self, spider):# 释放锁其他实例可以继绀获取新代理self.redis.delete(self.lock_key)spider.logger.debug(代理锁已释放。)RedisProxyMiddleware代码解析
可以细分为几个重要部分每个部分都有特定的目的。我们将对这些部分进行详细解析 初始化和属性赋值 __init__方法中实现了RedisProxyMiddleware的初始化方法。它接收来自Scrapy的参数如Redis数据库的连接信息、代理关键字、批量大小、最大失败次数和锁定键。这些参数在实例化时保存为类的属性以供后续使用。此外还初始化了一个空集合用于缓存代理IP。 from_crawler方法 from_crawler方法是一个类方法用于从Crawler对象获取参数并实例化RedisProxyMiddleware类。通过获取Scrapy设置中的Redis连接信息和其他参数我们可以方便地初始化中间件并与Redis建立连接。 process_request方法 process_request方法是RedisProxyMiddleware中的关键方法用于处理Spider请求以获取代理IP。在该方法中首先检查请求中是否存在代理IP存储在请求的meta数据中以及该代理IP是否在锁定键指定的Redis集合中。如果请求中没有代理IP或代理IP被锁定将调用fetch_proxies方法来获取新的代理IP。 fetch_proxies方法 fetch_proxies方法用于从Redis数据库获取一组全新的代理。通过使用srandmember方法它从Redis中的代理关键字指定的集合中获取指定数量的随机代理IP。如果成功获取到代理IP则将其添加到cached_proxies集合中。然后根据获取的代理IP数量记录调试日志或警告信息以供进一步的调试和分析。
总结
RedisProxyMiddleware在Scrapy框架中实现了一个IP代理池的管理中间件。通过对代码进行解析我们了解了它的初始化方法、参数设置、处理请求方法和获取全新代理IP的逻辑。RedisProxyMiddleware的设计目标是提供一个简单、可扩展和稳定的IP代理池解决方案以满足分布式爬虫的需求。通过精确管理代理IP并根据需要进行动态调整和切换我们可以提高爬虫的稳定性和数据抓取效率。