多线程下载nginx站点目录下文件

代码如下

import os
import time
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
from concurrent.futures import ThreadPoolExecutor, as_completed 
from tqdm import tqdm

base_url = ""  # 要下载文件的基础URL
download_dir = ""  # 保存下载文件的目录
max_workers = 10  # 最大并发数

# 下载单个文件
def download_file(file_url, download_dir):
    if not os.path.exists(download_dir):
        os.makedirs(download_dir)

    file_name = file_url.split('/')[-1]  # 提取文件名
    file_path = os.path.join(download_dir, file_name)

    if os.path.isdir(file_path):
        print(f"错误:路径 {file_path} 是一个目录,无法作为文件保存!")
        return

    # 如果文件不存在则开始下载
    if not os.path.exists(file_path): 
        with requests.get(file_url, stream=True) as r:
            r.raise_for_status()  # 确保请求成功
            total_size = int(r.headers.get('content-length', 0))  # 获取文件大小
            with open(file_path, 'wb') as f, tqdm(
                    desc=file_path,
                    total=total_size,
                    unit='B',
                    unit_scale=True,
                    unit_divisor=1024
            ) as bar:
                for chunk in r.iter_content(chunk_size=1024):
                    if chunk:
                        f.write(chunk)
                        bar.update(len(chunk))
    else:
        print(f"文件 {file_path} 已存在,跳过下载。")

# 获取目录中的所有文件和子目录链接
def get_links(url):
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')

    files = []  # 存放文件链接
    subdirs = []  # 存放子目录链接

    for link in soup.find_all('a'):
        href = link.get('href')
        if href not in ['../', '/']:  # 排除上级目录链接
            full_url = urljoin(url, href)  # 构建完整URL
            if href.endswith('/'):
                subdirs.append(full_url)  # 是子目录则添加到子目录列表
            else:
                files.append(full_url)  # 是文件则添加到文件列表

    return files, subdirs

# 并发下载文件和子目录中的文件
def download_concurrently(base_url, download_dir):
    files, subdirs = get_links(base_url)

    if not subdirs:  # 如果没有子目录,只顺序下载文件
        print(f"检测到目录下全是文件,顺序下载...")
        for file_url in files:
            download_file(file_url, download_dir)
    else:
        print(f"检测到有子目录,进行并发下载...")
        with ThreadPoolExecutor(max_workers=max_workers) as executor:
            futures = []
            for subdir in subdirs:
                subdir_name = subdir.split('/')[-2]
                subdir_path = os.path.join(download_dir, subdir_name)

                # 避免文件和目录同名冲突
                if os.path.isfile(subdir_path):
                    print(f"错误:路径 {subdir_path} 已存在且是文件,无法创建为目录!")
                    continue

                futures.append(executor.submit(download_files, subdir, subdir_path))

            # 顺序下载当前目录下的文件
            for file_url in files:
                futures.append(executor.submit(download_file, file_url, download_dir))

            # 显示并发任务的进度
            for future in as_completed(futures):
                try:
                    future.result()
                except Exception as e:
                    print(f"下载出错: {e}")

# 递归下载子目录中的文件
def download_files(url, download_dir):
    files, subdirs = get_links(url)

    if not os.path.exists(download_dir):
        os.makedirs(download_dir)

    for file_url in files:
        download_file(file_url, download_dir)

    for subdir in subdirs:
        subdir_name = subdir.split('/')[-2]
        subdir_path = os.path.join(download_dir, subdir_name)

        if os.path.isfile(subdir_path):
            print(f"错误:路径 {subdir_path} 已存在且是文件,无法创建为目录!")
            continue

        download_files(subdir, subdir_path)

if __name__ == "__main__":
    start_time = time.time()  # 记录开始时间
    download_concurrently(base_url, download_dir)
    end_time = time.time()  # 记录结束时间

    total_time = end_time - start_time
    print(f"总下载时间: {total_time:.2f} 秒")

说明

脚本用于从一个目录中下载文件,并且支持递归处理子目录。它使用了concurrent.futures库来实现多线程并发下载,从而提高下载速度。脚本的主要功能包括:

  1. 下载单个文件:使用requests模块获取文件,配合tqdm显示进度条。
  2. 获取目录链接:通过解析HTML页面,提取当前目录下的所有文件和子目录。
  3. 并发下载:如果有子目录,则创建线程池并发处理子目录和文件。
  4. 递归下载:对于每个子目录,递归下载其中的文件。
posted @ 2024-09-18 16:26  &UnstopPable  阅读(36)  评论(0编辑  收藏  举报