如何在Scrapy中重置Session以实现代理IP轮换
解决Scrapy中每次请求切换代理IP的问题
问题根源
你的代理服务需要关闭与代理的TCP连接后重新建立才会分配新IP,但Scrapy的Downloader默认会维护一个HTTP连接池,复用与代理服务器的连接,导致每次请求都使用同一个IP——这并非会话Cookie的持久化,而是底层TCP连接的复用导致的。
有效解决方案
1. 给每个请求添加Connection: close请求头
通过在请求头中指定Connection: close,告诉代理服务器在当前请求完成后立即关闭连接,这样Scrapy下次请求会重新和代理建立连接,触发IP轮换。
修改你的爬虫代码如下:
class IpSpider(scrapy.Spider): name = "ip" use_proxy = True http = 0 curl = 0 def start_requests(self): yield scrapy.Request( "http://ipinfo.io/ip", callback=self.parse_ip, dont_filter=True, headers={'Connection': 'close'} # 添加关闭连接的请求头 ) # 给curl命令添加对应请求头 yield scrapy.Request.from_curl( "curl -H 'Connection: close' ipinfo.io/ip", callback=self.parse_curl_ip, dont_filter=True ) def parse_ip(self, response): self.logger.info(f"http {response.body}") if self.http < 9: self.http += 1 yield scrapy.Request( "http://ipinfo.io/ip", callback=self.parse_ip, dont_filter=True, headers={'Connection': 'close'} ) def parse_curl_ip(self, response): self.logger.info(f"curl {response.body}") if self.curl < 9: self.curl += 1 yield scrapy.Request.from_curl( "curl -H 'Connection: close' ipinfo.io/ip", callback=self.parse_curl_ip, dont_filter=True )
2. 全局禁用Scrapy连接池
如果不想逐个请求添加头,可以在settings.py中全局禁用连接池,强制每次请求新建TCP连接:
DOWNLOADER_CLIENT_CONNECTION_POOL_ENABLED = False
该设置会让Scrapy不为任何请求复用连接,所有请求都会重新建立连接,直接触发代理的IP轮换。
3. 调整连接池空闲超时(可选)
若不想完全禁用连接池,可设置连接最大空闲时间为0,让空闲连接立即被回收:
DOWNLOADER_CLIENT_CONNECTION_POOL_MAX_IDLE_TIME = 0
这样连接池中的连接在请求完成后会立即关闭,下次请求需重新建立连接。
为何之前的尝试无效?
cookiejar参数仅用于隔离Cookie会话,和底层TCP连接池无关,无法触发IP轮换。scrapy-sessions库用于管理用户会话(如登录状态),不涉及TCP连接的管理,因此无法解决问题。
内容的提问来源于stack exchange,提问作者samuel guedon
相关产品推荐
相关产品推荐

