帮助中心 关于爬虫 爬虫请求重试与故障恢复机制:从简单重试到熔断降级的工程实践
爬虫请求重试与故障恢复机制:从简单重试到熔断降级的工程实践
作者: 山水代理
发布时间: 2026-06-01 10:27:22
阅读量: 20 人次

网络请求必然失败,重试策略决定采集的最终成功率


在爬虫系统中,网络请求失败是常态而非异常。代理IP失效、目标网站限流、网络抖动、服务器过载等原因都会导致请求失败。如果没有合理的重试与故障恢复机制,爬虫可能因为一次偶发错误就终止整个任务,或陷入无效重试的循环。本文从基础重试到高级熔断降级,系统讲解如何构建高可用的爬虫请求处理层。


一、哪些失败值得重试?—— 错误分类


不是所有错误都适合重试,盲目重试可能加剧服务器压力。需要根据错误类型区分处理:
可重试错误:超时(Timeout)、5xx服务端错误、429限流、连接断开(Connection Reset)。这些错误通常是临时的,重试有可能成功。
不应重试的错误:404(页面不存在)、403(禁止访问,需更换IP或检查权限)、400请求错误。重复重试只会浪费资源。
需要特殊处理的错误:代理认证失败(407)、IP被封。应先更换代理IP再重试。


二、基础重试:固定间隔与最大次数


最简单的实现
import time
import requests

def fetch_with_retry(url, max_retries=3):
    for i in range(max_retries):
        try:
            response = requests.get(url, timeout=10)
            if response.status_code == 200:
                return response
            elif response.status_code in [429, 500, 502, 503]:
                time.sleep(2) # 固定等待
                continue
        except Exception:
            time.sleep(2)
    return None


缺点
固定间隔重试可能加剧服务器拥堵,且无法适应错误类型的不同恢复时间。


三、指数退避重试:智能等待,缓解服务器压力


指数退避(Exponential Backoff)是推荐的工业级重试策略,每次重试的等待时间呈指数增长,并加入随机抖动避免“惊群效应”。

import random

def exponential_backoff(attempt, base_delay=1, max_delay=60):
    delay = min(base_delay * (2 ** attempt), max_delay)
    delay += random.uniform(0, delay * 0.1) # 加10%随机抖动
    time.sleep(delay)

for attempt in range(max_retries):
    try:
        response = requests.get(url, timeout=10)
        if response.status_code == 200:
            return response
        if response.status_code in [429, 503]:
            exponential_backoff(attempt)
            continue
    except requests.exceptions.Timeout:
        exponential_backoff(attempt)


指数退避的优势在于:给服务器足够的恢复时间,同时避免多个客户端同时重试造成二次拥堵。对于需要频繁重试的场景,还可引入Jitter(随机抖动),将重试时间分散。


四、重试与代理IP切换的联动


当使用代理IP时,很多失败是由于代理IP本身质量问题(慢、不稳定、被封)。最佳实践是在重试时同时切换代理IP。

def fetch_with_proxy_retry(url, proxy_pool):
    for retry in range(3):
        proxy = proxy_pool.get()
        try:
            response = requests.get(url, proxies={"http": proxy, "https": proxy}, timeout=10)
            if response.status_code == 200:
                return response
            if response.status_code in [403, 429]:
                proxy_pool.mark_bad(proxy) # 标记IP不可用
                continue
        except Exception:
            proxy_pool.mark_bad(proxy)
    return None


使用山水代理的隧道代理时,服务端已内置重试和IP切换逻辑,客户端只需简单调用,无需自行管理。


五、熔断降级:防止雪崩的系统保护机制


当目标网站或代理服务商持续不可用时,无休止的重试会耗尽系统资源。熔断器(Circuit Breaker)可以在错误率达到阈值时,暂时停止请求,进入“熔断”状态,一段时间后再试探性恢复。

class CircuitBreaker:
    def __init__(self, failure_threshold=5, recovery_timeout=30):
        self.failure_count = 0
        self.failure_threshold = failure_threshold
        self.recovery_timeout = recovery_timeout
        self.last_failure_time = 0
        self.state = "CLOSED" # CLOSED, OPEN, HALF_OPEN
    def call(self, func):
        if self.state == "OPEN":
            if time.time() - self.last_failure_time > self.recovery_timeout:
                self.state = "HALF_OPEN"
            else:
                raise Exception("Circuit breaker open")
        try:
            result = func()
            self.reset()
            return result
        except Exception:
            self.failure_count += 1
            self.last_failure_time = time.time()
            if self.failure_count >= self.failure_threshold:
                self.state = "OPEN"
            raise


熔断器可以在代理池大面积失效或目标网站完全不可达时,快速失败并抛出异常,让上层调度器暂停任务或切换到备用源。


六、Scrapy中的重试与代理中间件集成


Scrapy框架内置了重试中间件(RetryMiddleware),可配置重试条件和次数。结合代理中间件,可实现重试时自动更换IP。

# settings.py
RETRY_ENABLED = True
RETRY_TIMES = 3
RETRY_HTTP_CODES = [500, 502, 503, 504, 408, 429]

# middlewares.py - 自定义代理中间件
class RetryProxyMiddleware:
    def process_response(self, request, response, spider):
        if response.status in [403, 429]:
            return self.retry_with_new_proxy(request)
        return response
    def retry_with_new_proxy(self, request):
        new_proxy = get_new_proxy()
        request.meta['proxy'] = new_proxy
        return request


七、实战建议:构建健壮的爬虫请求层


1. 区分错误类型,配置差异化重试策略
超时和5xx错误使用指数退避,429则增加等待时间,代理认证失败立即切换IP。

2. 设置最大重试次数和总超时
避免无限重试,比如最多3次,或者每次任务总超时不超过2分钟。

3. 记录重试日志,分析失败原因
定期检查哪些URL频繁失败,可能是页面结构变化或代理IP质量问题,及时调整策略。

4. 使用专业代理服务降低重试次数
山水代理的代理IP质量高,可用率95%以上,且隧道代理内置自动重试,可大幅简化客户端逻辑。


总结


重试与故障恢复是爬虫工程中容易被忽视却至关重要的环节。从简单的固定间隔重试,到指数退避、代理联动,再到熔断降级,每一步都是提升采集稳定性的有效手段。结合高质量的代理服务(如山水代理),可以显著减少重试频率,提升整体效率。建议开发者根据业务的重要性和目标网站的反爬特点,选择合适的重试策略。


关于山水代理


山水代理提供高匿HTTP/HTTPS/SOCKS5代理,支持动态、静态、隧道三种模式。隧道代理内置智能重试、健康检查和故障转移,极大降低客户端开发成本。新用户可申请免费试用,体验高可用代理服务带来的稳定性提升。

企业微信

客服在线时间:9:00~18:00

133-5988-7911

Copyright© 2022-2023 祈美科技(牡丹江)有限公司 黑ICP备2022000763号-1 beian 黑公网安备 23100002000084号

山水代理仅提供代理IP服务,用户使用山水代理从事的任何行为均不代表山水代理的意志和观点,与山水代理的立场无关。

严禁用户使用山水代理从事任何违法犯罪行为。产生的相关责任用户自负,对此山水代理不承担任何法律责任。官网上所有内容的最终解释权归本公司所有。

企微客服
山水代理微信客服 客服二维码 扫一扫添加
联系客服
山水代理客服电话 133-5988-7911