Python写的一个优美的下载器

没有废话,直接上代码

#!/bin/python3
# author: lidawei
# create: 2016-07-11
# version: 1.0
# 功能说明:
#     从指定的URL将文件取回本地
#####################################################

import http.client
import os
import threading
import time
import logging
import unittest
from queue import Queue
from urllib.parse import urlparse

logging.basicConfig(level = logging.DEBUG,  
                    format = '%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',  
                    datefmt = '%a, %d %b %Y %H:%M:%S',  
                    filename = 'Downloader_%s.log' % (time.strftime('%Y-%m-%d')),  
                    filemode = 'a')

class Downloader(object):
    '''文件下载器'''
    url = ''
    filename = ''

    def __init__(self, full_url_str, filename):
        '''初始化'''
        self.url = urlparse(full_url_str)
        self.filename = filename

    def download(self):
        '''执行下载,返回True或False'''
        if self.url == '' or self.url == None or self.filename == '' or self.filename == None:
            logging.error('Invalid parameter for Downloader')
            return False

        successed = False
        conn = None
        if self.url.scheme == 'https':
            conn = http.client.HTTPSConnection(self.url.netloc)
        else:
            conn = http.client.HTTPConnection(self.url.netloc)
        conn.request('GET', self.url.path)
        response = conn.getresponse()
        if response.status == 200:
            total_size = response.getheader('Content-Length')
            total_size = (int)(total_size)
            if total_size > 0:
                finished_size = 0
                file = open(self.filename, 'wb')
                if file:
                    progress = Progress()
                    progress.start()
                    while not response.closed:
                        buffers = response.read(1024)
                        file.write(buffers)

                        finished_size += len(buffers)
                        progress.update(finished_size, total_size)
                        if finished_size >= total_size:
                            break
                    # ... end while statment
                    file.close()
                    progress.stop()
                    progress.join()
                else:
                    logging.error('Create local file %s failed' % (self.filename))
                # ... end if statment
            else:
                logging.error('Request file %s size failed' % (self.filename))
            # ... end if statment
        else:
            logging.error('HTTP/HTTPS request failed, status code:%d' % (response.status))
        # ... end if statment
        conn.close()

        return successed
    # ... end download() method
# ... end Downloader class

class DataWriter(threading.Thread):
    filename = ''
    data_dict = {'offset' : 0, 'buffers_byte' : b''} 
    queue = Queue(128)
    __stop = False

    def __init__(self, filename):
        self.filename = filename
        threading.Thread.__init__(self)

    #Override
    def run(self):
        while not self.__stop:
            self.queue.get(True, 1)

    def put_data(data_dict):
        '''将data_dict的数据放入队列,data_dict是一个字典,有两个元素:offset是偏移量,buffers_byte是二进制字节串'''
        self.queue.put(data_dict)

    def stop(self):
        self.__stop = True

class Progress(threading.Thread):
    interval = 1
    total_size = 0
    finished_size = 0
    old_size = 0
    __stop = False

    def __init__(self, interval = 0.5):
        self.interval = interval
        threading.Thread.__init__(self)

    #Override
    def run(self):
        # logging.info('       Total     Finished     Percent        Speed')
        print('       Total     Finished     Percent        Speed')
        while not self.__stop:
            time.sleep(self.interval)
            if self.total_size > 0:
                percent = self.finished_size / self.total_size * 100
                speed = (self.finished_size - self.old_size) / self.interval
                msg = '%12d %12d %10.2f%% %12d' % (self.total_size, self.finished_size, percent, speed)
                # logging.info(msg)
                print(msg)

                self.old_size = self.finished_size
            else:
                logging.error('Total size is zero')
        # ... end while statment
    # ... end run() method

    def stop(self):
        self.__stop = True

    def update(self, finished_size, total_size):
        self.finished_size = finished_size
        self.total_size = total_size

class TestDownloaderFunctions(unittest.TestCase):

	def setUp(self):
		print('setUp')

	def test_download(self):
	    url = 'http://dldir1.qq.com/qqfile/qq/QQ8.4/18376/QQ8.4.exe'
	    filename = 'QQ8.4.exe'
	    dl = Downloader(url, filename)
	    dl.download()

	def tearDown(self):
		print('tearDown')

if __name__ == '__main__':
	unittest.main()

这是测试结果:


  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

互联网速递520

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

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

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

打赏作者

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

抵扣说明:

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

余额充值