You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用Python的wget库实现Linux中wget -c的断点续传与防重复下载?

实现Python中类似wget -c的续传+避免重复下载功能

我之前也踩过这个坑!Python第三方库wget(就是pip install wget安装的那个)功能比较基础,确实没有直接对应Linux命令wget -c的参数。不过我们可以用更灵活的工具来实现相同的效果——要么用requests库(更简洁),要么用Python标准库urllib(不需要额外安装依赖)。

方法一:用requests库实现(推荐)

这个方法逻辑清晰,代码简洁,还能轻松处理HTTP头和状态码:

import requests
import os

def resume_download(url, save_path):
    # 检查本地文件是否存在,获取已下载大小
    if os.path.exists(save_path):
        downloaded_size = os.path.getsize(save_path)
        # 构建Range请求头,告诉服务器从已下载位置继续发送数据
        headers = {'Range': f'bytes={downloaded_size}-'}
        response = requests.get(url, headers=headers, stream=True)
        
        # 处理响应状态码
        if response.status_code == 416:
            print("文件已经完全下载,无需续传")
            return
        elif response.status_code != 206:
            print(f"续传请求失败(状态码:{response.status_code}),将从头开始下载")
            response = requests.get(url, stream=True)
            downloaded_size = 0
    else:
        # 文件不存在,直接从头下载
        response = requests.get(url, stream=True)
        downloaded_size = 0

    # 计算总文件大小
    total_size = int(response.headers.get('content-length', 0)) + downloaded_size

    # 以追加模式写入文件
    with open(save_path, 'ab') as f:
        for chunk in response.iter_content(chunk_size=1024*1024):  # 1MB块大小
            if chunk:
                f.write(chunk)
                downloaded_size += len(chunk)
                # 可选:打印实时下载进度
                print(f"\r已下载:{downloaded_size}/{total_size} bytes", end="")
    print("\n下载完成!")

# 使用示例
resume_download("https://example.com/your_large_file.zip", "./local_file.zip")

方法二:用标准库urllib实现(无额外依赖)

如果不想安装第三方库,用Python自带的urllib也能实现:

import urllib.request
import os

def resume_download_urllib(url, save_path):
    downloaded_size = 0
    headers = {}

    if os.path.exists(save_path):
        downloaded_size = os.path.getsize(save_path)
        headers['Range'] = f'bytes={downloaded_size}-'
    
    try:
        req = urllib.request.Request(url, headers=headers)
        with urllib.request.urlopen(req) as response:
            # 处理状态码
            if response.getcode() == 416:
                print("文件已经完全下载,无需操作")
                return
            elif response.getcode() != 206 and downloaded_size > 0:
                print("续传失败,将重新下载整个文件")
                req = urllib.request.Request(url)
                response = urllib.request.urlopen(req)
                downloaded_size = 0
            
            total_size = int(response.headers.get('Content-Length', 0)) + downloaded_size
            with open(save_path, 'ab') as f:
                while True:
                    chunk = response.read(1024*1024)  # 1MB块读取
                    if not chunk:
                        break
                    f.write(chunk)
                    downloaded_size += len(chunk)
                    print(f"\r已下载:{downloaded_size}/{total_size} bytes", end="")
        print("\n下载完成!")
    except Exception as e:
        print(f"下载过程出错:{str(e)}")

# 使用示例
resume_download_urllib("https://example.com/your_large_file.zip", "./local_file.zip")

为什么Python的wget库做不到?

第三方wget库的核心功能比较简单,它的download()函数默认会覆盖已存在的文件,或者通过out参数指定保存路径,但没有实现基于HTTP Range头的续传逻辑,所以没法直接实现wget -c的效果。上面两种方法都是手动实现了续传的核心逻辑——检查本地文件大小、发送Range请求、追加写入内容,完美复刻了wget -c的功能。

内容的提问来源于stack exchange,提问作者DevTar

火山引擎 最新活动