コード例 #1
0
    def download(self,
                 file_url: str,
                 goal_path: str = None,
                 rename: str = None,
                 file_exists: str = 'rename',
                 show_msg: bool = False,
                 **kwargs) -> tuple:
        """下载一个文件                                                                   \n
        :param file_url: 文件url
        :param goal_path: 存放路径
        :param rename: 重命名文件,可不写扩展名
        :param file_exists: 若存在同名文件,可选择 'rename', 'overwrite', 'skip' 方式处理
        :param show_msg: 是否显示下载信息
        :param kwargs: 连接参数
        :return: 下载是否成功(bool)和状态信息(成功时信息为文件路径)的元组
        """
        # 生成的response不写入self._response,是临时的
        goal_path = goal_path or OptionsManager().get_value(
            'paths', 'global_tmp_path')
        if not goal_path:
            raise IOError('No path specified.')

        kwargs['stream'] = True
        if 'timeout' not in kwargs:
            kwargs['timeout'] = 20

        r, info = self._make_response(file_url, mode='get', **kwargs)
        if not r:
            if show_msg:
                print(info)
            return False, info
        # -------------------获取文件名-------------------
        # header里有文件名,则使用它,否则在url里截取,但不能保证url包含文件名
        if 'Content-disposition' in r.headers:
            file_name = r.headers['Content-disposition'].split('"')[1].encode(
                'ISO-8859-1').decode('utf-8')
        elif os_PATH.basename(file_url):
            file_name = os_PATH.basename(file_url).split("?")[0]
        else:
            file_name = f'untitled_{time()}_{randint(0, 100)}'

        file_name = re_SUB(r'[\\/*:|<>?"]', '', file_name).strip()
        if rename:  # 重命名文件,不改变扩展名
            rename = re_SUB(r'[\\/*:|<>?"]', '', rename).strip()
            ext_name = file_name.split('.')[-1]
            if rename.lower().endswith(
                    f'.{ext_name}'.lower()) or ext_name == file_name:
                full_name = rename
            else:
                full_name = f'{rename}.{ext_name}'
        else:
            full_name = file_name

        goal_Path = Path(goal_path)
        goal_path = ''
        for key, i in enumerate(goal_Path.parts):  # 去除路径中的非法字符
            goal_path += goal_Path.drive if key == 0 and goal_Path.drive else re_SUB(
                r'[*:|<>?"]', '', i).strip()
            goal_path += '\\' if i != '\\' and key < len(
                goal_Path.parts) - 1 else ''

        goal_Path = Path(goal_path)
        goal_Path.mkdir(parents=True, exist_ok=True)
        goal_path = goal_Path.absolute()
        full_path = Path(f'{goal_path}\\{full_name}')

        if full_path.exists():
            if file_exists == 'skip':
                return False, 'A file with the same name already exists.'
            elif file_exists == 'overwrite':
                pass
            elif file_exists == 'rename':
                full_name = get_available_file_name(goal_path, full_name)
                full_path = Path(f'{goal_path}\\{full_name}')
            else:
                raise ValueError(
                    "Argument file_exists can only be 'skip', 'overwrite', 'rename'."
                )

        if show_msg:  # 打印要下载的文件
            print(full_name if file_name ==
                  full_name else f'{file_name} -> {full_name}')
            print(f'Downloading to: {goal_path}')

        # -------------------开始下载-------------------
        # 获取远程文件大小
        file_size = int(r.headers['Content-Length']
                        ) if 'Content-Length' in r.headers else None
        downloaded_size, download_status = 0, False  # 已下载文件大小和下载状态
        try:
            with open(str(full_path), 'wb') as tmpFile:
                for chunk in r.iter_content(chunk_size=1024):
                    if chunk:
                        tmpFile.write(chunk)
                        if show_msg and file_size:  # 如表头有返回文件大小,显示进度
                            downloaded_size += 1024
                            rate = downloaded_size / file_size if downloaded_size < file_size else 1
                            print('\r {:.0%} '.format(rate), end="")
        except Exception as e:
            download_status, info = False, f'Download failed.\n{e}'
        else:
            download_status, info = (
                False,
                'File size is 0.') if full_path.stat().st_size == 0 else (
                    True, 'Success.')
        finally:
            # 删除下载出错文件
            if not download_status and full_path.exists():
                full_path.unlink()
            r.close()
        # -------------------显示并返回值-------------------
        if show_msg:
            print(info)
        info = f'{goal_path}\\{full_name}' if download_status else info
        return download_status, info
コード例 #2
0
    def download(self,
                 file_url: str,
                 goal_path: str = None,
                 rename: str = None,
                 file_exists: str = 'rename',
                 post_data: dict = None,
                 show_msg: bool = False,
                 show_errmsg: bool = False,
                 **kwargs) -> tuple:
        """下载一个文件                                                                   \n
        :param file_url: 文件url
        :param goal_path: 存放路径
        :param rename: 重命名文件,可不写扩展名
        :param file_exists: 若存在同名文件,可选择 'rename', 'overwrite', 'skip' 方式处理
        :param show_msg: 是否显示下载信息
        :param show_errmsg: 是否抛出和显示异常
        :param kwargs: 连接参数
        :return: 下载是否成功(bool)和状态信息(成功时信息为文件路径)的元组
        """
        # 生成的response不写入self._response,是临时的
        goal_path = goal_path or OptionsManager().get_value(
            'paths', 'global_tmp_path')
        if not goal_path:
            raise IOError('No path specified.')

        kwargs['stream'] = True
        if 'timeout' not in kwargs:
            kwargs['timeout'] = 20

        if not post_data:
            r, info = self._make_response(file_url,
                                          mode='get',
                                          show_errmsg=show_errmsg,
                                          **kwargs)
        else:
            r, info = self._make_response(file_url,
                                          mode='post',
                                          data=post_data,
                                          show_errmsg=show_errmsg,
                                          **kwargs)
        if r is None:
            if show_msg:
                print(info)
            return False, info
        if not r.ok:
            if show_errmsg:
                raise ConnectionError(f'Status code: {r.status_code}.')
            return False, f'Status code: {r.status_code}.'

        # -------------------获取文件名-------------------
        file_name = ''
        content_disposition = tuple(x for x in r.headers
                                    if x.lower() == 'content-disposition')
        if content_disposition:  # header里有文件名,则使用它
            file_name = r.headers[content_disposition[0]].encode(
                'ISO-8859-1').decode('utf-8')
            file_name = re.search(r'filename *= *"?([^";]+)', file_name)
            if file_name:
                file_name = file_name.group(1)
            if file_name[0] == file_name[-1] == "'":
                file_name = file_name.strip("'")
        if not file_name and os_PATH.basename(file_url):  # 在url里获取文件名
            file_name = os_PATH.basename(file_url).split("?")[0]
        if not file_name:  # 找不到则用时间和随机数生成文件名
            file_name = f'untitled_{time()}_{randint(0, 100)}'
        file_name = re_SUB(r'[\\/*:|<>?"]', '', file_name).strip()  # 去除非法字符
        file_name = parse.unquote(file_name)

        # -------------------重命名文件名-------------------
        if rename:  # 重命名文件,不改变扩展名
            rename = re_SUB(r'[\\/*:|<>?"]', '', rename).strip()
            ext_name = file_name.split('.')[-1]
            if '.' in rename or ext_name == file_name:
                full_name = rename
            else:
                full_name = f'{rename}.{ext_name}'
        else:
            full_name = file_name

        # -------------------生成路径-------------------
        goal_Path = Path(goal_path)
        goal_path = ''
        for key, i in enumerate(goal_Path.parts):  # 去除路径中的非法字符
            goal_path += goal_Path.drive if key == 0 and goal_Path.drive else re_SUB(
                r'[*:|<>?"]', '', i).strip()
            goal_path += '\\' if i != '\\' and key < len(
                goal_Path.parts) - 1 else ''
        goal_Path = Path(goal_path)
        goal_Path.mkdir(parents=True, exist_ok=True)
        goal_path = goal_Path.absolute()
        full_path = Path(f'{goal_path}\\{full_name}')

        if full_path.exists():
            if file_exists == 'skip':
                return False, 'A file with the same name already exists.'
            elif file_exists == 'overwrite':
                pass
            elif file_exists == 'rename':
                full_name = get_available_file_name(goal_path, full_name)
                full_path = Path(f'{goal_path}\\{full_name}')
            else:
                raise ValueError(
                    "Argument file_exists can only be 'skip', 'overwrite', 'rename'."
                )

        # -------------------打印要下载的文件-------------------
        if show_msg:
            print(full_name if file_name ==
                  full_name else f'{file_name} -> {full_name}')
            print(f'Downloading to: {goal_path}')

        # -------------------开始下载-------------------
        # 获取远程文件大小
        content_length = tuple(x for x in r.headers
                               if x.lower() == 'content-length')
        file_size = int(r.headers[content_length]) if content_length else None
        downloaded_size, download_status = 0, False  # 已下载文件大小和下载状态
        try:
            with open(str(full_path), 'wb') as tmpFile:
                for chunk in r.iter_content(chunk_size=1024):
                    if chunk:
                        tmpFile.write(chunk)
                        if show_msg and file_size:  # 如表头有返回文件大小,显示进度
                            downloaded_size += 1024
                            rate = downloaded_size / file_size if downloaded_size < file_size else 1
                            print('\r {:.0%} '.format(rate), end="")
        except Exception as e:
            if show_errmsg:
                raise ConnectionError(e)
            download_status, info = False, f'Download failed.\n{e}'
        else:
            if full_path.stat().st_size == 0:
                if show_errmsg:
                    raise ValueError('File size is 0.')
                download_status, info = False, 'File size is 0.'
            else:
                download_status, info = True, 'Success.'
        finally:
            if not download_status and full_path.exists():
                full_path.unlink()  # 删除下载出错文件
            r.close()

        # -------------------显示并返回值-------------------
        if show_msg:
            print(info)
        info = f'{goal_path}\\{full_name}' if download_status else info
        return download_status, info
コード例 #3
0
        def do(url: str,
               goal: str,
               new_name: str = None,
               exists: str = 'rename',
               data: dict = None,
               msg: bool = False,
               errmsg: bool = False,
               **args) -> tuple:
            args['stream'] = True

            if 'timeout' not in args:
                args['timeout'] = 20

            mode = 'post' if data else 'get'
            # 生成的response不写入self._response,是临时的
            r, info = self._make_response(url,
                                          mode=mode,
                                          data=data,
                                          show_errmsg=errmsg,
                                          **args)

            if r is None:
                if msg:
                    print(info)

                return False, info

            if not r.ok:
                if errmsg:
                    raise ConnectionError(f'Status code: {r.status_code}.')

                return False, f'Status code: {r.status_code}.'

            # -------------------获取文件名-------------------
            file_name = ''
            content_disposition = r.headers.get('content-disposition')

            # 使用header里的文件名
            if content_disposition:
                file_name = r.headers[content_disposition[0]].encode(
                    'ISO-8859-1').decode('utf-8')
                file_name = re.search(r'filename *= *"?([^";]+)', file_name)

                if file_name:
                    file_name = file_name.group(1)

                    if file_name[0] == file_name[-1] == "'":
                        file_name = file_name[1:-1]

            # 在url里获取文件名
            if not file_name and os_PATH.basename(url):
                file_name = os_PATH.basename(url).split("?")[0]

            # 找不到则用时间和随机数生成文件名
            if not file_name:
                file_name = f'untitled_{time()}_{randint(0, 100)}'

            # 去除非法字符
            file_name = re_SUB(r'[\\/*:|<>?"]', '', file_name).strip()
            file_name = unquote(file_name)

            # -------------------重命名,不改变扩展名-------------------
            if new_name:
                new_name = re_SUB(r'[\\/*:|<>?"]', '', new_name).strip()
                ext_name = file_name.split('.')[-1]

                if '.' in new_name or ext_name == file_name:
                    full_name = new_name
                else:
                    full_name = f'{new_name}.{ext_name}'

            else:
                full_name = file_name

            # -------------------生成路径-------------------
            goal_Path = Path(goal)
            goal = ''
            skip = False

            for key, i in enumerate(goal_Path.parts):  # 去除路径中的非法字符
                goal += goal_Path.drive if key == 0 and goal_Path.drive else re_SUB(
                    r'[*:|<>?"]', '', i).strip()
                goal += '\\' if i != '\\' and key < len(
                    goal_Path.parts) - 1 else ''

            goal_Path = Path(goal).absolute()
            goal_Path.mkdir(parents=True, exist_ok=True)
            full_path = Path(f'{goal}\\{full_name}')

            if full_path.exists():
                if file_exists == 'rename':
                    full_name = get_available_file_name(goal, full_name)
                    full_path = Path(f'{goal}\\{full_name}')

                elif exists == 'skip':
                    skip = True

                elif exists == 'overwrite':
                    pass

                else:
                    raise ValueError(
                        "Argument file_exists can only be 'skip', 'overwrite', 'rename'."
                    )

            # -------------------打印要下载的文件-------------------
            if msg:
                print(file_url)
                print(full_name if file_name ==
                      full_name else f'{file_name} -> {full_name}')
                print(f'Downloading to: {goal}')

                if skip:
                    print('Skipped.\n')

            # -------------------开始下载-------------------
            if skip:
                return False, 'Skipped because a file with the same name already exists.'

            # 获取远程文件大小
            content_length = r.headers.get('content-length')
            file_size = int(content_length) if content_length else None

            # 已下载文件大小和下载状态
            downloaded_size, download_status = 0, False

            try:
                with open(str(full_path), 'wb') as tmpFile:
                    for chunk in r.iter_content(chunk_size=1024):
                        if chunk:
                            tmpFile.write(chunk)

                            # 如表头有返回文件大小,显示进度
                            if msg and file_size:
                                downloaded_size += 1024
                                rate = downloaded_size / file_size if downloaded_size < file_size else 1
                                print('\r {:.0%} '.format(rate), end="")

            except Exception as e:
                if errmsg:
                    raise ConnectionError(e)

                download_status, info = False, f'Download failed.\n{e}'

            else:
                if full_path.stat().st_size == 0:
                    if errmsg:
                        raise ValueError('File size is 0.')

                    download_status, info = False, 'File size is 0.'

                else:
                    download_status, info = True, str(full_path)

            finally:
                # 删除下载出错文件
                if not download_status and full_path.exists():
                    full_path.unlink()

                r.close()

            # -------------------显示并返回值-------------------
            if msg:
                print(info, '\n')

            info = f'{goal}\\{full_name}' if download_status else info
            return download_status, info