Python BeautifulSoup批量爬取时for循环随机卡住无报错求助
问题根因
- 核心问题是
requests.get()未设置超时参数,遇到网络波动、目标站响应挂起、连接假死时,请求会无限等待,直接阻塞整个循环,这是随机停滞的核心原因。打开Chrome等占带宽/资源的软件会提升连接异常概率,所以会显得卡顿加剧。 - 无自动重试机制,偶发的
ConnectionReset、站点临时错误会直接打断流程,没有容错空间。 - 无请求间隔、未复用连接、未配置常规请求头,高频请求容易触发目标站软限流,表现就是连接无响应。
- 单线程串行逻辑下,单个请求阻塞会卡住整个流程,且IO等待状态下Python无法及时响应键盘中断信号,所以中断内核需要等待很久。
修复方案
直接替换原有逻辑即可,代码如下:
import time import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry from bs4 import BeautifulSoup # 初始化带自动重试的会话 session = requests.Session() # 重试规则:最多重试3次,指数退避间隔,遇到连接重置、服务端错误、限流自动重试 retry_config = Retry( total=3, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504, 403], allowed_methods=["GET"] ) session.mount("http://", HTTPAdapter(max_retries=retry_config)) session.mount("https://", HTTPAdapter(max_retries=retry_config)) # 配置常规浏览器请求头,降低被拦截概率 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" } reviewsoups = [] # 断点位置,首次运行设为0,重启时改成上次中断的索引即可 start_idx = 0 for idx in range(start_idx, len(reviews)): try: # 关键配置:设置超时,连接超时10秒、读取超时30秒,杜绝无限等待 resp = session.get(reviews[idx], headers=headers, timeout=(10, 30)) resp.raise_for_status() reviewsoups.append(BeautifulSoup(resp.text, "html.parser")) print(f"进度:{idx+1}/{len(reviews)}") # 加1-1.5秒随机间隔,避免请求过频被限流 time.sleep(1 + (idx % 2)*0.5) except Exception as e: print(f"第{idx}页爬取失败,错误:{str(e)},跳过继续") reviewsoups.append(None) time.sleep(2) continue
关键改动说明:
- 强制给所有请求配置
timeout参数:从根源解决无限等待卡死的问题,无论出现什么网络异常,最多等待30秒就会触发超时抛出错误,不会阻塞整个流程。 - 会话复用+自动重试:偶发的连接重置、服务端临时故障、限流都会自动按退避间隔重试,不需要手动重启程序。
- 异常捕获+进度打印:单页爬取失败不会中断整个循环,控制台实时输出进度,不需要全程值守判断是否卡住。
- 预留断点参数:如果程序意外退出,修改
start_idx参数即可从中断位置继续爬取,不需要从头开始。
大规模爬取优化建议
- 数据量过万时,不要把所有解析结果存在内存列表里,边爬边写入本地文件/数据库,避免内存占满导致系统假死。
- 可以把串行逻辑改成5并发以内的多线程/异步协程模式,爬取效率能提升数倍,注意控制并发频率,不要触发站点反爬。
- 如果运行时开其他软件卡顿明显,可以给Python进程设置较低的资源优先级,避免和其他软件抢带宽、CPU资源。
内容的提问来源于stack exchange,提问作者Tous
相关产品推荐
相关产品推荐

