Python实现多线程下载脚本的示例代码


Posted in Python onApril 03, 2020

0x01 分析

一个简单的多线程下载资源的Python脚本,主要实现部分包含两个类:

Download类:包含download()get_complete_rate()两种方法。

  • download()方法种首先用 urlopen() 方法打开远程资源并通过 Content-Length获取资源的大小,然后计算每个线程应该下载网络资源的大小及对应部分吗,最后依次创建并启动多个线程来下载网络资源的指定部分。
  • get_complete_rate()则是用来返回已下载的部分占全部资源大小的比例,用来回显进度。

ThreadDownload类:该线程类继承了threading.Thread类,包含了一个run()方法。

run()方法主要负责每个线程读取网络数据并写入本地。

0x02 代码

# 文件名:ThreadDownload.py
import threading
from urllib.request import *


class Download:
  def __init__(self, link, file_path, thread_num):
    # 下载路径
    self.link = link
    # 保存位置
    self.file_path = file_path
    # 使用多少线程
    self.thread_num = thread_num
    # 初始化threads数组
    self.threads = []

  def download(self):
    req = Request(url=self.link, method='GET')
    req.add_header('Accept', '*/*')
    req.add_header('Charset', 'UTF-8')
    req.add_header('Connection', 'Keep-Alive')
    f = urlopen(req)
    # 获取要下载的文件的大小
    self.file_size = int(dict(f.headers).get('Content-Length', 0))
    f.close()
    # 计算每个线程要下载的资源的大小
    current_part_size = self.file_size // self.thread_num + 1
    for i in range(self.thread_num):
      # 计算每个线程下载的开始位置
      start_pos = i * current_part_size
      # 每个线程使用一个wb模式打开的文件进行下载
      t = open(self.file_path, 'wb')
      t.seek(start_pos, 0)
      # 创建下载线程
      td = ThreadDownload(self.link, start_pos, current_part_size, t)
      self.threads.append(td)
      td.start()

  # 获下载的完成百分比
  def get_complete_rate(self):
    sum_size = 0
    for i in range(self.thread_num):
      sum_size += self.threads[i].length
    return sum_size / self.file_size

class ThreadDownload(threading.Thread):
  def __init__(self, link, start_pos, current_part_size, current_part):
    super().__init__() 
    # 下载路径
    self.link = link
    # 当前线程的下载位置
    self.start_pos = start_pos
    # 定义当前线程负责下载的文件大小
    self.current_part_size = current_part_size
    # 当前文件需要下载的文件快
    self.current_part = current_part
    # 定义该线程已经下载的字节数
    self.length = 0
  
  def run(self):
    req = Request(url = self.link, method='GET')
    req.add_header('Accept', '*/*')
    req.add_header('Charset', 'UTF-8')
    req.add_header('Connection', 'Keep-Alive')

    f = urlopen(req)
    # 跳过self.start_pos个字节,表明该线程只负责下载自己负责的那部分内容
    for i in range(self.start_pos):
      f.read(1)
    # 读取网络数据,并写入本地
    while self.length < self.current_part_size:
      data = f.read(1024)
      if data is None or len(data) <= 0:
        break
      self.current_part.write(data)
      # 累计该线程下载的总大小
      self.length += len(data)
    self.current_part.close()
    f.close()
#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
# 文件名:thread_download-master.py

import sys
import time

from ThreadDownload import *


def show_process(dl):
  while dl.get_complete_rate() < 1:
    complete_rate = int(dl.get_complete_rate()*100) 
    print('\r' + '下载中···(已下载' + str(complete_rate) + '%)', end='', flush=True)
    time.sleep(0.01)


def main():
  try:  
    Link = input('[+]' + 'Link: ')
    file_path = input('[+]' + 'File Path: ')
    thread_number = input('[+]' + 'Thread Number: ')
    thread_number = int(thread_number)
    dl = Download(Link, file_path, thread_number)
    dl.download()
    print('\n开始下载!')
    show_process(dl)
    print('\r' + '下载中···(已下载' + '100%)', end='', flush=True)
    print('\n下载完成!')
  except Exception:
      print('Parameter Setting Error')
      sys.exit(1)

if __name__=='__main__':
    main()

0x03 运行结果

下载歌曲《男孩》为例,下载到./Download/目录下并命名为男孩.mp3,设置5个线程:

Python实现多线程下载脚本的示例代码

Python实现多线程下载脚本的示例代码

下载成功:

Python实现多线程下载脚本的示例代码

到此这篇关于Python实现多线程下载脚本的示例代码的文章就介绍到这了,更多相关Python 多线程下载脚本内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python获取糗百图片代码实例
Dec 18 Python
在Django框架中运行Python应用全攻略
Jul 17 Python
Python中常见的数据类型小结
Aug 29 Python
对pytorch网络层结构的数组化详解
Dec 08 Python
python样条插值的实现代码
Dec 17 Python
python游戏开发之视频转彩色字符动画
Apr 26 Python
Python实现打砖块小游戏代码实例
May 18 Python
Django User 模块之 AbstractUser 扩展详解
Mar 11 Python
python中可以声明变量类型吗
Jun 18 Python
关于Kotlin中SAM转换的那些事
Sep 15 Python
python pymysql库的常用操作
Oct 16 Python
python开发人人对战的五子棋小游戏
May 02 Python
python实现将两个文件夹合并至另一个文件夹(制作数据集)
Apr 03 #Python
pycharm安装及如何导入numpy
Apr 03 #Python
解决pyPdf和pyPdf2在合并pdf时出现异常的问题
Apr 03 #Python
Python利用PyPDF2库获取PDF文件总页码实例
Apr 03 #Python
Numpy 理解ndarray对象的示例代码
Apr 03 #Python
python计算Content-MD5并获取文件的Content-MD5值方式
Apr 03 #Python
Django自定义列表 models字段显示方式
Apr 03 #Python
You might like
PHP的FTP学习(一)
2006/10/09 PHP
PHP简洁函数小结
2011/08/12 PHP
windows下配置php5.5开发环境及开发扩展
2014/12/25 PHP
PHP实现微信退款的方法示例
2019/03/26 PHP
基于Laravel 5.2 regex验证的正确写法
2019/09/29 PHP
laravel 多图上传及图片的存储例子
2019/10/14 PHP
laravel ORM关联关系中的 with和whereHas用法
2019/10/16 PHP
深入理解JavaScript系列(13) This? Yes,this!
2012/01/18 Javascript
ie8 不支持new Date(2012-11-10)问题的解决方法
2013/07/31 Javascript
js左侧三级菜单导航实例代码
2013/09/13 Javascript
使用JS读秒使用示例
2013/09/21 Javascript
JS创建自定义表格具体实现
2014/02/11 Javascript
让table变成exls的示例代码
2014/03/24 Javascript
JQuery报错Uncaught TypeError: Illegal invocation的处理方法
2015/03/13 Javascript
js定义类的几种方法(推荐)
2016/06/08 Javascript
微信小程序 本地存储及登录页面处理实例详解
2017/01/11 Javascript
一种angular的方法级的缓存注解(装饰器)
2018/03/13 Javascript
.vue文件 加scoped 样式不起作用的解决方法
2018/05/28 Javascript
layui实现table加载的示例代码
2018/08/14 Javascript
解决vue单页路由跳转后scrollTop的问题
2018/09/03 Javascript
[00:32]DOTA2上海特级锦标赛 Ehome战队宣传片
2016/03/03 DOTA
[00:52]DOTA2第二届亚洲邀请赛预选赛宣传片
2017/01/13 DOTA
Python实现备份文件实例
2014/09/16 Python
Python中使用hashlib模块处理算法的教程
2015/04/28 Python
Python对象类型及其运算方法(详解)
2017/07/05 Python
pandas对指定列进行填充的方法
2018/04/11 Python
对numpy中的where方法嵌套使用详解
2018/10/31 Python
从DataFrame中提取出Series或DataFrame对象的方法
2018/11/10 Python
postman传递当前时间戳实例详解
2019/09/14 Python
python实现超市商品销售管理系统
2019/11/22 Python
Python用access判断文件是否被占用的实例方法
2020/12/17 Python
Html5 实现微信分享及自定义内容的流程
2019/08/20 HTML / CSS
如何写出高质量、高性能的MySQL查询
2014/11/17 面试题
寄语是什么意思
2014/04/10 职场文书
竞选班干部演讲稿300字
2014/08/20 职场文书
2014年党员评议表自我评价
2014/09/27 职场文书