开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 951|回复: 14
收起左侧

[其它源码] 来一个python 下载模块 支持多任务有回调 有进度 支持同步 ...

[复制链接]
头像被屏蔽
结帖率:100% (4/4)
发表于 2024-5-13 11:36:50 | 显示全部楼层 |阅读模式   安徽省马鞍山市
分享源码
界面截图: -
是否带模块: -
备注说明: -
import os
import requests
import threading
import time


class Downloader:
    def __init__(
        self,
        id,
        completion_callback=None,
        progress_callback=None,
        message_output=None,
        download_dir="cache",
    ):
        self.id = id
        self.file_urls = []
        self.completion_callback = completion_callback
        self.progress_callback = progress_callback
        self.message_output = message_output
        self.download_dir = download_dir
        self.downloaded_files = []
        self.stop_flag = False
        self.session = requests.Session()
        self._create_download_dir()

    def _create_download_dir(self):
        os.makedirs(self.download_dir, exist_ok=True)

    def add_url(self, url, filename, dirname=None):
        self.file_urls.append((url, filename, dirname))

    def start(self, callback=None, params=None):
        download_thread = threading.Thread(
            target=self._download,
            args=(
                callback,
                params,
            ),
        )
        download_thread.start()

    def start_sync(self, callback=None, params=None):
        return self._download(callback, params)

    def stop(self):
        self.stop_flag = True

    def _download(self, callback=None, params=None):
        for url, filename, dirname in self.file_urls:
            if self.stop_flag:
                break
            try:
                self._download_file(url, filename, dirname)
            except Exception as e:
                self._print_message(f"Failed to download {url}: {e}")
                break

        if self.completion_callback:
            sync = self.completion_callback(
                self.id, self.downloaded_files, self.download_dir
            )
            if callback:
                return callback(self.id, sync, params)
        self.session.close()

    def _download_file(self, url, filename, dirname):
        response = self.session.get(url, stream=True)

        total_size = int(response.headers.get("content-length", 0))
        bytes_so_far = 0
        start_time = time.time()

        # Remove trailing slash from self.download_dir if present
        download_dir = self.download_dir.rstrip(os.path.sep)

        # Concatenate paths while ensuring dirname starts with a directory separator
        path = os.path.join(download_dir, dirname.lstrip(os.path.sep) if dirname else "")
        os.makedirs(path, exist_ok=True)

        file_path = os.path.join(path, filename)
        with open(file_path, "wb") as file:
            for chunk in response.iter_content(chunk_size=1024):
                if self.stop_flag:
                    break
                if chunk:
                    file.write(chunk)
                    bytes_so_far += len(chunk)
                    if time.time() - start_time > 1:
                        if self.progress_callback:
                            self.progress_callback(
                                self.id, bytes_so_far, total_size, filename, dirname
                            )
                        start_time = time.time()
        self._print_message(f"{os.path.join(dirname or '', filename)} downloaded from {url}")
        self.downloaded_files.append(file_path)

    def _print_message(self, message):
        if self.message_output:
            self.message_output(message)
        else:
            print(message)


if __name__ == "__main__":

    def handle_download_completion(id, downloaded_files, download_dir):
        print_message(f"All files have been downloaded for download ID: {id}")
        print_message(f"Downloaded files: {downloaded_files}")
        return True

    def handle_progress_update(id, bytes_so_far, total_size, filename, dirname):
        print_message(
            f"Download ID: {id}, downloaded {bytes_so_far} of {total_size} bytes for {dirname} {filename}"
        )

    def print_message(message):
        print(message)

    base = os.path.dirname(__file__)
    cache = os.path.join(base, "static", "cache")
    downloader1 = Downloader(
        22, handle_download_completion, handle_progress_update, print_message, cache
    )

    downloader1.add_url("https://dldir1.qq.com/qqfile/qq/QQNT/a8b6c3ae/QQ9.9.6.20201_x64.exe", "QQSetup.exe")
    def callback(id, state, value):
        print("#callback", id, state,value)
    print(downloader1.start(callback,'is'))




补充内容 (2024-5-15 09:42):
更新了一下_download 下载路径处理规则 并自动处理路径转义 见10楼

点评

有专门的Python版块啊   广东省深圳市  发表于 2024-5-14 00:35

评分

参与人数 3好评 +1 精币 +4 收起 理由
chuanqibuding + 1 + 1 精彩文章希望继续努力
光影魔术 + 2 支持开源~!感谢分享
財財 + 1 感谢分享,很给力!~

查看全部评分


头像被屏蔽
结帖率:100% (4/4)
 楼主| 发表于 2024-5-15 09:40:04 | 显示全部楼层   安徽省马鞍山市
import os
import requests
import threading
import time


class Downloader:
    def __init__(
        self,
        id,
        completion_callback=None,
        progress_callback=None,
        message_output=None,
        download_dir="cache",
    ):
        self.id = id
        self.file_urls = []
        self.completion_callback = completion_callback
        self.progress_callback = progress_callback
        self.message_output = message_output
        self.download_dir = download_dir
        self.downloaded_files = []
        self.stop_flag = False
        self.session = requests.Session()
        self._create_download_dir()

    def _create_download_dir(self):
        os.makedirs(self.download_dir, exist_ok=True)

    def add_url(self, url, filename, dirname=None):
        self.file_urls.append((url, filename, dirname))

    def start(self, callback=None, params=None):
        download_thread = threading.Thread(
            target=self._download,
            args=(
                callback,
                params,
            ),
        )
        download_thread.start()

    def start_sync(self, callback=None, params=None):
        return self._download(callback, params)

    def stop(self):
        self.stop_flag = True

    def _download(self, callback=None, params=None):
        for url, filename, dirname in self.file_urls:
            if self.stop_flag:
                break
            try:
                self._download_file(url, filename, dirname)
            except Exception as e:
                self._print_message(f"Failed to download {url}: {e}")
                break

        if self.completion_callback:
            sync = self.completion_callback(
                self.id, self.downloaded_files, self.download_dir
            )
        self.session.close()
        if callback:
            return callback(self.id, sync, params)

    def _download_file(self, url, filename, dirname):
        response = self.session.get(url, stream=True)
        total_size = int(response.headers.get("content-length", 0))
        bytes_so_far = 0
        start_time = time.time()
        file_path = os.path.join(self.download_dir, dirname or "", filename)
        file_path = os.path.normpath(file_path)
        os.makedirs(os.path.dirname(file_path), exist_ok=True)
        with open(file_path, "wb") as file:
            for chunk in response.iter_content(chunk_size=1024):
                if self.stop_flag:
                    break
                if chunk:
                    file.write(chunk)
                    bytes_so_far += len(chunk)
                    if time.time() - start_time > 1:
                        if self.progress_callback:
                            self.progress_callback(
                                self.id, bytes_so_far, total_size, filename, dirname
                            )
                        start_time = time.time()
        self._print_message(
            f"{os.path.join(dirname or '', filename)} downloaded from {url}"
        )
        self.downloaded_files.append(file_path)

    def _print_message(self, message):
        if self.message_output:
            self.message_output(message)
        else:
            print(message)


if __name__ == "__main__":

    def handle_download_completion(id, downloaded_files, download_dir):
        print_message(f"All files have been downloaded for download ID: {id}")
        print_message(f"Downloaded files: {downloaded_files}")
        return True

    def handle_progress_update(id, bytes_so_far, total_size, filename, dirname):
        print_message(
            f"Download ID: {id}, downloaded {bytes_so_far} of {total_size} bytes for {dirname} {filename}"
        )

    def print_message(message):
        print(message)

    base = os.path.dirname(__file__)
    cache = os.path.join(base, "static", "cache")
    downloader1 = Downloader(
        22, handle_download_completion, handle_progress_update, print_message, cache
    )
    downloader1.add_url(
        "http://192.168.0.201:8998/html/data/download/schedule-88.zip",
        "os\\schedule-1.zip",
    )

    # downloader1.add_url("https://dldir1.qq.com/qqfile/qq/QQNT/a8b6c3ae/QQ9.9.6.20201_x64.exe", "QQSetup.exe")
    def callback(id, state, value):
        print("#callback", id, state, value)

    print(downloader1.start(callback, "is"))
回复 支持 反对

使用道具 举报

签到天数: 7 天

发表于 2024-5-18 04:42:18 | 显示全部楼层   浙江省温州市
感谢分享,很给力!~
回复 支持 反对

使用道具 举报

结帖率:100% (1/1)

签到天数: 15 天

发表于 2024-5-15 14:37:13 | 显示全部楼层   广西壮族自治区柳州市
感谢分享源码
回复 支持 反对

使用道具 举报

头像被屏蔽
结帖率:100% (4/4)
 楼主| 发表于 2024-5-15 09:41:31 | 显示全部楼层   安徽省马鞍山市
lisher 发表于 2024-5-13 12:41
您的代码中存在一些问题,这可能会影响其在实际运行中的表现:

1.print_message函数在Downloader类中被定 ...

使用方法没更新 不过不影响吃饭
回复 支持 反对

使用道具 举报

结帖率:0% (0/2)

签到天数: 25 天

发表于 2024-5-15 08:54:55 | 显示全部楼层   广西壮族自治区玉林市
感谢分享,很给力!~
回复 支持 反对

使用道具 举报

结帖率:80% (4/5)

签到天数: 2 天

发表于 2024-5-14 12:35:14 | 显示全部楼层   山东省潍坊市
已经顶贴,感谢您对论坛的支持!
回复 支持 反对

使用道具 举报

结帖率:0% (0/2)

签到天数: 25 天

发表于 2024-5-14 11:57:07 | 显示全部楼层   广西壮族自治区玉林市
支持开源~!感谢分享
回复 支持 反对

使用道具 举报

结帖率:100% (4/4)

签到天数: 27 天

发表于 2024-5-13 23:21:31 | 显示全部楼层   重庆市重庆市
新技能已get√
回复 支持 反对

使用道具 举报

签到天数: 29 天

发表于 2024-5-13 19:48:38 | 显示全部楼层   广东省揭阳市
新技能已get√
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表