坚果云文件自动下载

坚果云文件下载

使用说明

该脚本用于从坚果云的WebDAV服务中递归下载指定目录及其所有内容,并保存到本地。脚本通过发送PROPFIND请求获取目录结构,然后下载所有文件。用户需要在脚本中配置坚果云的账号、密码、起始路径以及本地保存路径,并且如果超过了坚果云的api 限制会继续请求,并且保存的文件路径和名称和坚果云一致。

个人博客

个人博客直达地址
网站不断完善中里面拥有大量的脚本,并且源码完全开放 欢迎纯白嫖。关注公众私信可免费写脚本

WebDAV获取账号密码的方式

WebDAV获取账号密码的方式直达地址

坚果云限制

  1. 坚果云API请求限制

    • 坚果云api 接口每半小时只能请求1500次
  2. 坚果云下载量限制

    • 坚果云每个月下载的文件大小不能超过2T的数据,如果操作只能联系客服进行重置。

配置步骤

  1. 修改脚本中的配置

    • username: 你的坚果云账号。
    • password: 你的坚果云WebDAV授权密钥。
    • base_url: 需要下载的坚果云文件夹路径。
    • download_dir: 文件下载保存的本地路径。
  2. 运行脚本

    • 确保已经安装所需的Python库:requests, logging, xml.etree.ElementTree, os, time, base64
    • 在终端中运行脚本,脚本会自动递归下载指定目录中的所有文件。
  3. 日志记录

    • 脚本将下载过程中的信息记录在jianguoyun.log日志文件中,便于排查错误。

注意事项

  1. 账户安全

    • 确保usernamepassword的安全,避免在公共场合或代码仓库中暴露这些敏感信息。
    • 建议将脚本中的密码配置部分换成环境变量或安全存储服务来保护敏感信息。
  2. 下载目录

    • 在运行脚本之前,确保download_dir目录存在且有足够的存储空间。
  3. 重试机制

    • 脚本包含重试机制,在网络连接不稳定或其他原因导致下载失败时,会自动重试。默认的重试机制是无限次重试,用户可以根据需求调整max_retries变量。
  4. 递归下载

    • 脚本会递归下载指定目录下的所有文件和子目录,确保download_dir路径设置正确,避免误操作。

代码说明

  • 认证与请求

    • 脚本使用HTTP基本认证方式,生成Base64编码的认证信息,通过Authorization头部发送给坚果云服务器。
    • propfind函数发送PROPFIND请求,用于获取目录和文件信息。
  • 文件下载

    • download_file函数负责下载文件,并将其保存到本地指定路径。如果下载失败,脚本会进行重试。
    • 下载过程中的日志信息将记录在jianguoyun.log文件中,便于追踪下载状态和错误信息。
  • 目录解析与递归下载

    • parse_response函数解析PROPFIND请求的响应内容,提取文件和目录信息。
    • recursive_download函数递归处理目录及其内容,确保所有文件都被正确下载。
import os
import base64
import requests
from xml.etree import ElementTree
import time
import logging

# 配置
username = '自己的坚果云账号'
password = '自己的坚果云KEY'
url = 'https://dav.jianguoyun.com'
base_url = 'https://dav.jianguoyun.com/dav/需要下载的文件夹名称/'  # 初始定义的起始路径
download_dir = './downloads/'  # 自定义下载路径

# 设置日志记录
log_file = 'jianguoyun.log'
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[logging.FileHandler(log_file), logging.StreamHandler()])

# 生成Base64编码的认证信息
auth_str = f"{username}:{password}"
auth_bytes = auth_str.encode('ascii')
auth_base64 = base64.b64encode(auth_bytes).decode('ascii')
headers = {
    'Authorization': f'Basic {auth_base64}'
}

def propfind(url):
    """发送PROPFIND请求以获取目录和文件信息"""
    response = requests.request('PROPFIND', url, headers=headers)
    response.raise_for_status()
    return response.text

def download_file(url, local_path):
    """下载文件,带重试机制"""
    retry_count = 0
    retry_interval = 60  # 初始重试间隔为1分钟
    max_retries = float('inf')  # 无限重试

    while retry_count < max_retries:
        try:
            response = requests.get(url, headers=headers, stream=True)
            response.raise_for_status()
            os.makedirs(os.path.dirname(local_path), exist_ok=True)
            with open(local_path, 'wb') as file:
                for chunk in response.iter_content(chunk_size=8192):
                    file.write(chunk)
            logging.info(f"下载完成: {url}")
            return
        except requests.exceptions.RequestException as e:
            retry_count += 1
            if retry_count == 3:
                retry_interval = 15 * 60  # 如果重试3次后仍失败,则等待15分钟
            elif retry_count > 3:
                retry_interval = 60  # 如果在等待20分钟后仍失败,则每分钟重试一次
            logging.warning(f"下载失败 ({url}),重试 {retry_count}/{max_retries} 次: {e}")
            time.sleep(retry_interval)

    logging.error(f"下载失败且重试次数耗尽: {url}")

def parse_response(response_text):
    """解析PROPFIND响应,提取文件和目录信息"""
    tree = ElementTree.fromstring(response_text)
    namespaces = {'d': 'DAV:'}
    for response in tree.findall('d:response', namespaces):
        href = response.find('d:href', namespaces).text
        displayname = response.find('.//d:displayname', namespaces).text
        resourcetype = response.find('.//d:resourcetype', namespaces)
        is_collection = resourcetype.find('d:collection', namespaces) is not None
        yield href, displayname, is_collection

def recursive_download(base_url, current_url, local_path, visited):
    """递归下载目录及其内容"""
    response_text = propfind(current_url)
    logging.info(f"正在处理目录: {current_url}")
    for href, displayname, is_collection in parse_response(response_text):
        full_url = url.rstrip('/') + href
        local_file_path = os.path.join(local_path, displayname)
        if full_url in visited:
            continue
        visited.add(full_url)
        logging.info(f"正在处理: {full_url}")
        if is_collection:
            recursive_download(base_url, full_url, local_file_path, visited)
        else:
            download_file(full_url, local_file_path)

if __name__ == '__main__':
    visited_urls = set()
    last_successful_url = base_url  # 记录上次成功下载的URL
    recursive_download(base_url, last_successful_url, download_dir, visited_urls)
    logging.info(f"下载完成,文件保存在 {os.path.abspath(download_dir)}")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

脚本小能手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值