热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python百余行代码能做什么?能实现一个类IDM下载程序!

文章目录1.前言2.环境3.效果4.实现步骤4.1导包4.2初始化4.3获取下载4.4终端打印4.5执行5.运行方法与效果5.1运行方法5.2效果6.思考与不足6.1思考6.2不足

文章目录

  • 1.前言
  • 2.环境
  • 3.效果
  • 4.实现步骤
    • 4.1 导包
    • 4.2 初始化
    • 4.3 获取下载
    • 4.4 终端打印
    • 4.5 执行
  • 5. 运行方法与效果
    • 5.1 运行方法
    • 5.2 效果
  • 6.思考与不足
    • 6. 1 思考
    • 6.2 不足
  • 7. 附录
    • 7.1 程序下载
1.前言

很久没写博客了。某天在b站上面看到的使用python的多线程文件IO操作机制,突发奇想来实现下

人们总有这样的困扰,使用有名的工具下载大文件的时候,总会限速(比如某度云),使用迅雷下载BT文件的时候又不得不被广告困扰。使用IDM这种无限制下载软件的时候 ,又会弹出各种注册弹窗的问题。故笔者这里使用python的多线程文件IO下载,百行代码左右实现一个快速下载工具。

2.环境
  • win10
  • python3.6
  • Pycharm2017
3.效果

使用python实现的类IDM下载器,具有不限制网速(取决于网速带宽),以及多线程下载的特点。

《python百余行代码能做什么?能实现一个类IDM下载程序!》

4.实现步骤

4.1 导包

实现这个功能主要用到的是python中的Request库,以及线程处理库,基于python对文件IO操作的友好性,使用较少的代码实现了上述下载的功能。

import os
import time
import sys
from requests import get,head
from concurrent.futures import ThreadPoolExecutor,wait

如果运行出错。可能需要安装相关包

4.2 初始化

新定义一个下载类,对其进行初始化,声明下载链接,线程数以及另存为的文件名

def __init__(self, url, nums, file):
self.url = url # url链接
self.num = nums # 线程数
self.name = file # 文件名字
self.getSize = 0 # 大小
self.info = {
'main': {
'progress': 0, # 主线程状态
'speed': '' # 下载速度
},
'sub': {
'progress': [0 for i in range(nums)], # 子线程状态
'stat': [1 for i in range(nums)] # 下载状态
}
}
r = head(self.url)
# 状态码显示302则迭代寻找文件
while r.status_code == 302:
self.url = r.headers['Location']
print("此url已重定向至{}".format(self.url))
r = head(self.url)
self.size = int(r.headers['Content-Length'])
print('该文件大小为: {} bytes'.format(self.size))

  • HTTP中返回302表示文件重定向,可能出现的原因是下载文件链接失效,这时候主需要重新选择一个可以在游览器中就可以下载的文件连接即可

4.3 获取下载

定义一个下载方法,主要使用Request库,以及多线程的方式,由于python对文件I/O为密集型操作,较为友好,因此使用此种方式为直接获取的形式。

def down(self, start, end, thread_id, chunk_size = 10240):
raw_start = start
for _ in range(10):
try:
headers = { 'Range': 'bytes={}-{}'.format(start, end)}
r = get(self.url, headers=headers, timeout=10, stream=True) # 获取
print(f"线程{thread_id}连接成功")
size = 0
with open(self.name, "rb+") as fp:
fp.seek(start)
for chunk in r.iter_content(chunk_size=chunk_size):
if chunk:
self.getSize += chunk_size
fp.write(chunk)
start += chunk_size
size += chunk_size
progress = round(size / (end - raw_start) * 100, 2)
self.info['sub']['progress'][thread_id - 1] = progress
self.info['sub']['stat'][thread_id - 1] = 1
return
except Exception as error:
print(error)
self.down(start, end, thread_id)
print(f"{start}-{end}, 下载失败")
self.info['sub']['start'][thread_id - 1] = 0

4.4 终端打印

定义一个显示方法,在终端对其但打印下载信息,包括主线程下载速度以及子线程线程数和状态

def show(self):
while True:
speed = self.getSize
time.sleep(0.5)
speed = int((self.getSize - speed) * 2 / 1024)
if speed > 1024:
speed = f"{round(speed / 1024, 2)} M/s"
else:
speed = f"{speed} KB/s"
progress = round(self.getSize / self.size * 100, 2)
self.info['main']['progress'] = progress
self.info['main']['speed'] = speed
print(self.info)
if progress >= 100:
break # end

4.5 执行

定义运行方法,包括对文件IO的处理以及下载判断

def run(self):
# 创建一个要下载的文件
fp = open(self.name, 'wb')
print(f"正在初始化下载文件: {self.name}")
fp.truncate(self.size)
print(f"文件初始化完成")
start_time = time.time()
fp.close()
part = self.size // self.num # 整除
pool = ThreadPoolExecutor(max_workers=self.num + 1)
futures = []
for i in range(self.num):
start = part * i
if i == self.num - 1:
end = self.size
else:
end = start + part - 1
futures.append(pool.submit(self.down, start, end, i + 1))
futures.append(pool.submit(self.show))
print(f"正在使用{self.num}个线程进行下载...")
wait(futures)
end_time = time.time()
speed = int(self.size / 1024 / (end_time - start_time))
if speed > 1024:
speed = f"{round(speed / 1024, 2)} M/s"
else:
speed = f"{speed} KB/s"
print(f"{self.name}下载完成,平均速度: {speed}")

入口函数如下

if __name__ == '__main__':
debug = 1 # 测试情况
if debug:
url = 'http://119.6.237.61:8899/w10.xitongxz.net/202007/DEEP_GHOST_WIN10_X64_V2020_07.iso'
down = Dowmloader(url, 8, os.path.basename(url))
else:
# 命令行执行方式
url = sys.argv[1] # 下载链接
file = sys.argv[2] # 默认保存在项目路径下,文件的名字以文件格式结尾
thread_num = int(sys.argv[3]) # 使用的线程数量
down = Dowmloader(url, thread_num, file)
down.run()
5. 运行方法与效果

5.1 运行方法

运行程序的方式有两种,

  • 直接运行
  • 使用命令行运行

直接运行就是直接在IDE中执行程序。输出为py文件,如上图所示,另外一种就是使用命令行参数的方式,可自行选择仙下载线程和文件名

比如我们的python文件名字为test_demo.py 要下载一个.iso文件,在工程目录下执行如下命令,我这里要下载的文件是一个iso镜像系统,

《python百余行代码能做什么?能实现一个类IDM下载程序!》

将其链接拷贝出来

# python .py文件 链接 文件名 线程数
python test_demo.py '链接' test.iso 8

《python百余行代码能做什么?能实现一个类IDM下载程序!》

5.2 效果

使用这种方式,将取决于自己网速,而不再受限制了,有点香啊

《python百余行代码能做什么?能实现一个类IDM下载程序!》
《python百余行代码能做什么?能实现一个类IDM下载程序!》

6.思考与不足

6. 1 思考

python中对任务的执行方法有两种

  • CPU计算密集型:指CPU计算占主要的任务,CPU一直处于满负荷状态。比如在一个很大的列表中查找元素,复杂的加减乘除等。
  • IO密集型:是指磁盘IO、网络IO占主要的任务,计算量很小。比如请求网页、读写文件等。当然我们在Python中可以利用time中的sleep达到IO密集型任务的目的

因此,在使用爬虫等网页操作的时候,多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序执行效率)。所以python的多线程对IO密集型代码比较友好,而使用多线程时,考虑到计算机硬件结构的负担,线程保持在8个左右最为合适,设置较多的线程加大CPU的负担。

6.2 不足

在执行这个程序的时候,有些功能暂时未能实现,如

  • 该程序暂时不能实现断点续传的功能,只能将程序一直运行下去,知道文件下载完毕
  • 暂时未能将其封装为一个下载界面,提供可视化的下载监控,可能后期会实现下
7. 附录

7.1 程序下载

  • GitHub
  • CSDN

推荐阅读
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 使用圣杯布局模式实现网站首页的内容布局
    本文介绍了使用圣杯布局模式实现网站首页的内容布局的方法,包括HTML部分代码和实例。同时还提供了公司新闻、最新产品、关于我们、联系我们等页面的布局示例。商品展示区包括了车里子和农家生态土鸡蛋等产品的价格信息。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
author-avatar
手机用户2502926901
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有