爬取链接时代理连接失败,如何重试当前循环?
处理爬虫代理连接失败的解决方案
嘿,这个问题我之前做大规模数据爬取的时候可太熟悉了!代理不稳定简直是爬虫的噩梦,直接让程序崩掉前功尽弃太闹心。咱们一步步来解决这个问题:
核心思路:别让单次失败终止整个程序
首先,你的程序之所以直接关闭,是因为没捕获代理连接失败的异常,Python默认会把未捕获的异常抛出来终止程序。所以第一步必须把异常接住,然后决定是重试还是换代理。
至于你问的「持续尝试代理连接直至成功」还是「重新运行当前循环」——其实最优解是两者结合:先对当前代理重试几次(避免临时网络波动导致的失败),如果还是不行,就换一个代理重新尝试当前URL的爬取;要是代理池里的代理都试过了还失败,就把这个URL记录下来,后续再处理,绝对不能直接终止整个程序。
具体实现代码示例
我以Python的requests库为例,给你写个可落地的版本,用到了tenacity这个重试库(需要先pip install tenacity):
import requests import random import logging from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type # 配置日志,方便排查问题 logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger(__name__) # 你的代理池(建议定期检测代理可用性,剔除失效的) PROXY_POOL = [ "http://proxy1:8080", "http://proxy2:8080", "http://proxy3:8080", # 更多代理... ] # 待爬取的链接列表 URLS_TO_CRAWL = [ "https://target-url-1.com", "https://target-url-2.com", # 更多链接... ] # 定义重试逻辑:针对代理错误/连接错误,重试3次,等待时间指数增长 @retry( stop=stop_after_attempt(3), # 最多重试3次 wait=wait_exponential(multiplier=1, min=2, max=10), # 等待时间:2s→4s→8s(不超过10s) retry=retry_if_exception_type((requests.exceptions.ProxyError, requests.exceptions.ConnectionError)) ) def fetch_url(url, proxy): """用指定代理爬取单个URL""" logger.info(f"尝试用代理 {proxy} 爬取 {url}") response = requests.get( url, proxies={"http": proxy, "https": proxy}, timeout=15, # 设置超时,避免程序卡住 headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"} ) response.raise_for_status() # 抛出HTTP状态码异常(比如403、500) return response def main(): for url in URLS_TO_CRAWL: success = False used_proxies = set() # 记录已经试过的代理,避免重复踩坑 max_proxy_attempts = len(PROXY_POOL) # 最多尝试所有代理一次 while not success and len(used_proxies) < max_proxy_attempts: current_proxy = random.choice(PROXY_POOL) if current_proxy in used_proxies: continue used_proxies.add(current_proxy) try: response = fetch_url(url, current_proxy) # 这里写你的数据处理逻辑:解析HTML、保存到数据库/文件等 logger.info(f"✅ 成功爬取 {url},状态码:{response.status_code}") success = True except requests.exceptions.ProxyError: logger.warning(f"❌ 代理 {current_proxy} 连接失败,换代理重试...") except requests.exceptions.ConnectionError: logger.warning(f"❌ 连接 {url} 超时,换代理重试...") except requests.exceptions.HTTPError as e: logger.error(f"❌ 爬取 {url} 遇到HTTP错误:{str(e)},标记为待处理") break except Exception as e: logger.error(f"❌ 爬取 {url} 遇到未知错误:{str(e)},标记为待处理") break if not success: # 所有代理都试过还失败,记录到文件或者数据库 with open("failed_urls.txt", "a", encoding="utf-8") as f: f.write(f"{url}\n") logger.error(f"⚠️ 所有代理都无法爬取 {url},已记录到failed_urls.txt") if __name__ == "__main__": main()
关键细节解释
- 异常捕获:专门针对
ProxyError和ConnectionError做处理,这是代理连接失败最常见的两种异常;同时也捕获其他HTTP错误和未知异常,避免程序崩溃。 - 重试机制:用
tenacity的装饰器实现智能重试,指数增长的等待时间能降低被目标网站封禁的风险,也给代理恢复的时间。 - 代理池轮换:每个URL会尝试不同的代理,直到成功或者代理池用完,避免死磕一个失效的代理。
- 失败记录:把爬取失败的URL记录下来,后续可以换一批代理再重新爬,不会丢失任务。
额外建议
- 维护代理池:定期检测代理的可用性(比如定时请求百度,看能不能成功),把失效的代理从池子里删掉,补充新的有效代理,这能大幅减少连接失败的概率。
- 不要无限重试:设置重试次数上限,比如最多重试3次代理,最多尝试5个不同的代理,避免陷入死循环。
- 模拟真实请求:加上合理的
User-Agent,甚至可以随机切换,避免被目标网站识别为爬虫。
内容的提问来源于stack exchange,提问作者phapha pha
相关产品推荐
相关产品推荐

