You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python批量下载大文件时遇到不完整下载及连接报错的问题求助

使用Python批量下载大文件时遇到不完整下载及连接报错的问题求助

嗨,我最近碰到个批量下载文件的麻烦事,想请大伙帮忙支支招:

我需要从指定URL下载16000+个文件(单个最大1GB),格式涵盖.pdf、.ppt、.doc、.docx、.zip、.jpg、.iso等。自己用requests写了代码,但遇到两个头疼的问题:

  • 有时候能正常下载,但经常只下了26KB就停了,文件完全不完整
  • 时不时会弹出错误:[Errno 10054] An existing connection was forcibly closed by the remote host

我最开始写的代码是这样的:

def download_file(s):
    for row in sheet.iter_rows(min_row=2):
        try:
            url = row[6].value # 从Excel里读取URL
            # 发送GET请求
            response = s.get(url)    
            if response.status_code == 200:    
                with open(save_path, 'wb') as file:
                    file.write(response.content)
        except Exception as e:
            print(f"Error: {e}")


if __name__ == "__main__":
    with requests.session() as s:
        res = s.post(login_url, data=login_data)
        download_file(s)

后来我也尝试过用shutil分块下载,还有手动迭代分块的方式,但问题还是没解决:

import shutil
with requests.get(url, stream=True) as r:
        with open(local_filename, 'wb') as f:
            shutil.copyfileobj(r.raw, f)
response = requests.get(url, stream=True)
with open(book_name, 'wb') as f:
     for chunk in response.iter_content(1024 * 1024 * 2): 
        f.write(chunk)

问题分析与解决方案

我来帮你捋捋问题根源,再给你一套更健壮的处理方案:

为什么会出现这些问题?

  1. 连接被强制关闭(Errno 10054):大概率是服务器检测到你批量请求的频率太高,触发了限流/反爬机制,直接断开了连接;也可能是网络波动导致连接中途中断。
  2. 文件下载不完整:一方面是连接中断后没有重试逻辑,只下载了部分内容就停止;另一方面,直接读取response.content会把整个文件塞进内存,大文件很容易出问题,而且如果服务器没有返回完整响应,也会导致文件残缺。

改进后的代码

这套代码加入了重试机制、浏览器请求头模拟、文件完整性校验、请求频率控制,专门针对批量大文件下载优化:

import requests
import time
import os
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_robust_session():
    # 创建带重试策略的session,应对连接错误和服务器异常
    session = requests.Session()
    retry_strategy = Retry(
        total=3,  # 最多重试3次
        backoff_factor=1,  # 重试间隔依次为1s, 2s, 4s
        status_forcelist=[429, 500, 502, 503, 504],  # 遇到这些状态码自动重试
        allowed_methods=["GET"]  # 只对GET请求重试
    )
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("https://", adapter)
    session.mount("http://", adapter)
    
    # 模拟浏览器请求头,避免被识别为爬虫
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
    })
    return session

def download_single_file(session, url, save_path, chunk_size=2*1024*1024):
    # 跳过已存在的文件,避免重复下载
    if os.path.exists(save_path):
        print(f"[{save_path}] 已存在,跳过")
        return
    
    try:
        # 发送请求,设置超时时间防止卡住
        with session.get(url, stream=True, timeout=30) as response:
            response.raise_for_status()  # 主动抛出HTTP错误(比如404、500)
            
            # 获取文件总大小(服务器返回的话)
            total_size = int(response.headers.get('content-length', 0))
            downloaded_size = 0
            
            with open(save_path, 'wb') as f:
                for chunk in response.iter_content(chunk_size=chunk_size):
                    if chunk:  # 过滤空块
                        f.write(chunk)
                        downloaded_size += len(chunk)
                        # 可选:打印下载进度
                        # print(f"[{save_path}] 已下载: {downloaded_size}/{total_size} bytes", end='\r')
            
            # 校验文件完整性
            if total_size != 0 and downloaded_size != total_size:
                print(f"[{save_path}] 下载不完整,已删除残缺文件")
                os.remove(save_path)
                # 可选:这里可以再加一次重试
                # download_single_file(session, url, save_path)
            else:
                print(f"[{save_path}] 下载完成")
    except Exception as e:
        print(f"[{url}] 下载失败: {str(e)}")
        # 删除可能存在的残缺文件
        if os.path.exists(save_path):
            os.remove(save_path)

if __name__ == "__main__":
    login_url = "你的登录地址"
    login_data = {"username": "你的用户名", "password": "你的密码"}
    # 假设sheet是你已读取好的Excel工作表对象(比如用openpyxl加载)
    # sheet = ... 请自行初始化Excel读取逻辑
    
    with create_robust_session() as s:
        # 先确保登录成功
        login_res = s.post(login_url, data=login_data)
        login_res.raise_for_status()
        print("登录成功")
        
        # 遍历Excel行批量下载
        for row_num, row in enumerate(sheet.iter_rows(min_row=2), start=2):
            url = row[6].value
            if not url:
                print(f"第{row_num}行URL为空,跳过")
                continue
            
            # 从URL提取文件名,生成保存路径
            filename = url.split('/')[-1]
            save_dir = "你的文件保存目录"
            os.makedirs(save_dir, exist_ok=True)  # 确保保存目录存在
            save_path = os.path.join(save_dir, filename)
            
            download_single_file(s, url, save_path)
            
            # 控制请求频率,避免触发服务器限流
            time.sleep(1)

额外小贴士

  1. 日志记录:可以把下载失败的URL写入日志文件,方便后续批量重试或者手动处理
  2. 多线程优化:如果单线程下载太慢,可以用concurrent.futures.ThreadPoolExecutor开少量线程(比如5-10个),但一定要配合time.sleep控制频率,别把服务器惹毛了
  3. 断点续传:对于1GB级的超大文件,可以实现断点续传——检查已下载文件的大小,发送Range请求继续下载剩余部分
  4. 代理IP:如果你的IP被服务器封禁,可以考虑用代理池,但要注意代理的稳定性和合法性

备注:内容来源于stack exchange,提问作者user166013

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 19:27:58