Python 爬虫稳定性:超时控制与自动重试机制

网络请求天然不可靠,一个生产级爬虫必须能优雅地处理超时、SSL 错误和请求失败。本文系统讲解 timeout 参数用法与 retrying 自动重试装饰器的最佳实践。

目录

  1. 为什么超时控制不可或缺
  2. timeout 参数详解
  3. verify 参数:跳过 SSL 验证
  4. 用 retrying 实现自动重试
  5. retrying 核心参数速查
  6. 组合使用:超时 + 重试 + 代理池联动

①为什么超时控制不可或缺

requests 默认没有超时限制------如果目标服务器不响应,程序会永远挂起等待。这在批量爬取时是灾难性的:一个卡死的请求会阻塞整个队列,代理池里的失效节点也无法被及时剔除。

发出请求→服务器无响应→无超时:永久阻塞vs有超时:抛出异常 → 继续下一个

设置合理的超时是爬虫从"能跑"到"稳定跑"的关键一步,也是代理池健康管理的前提。

②timeout 参数详解

requests 的 timeout 参数支持两种写法:传单个数值或传元组,语义不同。

复制代码
# 写法一:单值,同时限制连接超时和读取超时
resp = requests.get(url, timeout=3)

# 写法二:元组 (connect_timeout, read_timeout),分别控制
# 3 秒内未建立连接就放弃;建立连接后 10 秒内没有新数据也放弃
resp = requests.get(url, timeout=(3, 10))
写法 含义 适用场景
timeout=3 连接 + 读取总共不超过 3 秒 快速 API、轻量页面
timeout=(3, 10) 连接 3 秒,读取 10 秒 大文件下载、响应体较大的页面
timeout=None 无限等待(默认值) 几乎不应使用

超时触发后 requests 会抛出 requests.exceptions.Timeout 异常,务必配合 try/except 捕获,否则程序仍会崩溃。

复制代码
import requests

def fetch(url):
    headers = {"User-Agent": "Mozilla/5.0 ..."}
    data = {"uname": "admin", "passwd": "admin"}
    try:
        resp = requests.get(
            url,
            headers=headers,
            data=data,
            verify=False,   # 跳过 SSL 证书验证(见下节)
            timeout=3       # 3 秒无响应则放弃
        )
        return resp.content.decode("utf-8")
    except requests.exceptions.Timeout:
        print("超时,跳过此请求")
    except requests.exceptions.RequestException as e:
        print(f"请求异常:{e}")
    return None

if __name__ == "__main__":
    print(fetch("http://example.com/page"))

③verify 参数:跳过 SSL 验证

访问 HTTPS 网站时,requests 默认验证 SSL 证书。某些网站使用自签名证书或证书已过期,会导致 SSLError。传入 verify=False 可临时跳过这一检查。

关闭 SSL 验证会带来中间人攻击风险,切勿在涉及账号密码、支付信息的请求上使用。仅用于爬取公开内容的测试/开发环境。同时建议加上 urllib3.disable_warnings() 压制控制台的 InsecureRequestWarning 警告。

复制代码
import requests
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

resp = requests.get("https://self-signed.example.com", verify=False, timeout=5)

④用 retrying 实现自动重试

网络抖动、服务器偶发 5xx、代理临时失效------这些故障往往是暂时的,重试一次就能成功。手写重试逻辑繁琐,retrying 库提供了装饰器方案,一行注解搞定。

pip install retrying

复制代码
import requests
from retrying import retry

# 失败后最多重试 3 次(含首次),仍失败则向上抛出异常
@retry(stop_max_attempt_number=3)
def fetch_page(url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90"
    }
    # 没有 try/except:抛出异常才会触发 retrying 的重试机制
    res = requests.get(url=url, headers=headers, timeout=5)
    res.raise_for_status()  # 4xx/5xx 状态码同样触发重试
    with open("page.html", "wb") as f:
        f.write(res.content)

def main():
    try:
        fetch_page("http://example.com/list/page-1/")
    except Exception as e:
        print(f"3 次重试均失败:{e}")  # 记录日志或标记任务失败

if __name__ == "__main__":
    main()

retrying 的工作原理:被装饰的函数抛出任意异常时,自动重新调用,直到成功或达到最大次数。因此函数内部不应吞掉异常(不要用裸 except pass),否则 retrying 无法感知失败。

⑤retrying 核心参数速查

参数 含义 示例
stop_max_attempt_number 最大尝试总次数(含首次) =3
stop_max_delay 从首次调用起最长等待毫秒数 =10000(10 秒)
wait_fixed 每次重试前固定等待毫秒 =2000(等 2 秒再重试)
wait_random_min / max 随机等待区间(毫秒),模拟人类行为 wait_random_min=1000, wait_random_max=3000
retry_on_exception 传入函数,决定哪些异常触发重试 =lambda e: isinstance(e, Timeout)

⑥组合使用:超时 + 重试 + 代理池联动

三者结合是构建稳健爬虫的标准模式:超时快速识别失效代理,重试自动切换并补偿,代理池及时淘汰失效节点。

复制代码
import requests
from retrying import retry

PROXY_POOL = [
    "http://1.2.3.4:8888",
    "http://5.6.7.8:9999",
]

@retry(stop_max_attempt_number=3, wait_fixed=1000)
def fetch_with_proxy(url, proxy):
    proxies = {"http": proxy, "https": proxy}
    resp = requests.get(url, proxies=proxies, timeout=5)
    resp.raise_for_status()
    return resp.content

def main(url):
    for proxy in PROXY_POOL:
        try:
            content = fetch_with_proxy(url, proxy)
            print(f"成功,代理:{proxy}")
            return content
        except Exception:
            print(f"代理 {proxy} 失效,从池中移除")
            PROXY_POOL.remove(proxy)  # 超时/失败则剔除代理
    print("代理池已耗尽")

if __name__ == "__main__":
    main("http://example.com/data")

✓小结

超时设置 timeout=(3, 10)

SSL 问题 verify=False

自动重试 @retry(次数=3)

代理联动 失效即剔除

超时是爬虫稳定性的最基础保障,重试是应对偶发性网络故障的标准手段,两者结合代理池的动态管理,共同构成生产级爬虫的容错体系。

相关推荐
深蓝电商API13 小时前
Font Fingerprint 原理详解
爬虫
绘梨衣54714 小时前
水质月报爬虫解析架构选型:动态表头映射为主 + 字段覆盖率监控为辅(工程复盘)
爬虫·架构
Python大数据分析@14 小时前
如何应对网站反爬虫策略?如何高效地爬大量数据?
爬虫
'pi%'16 小时前
多 Agent 协同方案实践:基于 LangGraph 搭建能源领域智能调度工作流
人工智能·爬虫·microsoft·langchain·ocr·能源
kisloy1 天前
【爬虫入门第13讲】Scrapy 框架深度解析(四)核心配置与自定义扩展
网络·爬虫·scrapy
TlSfoward2 天前
TLSFoward 能帮你看到什么 TLSFOWARD抓包工具
服务器·爬虫·网络协议·https
2501_916007472 天前
Python实现HTTPS爬虫的完整指南:使用requests、BeautifulSoup、Selenium和Scrapy
爬虫·python·ios·小程序·https·uni-app·iphone
'pi%'2 天前
LangGraph 多智能体实战:搭建电力政策跟踪 Agent,实现网页爬虫、OCR 与 PDF 文档自动化解析
爬虫·pdf·ocr
杨先生哦2 天前
【2026热端攻防系列 11/12】前端AI风控攻防实战:验证码缺陷、人机验证绕过、智能爬虫对抗与企业智能风控加固方案
前端·人工智能·笔记·爬虫·安全
久久学姐2 天前
Python开发爬虫的常用技术架构
爬虫·python·http·框架·数据存储