Python中requests库在并发太高的情况下报错如何解决

也就开了 32 个线程这样,爬一会就疯狂报错 然后把并发改为 10 之后就可以正常爬了

requests.exceptions.SSLError: EOF occurred in violation of protocol (_ssl.c:645)

还有个问题:爬虫插入 mysql 的策略是什么? 一定数量批量插 还是一条一条插 感觉一条条插在高并发的情况下十分不稳定


Python中requests库在并发太高的情况下报错如何解决
8 回复

貌似是 openssl 的限制?


帖子标题问的是requests库在高并发下报错怎么搞。这个我熟,直接上代码。

核心就两点:一是用连接池复用TCP连接,别每次都新建;二是控制并发数,别一股脑发一堆请求把服务器或自己搞崩了。用requests.Session()配合requests.adapters.HTTPAdapter来调连接池参数,再用concurrent.futuresThreadPoolExecutor来限制线程数,稳得很。

下面是个完整例子,直接抄了改改就能用:

import requests
from requests.adapters import HTTPAdapter
from concurrent.futures import ThreadPoolExecutor, as_completed
from urllib3.util.retry import Retry

# 1. 创建自定义Session,配置连接池和重试策略
session = requests.Session()

# 设置重试策略(可选,但建议加上)
retry_strategy = Retry(
    total=3,  # 总重试次数
    backoff_factor=1,  # 退避因子
    status_forcelist=[429, 500, 502, 503, 504],  # 遇到这些状态码就重试
)
adapter = HTTPAdapter(
    pool_connections=100,   # 连接池大小
    pool_maxsize=100,       # 最大连接数
    max_retries=retry_strategy,
)
session.mount('http://', adapter)
session.mount('https://', adapter)

# 2. 要请求的URL列表
urls = [
    'https://httpbin.org/get?id=1',
    'https://httpbin.org/get?id=2',
    # ... 你的URL列表,可以有几百上千个
]

# 3. 实际的请求函数
def fetch_url(url):
    try:
        # 使用配置好的session,而不是requests.get
        response = session.get(url, timeout=5)
        # 可以根据需要处理响应,这里简单返回状态码和内容长度
        return url, response.status_code, len(response.content)
    except Exception as e:
        return url, f'ERROR: {e}', None

# 4. 使用线程池控制并发数
def main():
    results = []
    # 关键在这里:max_workers控制最大并发线程数,别设太高,比如10-50
    with ThreadPoolExecutor(max_workers=20) as executor:
        # 提交所有任务
        future_to_url = {executor.submit(fetch_url, url): url for url in urls}
        
        # 获取完成的结果
        for future in as_completed(future_to_url):
            result = future.result()
            results.append(result)
            print(f'Completed: {result[0]} -> {result[1]}')
    
    # 处理结果...
    print(f"\nTotal requests: {len(urls)}")
    print(f"Successful: {len([r for r in results if 'ERROR' not in str(r[1])])}")

if __name__ == '__main__':
    main()

重点解释:

  • HTTPAdapterpool_connectionspool_maxsize设大点,让连接能复用。max_retriesRetry对象配置,自动处理429、500这些临时错误。
  • ThreadPoolExecutor(max_workers=20):这是控制并发数的阀门。别瞎设成500,根据你机器和对方服务器的承受能力来,一般20-100够用了。线程太多会吃光资源,报各种连接错误。
  • 一定要用Session:整个程序就用一个session实例,所有请求都通过它发,连接池才能生效。
  • 超时timeout=5必须加,防止某些请求卡死拖垮整个程序。

如果请求量巨大(比如上万),可以考虑用asyncio + aiohttp,那才是为高并发而生的。但requests同步写法简单,加上面这套配置,应对日常几百几千的并发压力不大。

简单说就是调大连接池,用Session,控制好线程数

批量插

pip install ‘requests[security]’

后来我发现 我开并发为 10 的情况下也会报错

试试异步 aiohttp

你好,我也遇到这个问题。请问解决了吗?

安装 requets[security]

回到顶部