Python多线程下载器,文件下载正确,但是无法再Windows上运行

查看:109
本文介绍了Python多线程下载器,文件下载正确,但是无法再Windows上运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

一. 描述问题&上下文环境

想下载QQ.exe到Windows电脑
用了多线程

文件下载正确(大小), 但是为"无效的exe文件"
debug了很久, 没有找到原因

Windows7_64-py2.7.11

Python 2.7.11 |Anaconda 2.5.0 (64-bit)| (default, Jan 29 2016, 14:26:21) [MSC v
1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
Anaconda is brought to you by Continuum Analytics.
Please check out: http://continuum.io/thanks and https://anaconda.org

[Anaconda2] C:\Users\hzm>pip show requests
---
Metadata-Version: 1.1
Name: requests
Version: 2.9.1
Summary: Python HTTP for Humans.
Home-page: http://python-requests.org
Author: Kenneth Reitz
Author-email: me@kennethreitz.com
License: Apache 2.0
Location: c:\anaconda2\lib\site-packages
Requires:

重现: 拷贝以下代码, 并且运行即可

二. 相关代码&重现

from __future__ import absolute_import, unicode_literals

import requests
import threading


class Downloader(object):
    def __init__(self, url, thread_amount, filename, headers=None):
        """构造下载器
        在开始下载前,准备好初始资源

        :param url: 需要下载的url地址
        :param thread_amount: 线程数量
        :param filename: 本地存储文件名
        :param headers: 可以适当添加合适的headers字段
        :return:
        """
        self._url = url
        self._thread_amount = thread_amount
        self.fd = open(filename, 'wb')

        if headers is None:
            self._headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Ge'
                                           'cko) Chrome/50.0.2661.102 Safari/537.36'}

        self._total = int(self.get_total(self._url) )
    def start_download(self):
        """Start download the resource

        步骤:
            获取资源的长度(构造器中已经做好)
            根据长度,线程数量切成一个一个范围(见split)
            开始线程,分配各自任务下载
            合并线程
        :return:
        """
        ranges = self.split()
        thread_list = []

        for i in range(self._thread_amount):
            start, end = ranges[i]  #获取一个范围
            t = threading.Thread(target=self.download, args=(start, end))
            t.start()
            thread_list.append(t)

        for t in thread_list:     #合并每个线程, 有更好的方法,这里不知道如何做
            t.join()

        self.fd.close()

    def get_total(self, url):
        return requests.head(url).headers['Content-Length']

    def split(self):
        """依据线程数量,将total进行切片

        :return: 范围列表, 最后一个范围的end为空. 如 [(0, 10), (11, 20), (21, '') ]
        """
        offset = int(self._total / self._thread_amount)

        ranges = []

        for i in range(self._thread_amount):
            if i == self._thread_amount - 1:
                ranges.append((i * offset, ''))
            else:
                ranges.append((i * offset, (i + 1) * offset))
        return ranges

    def download(self, start, end):
        """下载某一范围的数据,并写入文件

        文件是一直打开的,写入的数据是二进制/文本

        :param start: 开始点
        :param end: 结束点
        :return:
        """
        self._headers['Range'] = 'Bytes=%s-%s' % (start, end)
        self._headers['Accept-Encoding'] = '*'

        response = requests.get(self._url, headers=self._headers)

        self.fd.seek(start)
        self.fd.write(response.content)


if __name__ == '__main__':
    url = 'http://sw.bos.baidu.com/sw-search-sp/software/0fc9db1ea0b/QQ_8.3.18027.0_setup.exe'
    thread_amount = 10
    filename = 'qq-2.exe'
    d = Downloader(url,
                    thread_amount,
                    filename)
    d.start_download()

三. 报错信息

运行代码, 运行QQ.exe文件, 即可看到报错信息

四. 相关截图

五. 已经尝试哪些方法仍然没有解决(附上相关链接)

六.问题简化

解决方案

多线程操作self.fd要加锁
PS 文件大小不对啊 你用代码跑的文件大小和wget直接下载的文件大小差不少啊

这篇关于Python多线程下载器,文件下载正确,但是无法再Windows上运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆