diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..1cc5a5e3b54e02a90158bab6494aa52512e64e6f --- /dev/null +++ b/.gitignore @@ -0,0 +1,112 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/DownloadKit/downloadKit.py b/DownloadKit/downloadKit.py index cec53a8c7ee88a0084204c5f7a4a87a44d571882..dfffbabe88a6edf8c2059fe974c4144c45a87322 100644 --- a/DownloadKit/downloadKit.py +++ b/DownloadKit/downloadKit.py @@ -11,12 +11,12 @@ from re import sub from threading import Thread, Lock from time import sleep, perf_counter -from DataRecorder import Recorder -from requests import Session, Response +from requests import Response from requests.structures import CaseInsensitiveDict from ._funcs import FileExistsSetter, PathSetter, BlockSizeSetter, set_charset, get_file_info from .mission import Task, Mission +from .setter import Setter class DownloadKit(object): @@ -24,12 +24,12 @@ class DownloadKit(object): goal_path = PathSetter() block_size = BlockSizeSetter() - def __init__(self, goal_path=None, roads=10, session=None, file_exists='rename'): + def __init__(self, goal_path=None, roads=10, session=None, file_exists='rename', driver=None): """ :param goal_path: 文件保存路径 :param roads: 可同时运行的线程数 - :param session: 使用的Session对象,或配置对象、页面对象等 :param file_exists: 有同名文件名时的处理方式,可选 'skip', 'overwrite', 'rename', 'add' + :param driver: 使用的Session对象,或配置对象、页面对象等 """ self._roads = roads self._missions = {} @@ -54,7 +54,7 @@ class DownloadKit(object): self.file_exists = file_exists self.split = True self.block_size = '50M' - self.set.driver(session) + self.set.driver(session or driver) def __call__(self, file_url, goal_path=None, rename=None, file_exists=None, show_msg=True, **kwargs): """以阻塞的方式下载一个文件并返回结果 @@ -118,17 +118,17 @@ class DownloadKit(object): @property def session(self): + """返回用于保存默认连接设置的Session对象""" return self._session @property def is_running(self): """返回是否有线程还在运行""" return self._running_count > 0 - # return any([i for i in self._missions.values() if not i.is_done]) - # return any(self._threads.values()) or not self.waiting_list.empty() @property def missions(self): + """用list方式返回所有任务对象""" return self._missions def add(self, file_url, goal_path=None, rename=None, file_exists=None, split=None, **kwargs): @@ -222,10 +222,10 @@ class DownloadKit(object): """等待所有或指定任务完成 :param mission: 任务对象或任务id,为None时等待所有任务结束 :param show: 是否显示进度 - :param timeout: 超时时间,默认为连接超时时间,0为无限 + :param timeout: 超时时间,None或0为无限 :return: 任务结果和信息组成的tuple """ - timeout = timeout if timeout is not None else self.timeout + timeout = 0 if timeout is None else timeout if mission: return self.get_mission(mission).wait(show, timeout) @@ -442,18 +442,18 @@ class DownloadKit(object): chunks[-1][-1] = '' chunks_len = len(chunks) - task1 = Task(mission, chunks[0], f'1/{chunks_len}') + task1 = Task(mission, chunks[0], f'1/{chunks_len}', chunks[0][1] - chunks[0][0]) mission.tasks_count = chunks_len - mission.tasks = [] - mission.tasks.append(task1) + mission.tasks = [task1] for ind, chunk in enumerate(chunks[1:], 2): - task = Task(mission, chunk, f'{ind}/{chunks_len}') + s = file_size - chunk[0] if chunks_len == ind else chunk[1] - chunk[0] + task = Task(mission, chunk, f'{ind}/{chunks_len}', s) mission.tasks.append(task) self._run_or_wait(task) else: # 不分块 - task1 = Task(mission, None, '1/1') + task1 = Task(mission, None, '1/1', file_size) mission.tasks.append(task1) self._threads[thread_id]['mission'] = task1 @@ -471,7 +471,7 @@ def _do_download(r: Response, task: Task, first: bool = False): return task.set_states(result=None, info='下载中', state='running') - block_size = 2 # 64k + block_size = 131072 # 128k result = None try: @@ -545,213 +545,3 @@ def _do_download(r: Response, task: Task, first: bool = False): r.close() task._set_done(result=result, info=info) - - -class Setter(object): - def __init__(self, downloadKit): - """ - :param downloadKit: downloadKit对象 - """ - self._downloadKit: DownloadKit = downloadKit - - @property - def DownloadKit(self): - """返回使用的DownloadKit对象""" - return self._downloadKit - - @property - def if_file_exists(self): - """返回用于设置文件同名策略的对象""" - return FileExists(self) - - @property - def log_mode(self): - """返回用于设置记录模式的对象""" - return LogSet(self) - - def driver(self, driver): - """设置Session对象 - :param driver: Session对象或DrissionPage的页面对象 - :return: None - """ - self._downloadKit._copy_cookies = False - if isinstance(driver, Session): - self._downloadKit._session = driver - return - - try: - from DrissionPage.base import BasePage - from DrissionPage import SessionPage, WebPage - from DrissionPage.chromium_tab import WebPageTab - from DrissionPage import SessionOptions - if isinstance(driver, (WebPageTab, WebPage)): - self._downloadKit._session = driver.session - self._downloadKit.page = driver - self._downloadKit._copy_cookies = True - return - elif isinstance(driver, SessionPage): - self._downloadKit._session = driver.session - self._downloadKit.page = driver - return - elif isinstance(driver, BasePage): - self._downloadKit._session = Session() - self._downloadKit.page = driver - self._downloadKit._copy_cookies = True - return - elif isinstance(driver, SessionOptions): - self._downloadKit._session = driver.make_session() - return - except ModuleNotFoundError: - pass - - self._downloadKit._session = Session() - - def roads(self, num): - """设置可同时运行的线程数 - :param num: 线程数量 - :return: None - """ - if self._downloadKit.is_running: - print('有任务未完成时不能改变roads。') - return - if num != self._downloadKit.roads: - self._downloadKit._roads = num - self._downloadKit._threads = {i: None for i in range(num)} - - def retry(self, times): - """设置连接失败时重试次数 - :param times: 重试次数 - :return: None - """ - if not isinstance(times, int) or times < 0: - raise TypeError('times参数只能接受int格式且不能小于0。') - self._downloadKit._retry = times - - def interval(self, seconds): - """设置连接失败时重试间隔 - :param seconds: 连接失败时重试间隔(秒) - :return: None - """ - if not isinstance(seconds, (int, float)) or seconds < 0: - raise TypeError('seconds参数只能接受int或float格式且不能小于0。') - self._downloadKit._interval = seconds - - def timeout(self, seconds): - """设置连接超时时间 - :param seconds: 超时时间(秒) - :return: None - """ - if not isinstance(seconds, (int, float)) or seconds < 0: - raise TypeError('seconds参数只能接受int或float格式且不能小于0。') - self._downloadKit._timeout = seconds - - def goal_path(self, path): - """设置文件保存路径 - :param path: 文件路径,可以是str或Path - :return: None - """ - self._downloadKit.goal_path = path - - def split(self, on_off): - """设置大文件是否分块下载 - :param on_off: bool代表开关 - :return: None - """ - self._downloadKit.split = on_off - - def block_size(self, size): - """设置分块大小 - :param size: 单位为字节,可用'K'、'M'、'G'为单位,如'50M' - :return: None - """ - self._downloadKit.block_size = size - - def proxies(self, http=None, https=None): - """设置代理地址及端口,例:'127.0.0.1:1080' - :param http: http代理地址及端口 - :param https: https代理地址及端口 - :return: None - """ - self._downloadKit._session.proxies = {'http': http, 'https': https} - - -class LogSet(object): - """用于设置信息打印和记录日志方式""" - - def __init__(self, setter): - """ - :param setter: Setter对象 - """ - self._setter = setter - - def log_path(self, log_path): - """设置日志文件路径 - :param log_path: 文件路径,可以是str或Path - :return: None - """ - if self._setter.DownloadKit._logger is not None: - self._setter.DownloadKit._logger.record() - self._setter.DownloadKit._logger = Recorder(log_path) - - def print_all(self): - """打印所有信息""" - self._setter.DownloadKit._print_mode = 'all' - - def print_failed(self): - """只有在下载失败时打印信息""" - self._setter.DownloadKit._print_mode = 'failed' - - def print_nothing(self): - """不打印任何信息""" - self._setter.DownloadKit._print_mode = None - - def log_all(self): - """记录所有信息""" - if self._setter.DownloadKit._logger is None: - raise RuntimeError('请先用log_path()设置log文件路径。') - self._setter.DownloadKit._log_mode = 'all' - - def log_failed(self): - """只记录下载失败的信息""" - if self._setter.DownloadKit._logger is None: - raise RuntimeError('请先用log_path()设置log文件路径。') - self._setter.DownloadKit._log_mode = 'failed' - - def log_nothing(self): - """不进行记录""" - self._setter.DownloadKit._log_mode = None - - -class FileExists(object): - """用于设置存在同名文件时处理方法""" - - def __init__(self, setter): - """ - :param setter: Setter对象 - """ - self._setter = setter - - def __call__(self, mode): - """设置文件存在时的处理方式 - :param mode: 'skip', 'rename', 'overwrite', 'add' - :return: None - """ - if mode not in ('skip', 'rename', 'overwrite', 'add'): - raise ValueError("mode参数只能是'skip', 'rename', 'overwrite', 'add'") - self._setter.DownloadKit.file_exists = mode - - def skip(self): - """设为跳过""" - self._setter.DownloadKit.file_exists = 'skip' - - def rename(self): - """设为重命名,文件名后加序号""" - self._setter.DownloadKit.file_exists = 'rename' - - def overwrite(self): - """设为覆盖""" - self._setter.DownloadKit.file_exists = 'overwrite' - - def add(self): - """设为追加""" - self._setter.DownloadKit.file_exists = 'add' diff --git a/DownloadKit/downloadKit.pyi b/DownloadKit/downloadKit.pyi index 655d4ac981a12cd2de4d636197dd695bb3d9ca40..7cc1c7153a5c07d8b45aee1241172e6fc36d8b7d 100644 --- a/DownloadKit/downloadKit.pyi +++ b/DownloadKit/downloadKit.pyi @@ -9,12 +9,12 @@ from threading import Lock from typing import Union, Tuple, Any, Literal, Optional from DataRecorder import Recorder -from DrissionPage import SessionOptions from DrissionPage.base import BasePage from requests import Session, Response from ._funcs import FileExistsSetter, PathSetter, BlockSizeSetter from .mission import Task, Mission, BaseTask +from .setter import Setter FILE_EXISTS = Literal['add', 'skip', 'rename', 'overwrite'] @@ -24,34 +24,31 @@ class DownloadKit(object): goal_path: PathSetter = ... block_size: BlockSizeSetter = ... + _roads: int = ... + _setter: Optional[Setter] = ... + _print_mode: Optional[str] = ... + _log_mode: Optional[str] = ... + _logger: Optional[Recorder] = ... + _retry: Optional[int] = ... + _interval: Optional[float] = ... + page: Optional[BasePage] = ... + _waiting_list: Queue = ... + _session: Session = ... + _running_count: int = ... + _missions_num: int = ... + _missions: dict = ... + _threads: dict = ... + _timeout: Optional[int, float] = ... + _stop_printing: bool = ... + _lock: Lock = ... + _copy_cookies: bool = ... + split: bool = ... + def __init__(self, goal_path: Union[str, Path] = None, roads: int = 10, - session: Union[Session, BasePage] = None, - file_exists: FILE_EXISTS = 'rename'): - self._roads: int = ... - self._setter: Setter = ... - self._print_mode: str = ... - self._log_mode: str = ... - self._logger: Recorder = ... - self._retry: int = ... - self._interval: float = ... - self.page: Optional[BasePage] = ... - self._waiting_list: Queue = ... - self._session: Session = ... - self._running_count: int = ... - self._missions_num: int = ... - self._missions: dict = ... - self._threads: dict = ... - self._timeout: Union[int, float] = ... - self._stop_printing: bool = ... - self._lock: Lock = ... - self._copy_cookies: bool = ... - - self.goal_path: str = ... - self.file_exists: FILE_EXISTS = ... - self.split: bool = ... - self.block_size: Union[str, int] = ... + driver: Union[Session, BasePage] = None, + file_exists: FILE_EXISTS = 'rename'): ... def __call__(self, file_url: str, @@ -173,67 +170,3 @@ class DownloadKit(object): def _download(self, mission_or_task: Union[Mission, Task], thread_id: int) -> None: ... - - -class Setter(object): - def __init__(self, downloadKit: DownloadKit): - self._downloadKit: DownloadKit = ... - - @property - def DownloadKit(self) -> DownloadKit: ... - - @property - def if_file_exists(self) -> FileExists: ... - - @property - def log_mode(self) -> LogSet: ... - - def driver(self, driver: Union[Session, BasePage, SessionOptions]) -> None: ... - - def roads(self, num: int) -> None: ... - - def retry(self, times: int) -> None: ... - - def interval(self, seconds: float) -> None: ... - - def timeout(self, seconds: float) -> None: ... - - def goal_path(self, path: Union[str, Path]) -> None: ... - - def split(self, on_off: bool) -> None: ... - - def block_size(self, size: Union[str, int]) -> None: ... - - def proxies(self, http: str = None, https: str = None) -> None: ... - - -class LogSet(object): - def __init__(self, setter: Setter): - self._setter: Setter = ... - - def log_path(self, log_path: Union[str, Path]) -> None: ... - - def print_all(self) -> None: ... - - def print_failed(self) -> None: ... - - def print_nothing(self) -> None: ... - - def log_all(self) -> None: ... - - def log_failed(self) -> None: ... - - def log_nothing(self) -> None: ... - - -class FileExists(object): - def __init__(self, setter: Setter): - self._setter: Setter = ... - - def __call__(self, mode: FILE_EXISTS): ... - - def skip(self) -> None: ... - - def rename(self) -> None: ... - - def overwrite(self) -> None: ... diff --git a/DownloadKit/mission.py b/DownloadKit/mission.py index eabd59cb97fe9a68af21a262edcc1b89bfdb7f68..270557840c3bb4d8ff4242ba75110b33ef57f69d 100644 --- a/DownloadKit/mission.py +++ b/DownloadKit/mission.py @@ -128,10 +128,12 @@ class Mission(BaseTask): @property def rate(self): """返回下载进度百分比""" - if self.path and self.path.exists(): - return round((self.path.stat().st_size / self.size) * 100, 2) if self.size else None - else: - return + if not self.size: + return None + c = 0 + for t in self.tasks: + c += t._downloaded_size if t._downloaded_size else 0 + return round((c / self.size) * 100, 2) def cancel(self) -> None: """取消该任务,停止未下载完的task""" @@ -285,7 +287,7 @@ class Mission(BaseTask): class Task(BaseTask): - def __init__(self, mission, range_, ID): + def __init__(self, mission, range_, ID, size): """子任务类 :param mission: 父任务对象 :param range_: 读取文件数据范围 @@ -294,9 +296,11 @@ class Task(BaseTask): super().__init__(ID) self.mission = mission self.range = range_ + self.size = size + self._downloaded_size = 0 def __repr__(self): - return f'' + return f'' @property def mid(self): @@ -318,12 +322,18 @@ class Task(BaseTask): """返回文件名""" return self.mission.file_name + @property + def rate(self): + """返回下载进度百分比""" + return round((self._downloaded_size / self.size) * 100, 2) if self.size else None + def add_data(self, data, seek=None): """把数据输入到记录器 :param data: 文件字节数据 :param seek: 在文件中的位置,None表示最后 :return: None """ + self._downloaded_size += len(data) self.mission.recorder.add_data(data, seek) def clear_cache(self): diff --git a/DownloadKit/mission.pyi b/DownloadKit/mission.pyi index 6214a413f6890ba18725369b181dc92f159667ce..c91570fcd86250cf4ad73279418dfe0ce9b12e95 100644 --- a/DownloadKit/mission.pyi +++ b/DownloadKit/mission.pyi @@ -10,16 +10,16 @@ from .downloadKit import DownloadKit class MissionData(object): """保存任务数据的对象""" + url: str = ... + goal_path: Union[str, Path] = ... + rename: Optional[str] = ... + file_exists: str = ... + split: bool = ... + kwargs: dict = ... + offset: int = ... def __init__(self, url: str, goal_path: Union[str, Path], rename: Optional[str], - file_exists: str, split: bool, kwargs: dict, offset: int = 0): - self.url: str = ... - self.goal_path: Union[str, Path] = ... - self.rename: Optional[str] = ... - self.file_exists: str = ... - self.split: bool = ... - self.kwargs: dict = ... - self.offset: int = ... + file_exists: str, split: bool, kwargs: dict, offset: int = 0): ... class BaseTask(object): @@ -27,9 +27,12 @@ class BaseTask(object): _DONE: str = ... RESULT_TEXTS: dict = ... - def __init__(self, ID: Union[int, str]): - self._id: str = ... - self.state: str = ... + _id: str = ... + state: str = ... + result: Optional[str, False] = ... + info: str = ... + + def __init__(self, ID: Union[int, str]): ... @property def id(self) -> Union[int, str]: ... @@ -48,22 +51,20 @@ class BaseTask(object): class Mission(BaseTask): """任务类""" + file_name: Optional[str] = ... + _data: MissionData = ... + _path: Optional[str, Path] = ... + _recorder: Optional[ByteRecorder] = ... + size: Optional[float] = ... + done_tasks_count: int = ... + tasks_count: int = ... + tasks: List[Task] = ... + download_kit: DownloadKit = ... + session: Session = ... + method: str = ... def __init__(self, ID: int, download_kit: DownloadKit, file_url: str, goal_path: Union[str, Path], rename: str, - file_exists: str, split: bool, kwargs: dict): - self.info: str = ... - self.file_name: str = ... - self._data: MissionData = ... - self._path: Union[str, Path] = ... - self._recorder: ByteRecorder = ... - self.size: float = ... - self.done_tasks_count: int = ... - self.tasks_count: int = ... - self.tasks: List[Task] = ... - self.download_kit: DownloadKit = ... - self.session: Session = ... - self.result: Optional[str, bool] = ... - self.method: str = ... + file_exists: str, split: bool, kwargs: dict): ... def __repr__(self) -> str: ... @@ -100,12 +101,12 @@ class Mission(BaseTask): class Task(BaseTask): """子任务类""" + mission: Mission = ... + range: Optional[list] = ... + size: Optional[int] = ... + _downloaded_size: int = 0 - def __init__(self, mission: Mission, range_: Optional[list], ID: str): - self._id: str = ... - self.info: str = ... - self.mission: Mission = ... - self.range: Optional[list] = ... + def __init__(self, mission: Mission, range_: Optional[list], ID: str, size: Optional[int]): ... def __repr__(self) -> str: ... @@ -121,6 +122,9 @@ class Task(BaseTask): @property def file_name(self) -> str: ... + @property + def rate(self) -> Optional[float]: ... + def add_data(self, data: bytes, seek: int = None) -> None: ... def clear_cache(self) -> None: ... diff --git a/DownloadKit/setter.py b/DownloadKit/setter.py new file mode 100644 index 0000000000000000000000000000000000000000..43fe163d22bc54317019ace71b8c76ced3422475 --- /dev/null +++ b/DownloadKit/setter.py @@ -0,0 +1,213 @@ +# -*- coding:utf-8 -*- +""" +@Author : g1879 +@Contact : g1879@qq.com +@File : setter.py +""" +from DataRecorder import Recorder +from requests import Session + + +class Setter(object): + def __init__(self, downloadKit): + """ + :param downloadKit: downloadKit对象 + """ + self._downloadKit = downloadKit + + @property + def if_file_exists(self): + """返回用于设置文件同名策略的对象""" + return FileExists(self) + + @property + def log(self): + """返回用于设置记录模式的对象""" + return LogSet(self) + + def driver(self, driver): + """设置Session对象 + :param driver: Session对象或DrissionPage的页面对象 + :return: None + """ + self._downloadKit._copy_cookies = False + if isinstance(driver, Session): + self._downloadKit._session = driver + return + + try: + from DrissionPage.base import BasePage + from DrissionPage import SessionPage, WebPage + from DrissionPage.chromium_tab import WebPageTab + from DrissionPage import SessionOptions + if isinstance(driver, (WebPageTab, WebPage)): + self._downloadKit._session = driver.session + self._downloadKit.page = driver + self._downloadKit._copy_cookies = True + return + elif isinstance(driver, SessionPage): + self._downloadKit._session = driver.session + self._downloadKit.page = driver + return + elif isinstance(driver, BasePage): + self._downloadKit._session = Session() + self._downloadKit.page = driver + self._downloadKit._copy_cookies = True + return + elif isinstance(driver, SessionOptions): + self._downloadKit._session = driver.make_session() + return + except ModuleNotFoundError: + pass + + self._downloadKit._session = Session() + + def roads(self, num): + """设置可同时运行的线程数 + :param num: 线程数量 + :return: None + """ + if self._downloadKit.is_running: + print('有任务未完成时不能改变roads。') + return + if num != self._downloadKit.roads: + self._downloadKit._roads = num + self._downloadKit._threads = {i: None for i in range(num)} + + def retry(self, times): + """设置连接失败时重试次数 + :param times: 重试次数 + :return: None + """ + if not isinstance(times, int) or times < 0: + raise TypeError('times参数只能接受int格式且不能小于0。') + self._downloadKit._retry = times + + def interval(self, seconds): + """设置连接失败时重试间隔 + :param seconds: 连接失败时重试间隔(秒) + :return: None + """ + if not isinstance(seconds, (int, float)) or seconds < 0: + raise TypeError('seconds参数只能接受int或float格式且不能小于0。') + self._downloadKit._interval = seconds + + def timeout(self, seconds): + """设置连接超时时间 + :param seconds: 超时时间(秒) + :return: None + """ + if not isinstance(seconds, (int, float)) or seconds < 0: + raise TypeError('seconds参数只能接受int或float格式且不能小于0。') + self._downloadKit._timeout = seconds + + def goal_path(self, path): + """设置文件保存路径 + :param path: 文件路径,可以是str或Path + :return: None + """ + self._downloadKit.goal_path = path + + def split(self, on_off): + """设置大文件是否分块下载 + :param on_off: bool代表开关 + :return: None + """ + self._downloadKit.split = on_off + + def block_size(self, size): + """设置分块大小 + :param size: 单位为字节,可用'K'、'M'、'G'为单位,如'50M' + :return: None + """ + self._downloadKit.block_size = size + + def proxies(self, http=None, https=None): + """设置代理地址及端口,例:'127.0.0.1:1080' + :param http: http代理地址及端口 + :param https: https代理地址及端口 + :return: None + """ + self._downloadKit._session.proxies = {'http': http, 'https': https} + + +class LogSet(object): + """用于设置信息打印和记录日志方式""" + + def __init__(self, setter): + """ + :param setter: Setter对象 + """ + self._setter = setter + + def path(self, path): + """设置日志文件路径 + :param path: 文件路径,可以是str或Path + :return: None + """ + if self._setter._downloadKit._logger is not None: + self._setter._downloadKit._logger.record() + self._setter._downloadKit._logger = Recorder(path) + + def print_all(self): + """打印所有信息""" + self._setter._downloadKit._print_mode = 'all' + + def print_failed(self): + """只有在下载失败时打印信息""" + self._setter._downloadKit._print_mode = 'failed' + + def print_nothing(self): + """不打印任何信息""" + self._setter._downloadKit._print_mode = None + + def log_all(self): + """记录所有信息""" + if self._setter._downloadKit._logger is None: + raise RuntimeError('请先用log_path()设置log文件路径。') + self._setter._downloadKit._log_mode = 'all' + + def log_failed(self): + """只记录下载失败的信息""" + if self._setter._downloadKit._logger is None: + raise RuntimeError('请先用log_path()设置log文件路径。') + self._setter._downloadKit._log_mode = 'failed' + + def log_nothing(self): + """不进行记录""" + self._setter._downloadKit._log_mode = None + + +class FileExists(object): + """用于设置存在同名文件时处理方法""" + + def __init__(self, setter): + """ + :param setter: Setter对象 + """ + self._setter = setter + + def __call__(self, mode): + """设置文件存在时的处理方式 + :param mode: 'skip', 'rename', 'overwrite', 'add' + :return: None + """ + if mode not in ('skip', 'rename', 'overwrite', 'add'): + raise ValueError("mode参数只能是'skip', 'rename', 'overwrite', 'add'") + self._setter._downloadKit.file_exists = mode + + def skip(self): + """设为跳过""" + self._setter._downloadKit.file_exists = 'skip' + + def rename(self): + """设为重命名,文件名后加序号""" + self._setter._downloadKit.file_exists = 'rename' + + def overwrite(self): + """设为覆盖""" + self._setter._downloadKit.file_exists = 'overwrite' + + def add(self): + """设为追加""" + self._setter._downloadKit.file_exists = 'add' diff --git a/DownloadKit/setter.pyi b/DownloadKit/setter.pyi new file mode 100644 index 0000000000000000000000000000000000000000..359325be7101c7629126296d3f8cc7eff4b91b2e --- /dev/null +++ b/DownloadKit/setter.pyi @@ -0,0 +1,79 @@ +# -*- coding:utf-8 -*- +""" +@Author : g1879 +@Contact : g1879@qq.com +""" +from pathlib import Path +from typing import Union, Literal + +from DrissionPage.base import BasePage +from DrissionPage import SessionOptions +from requests import Session + +from .downloadKit import DownloadKit + +FILE_EXISTS = Literal['add', 'skip', 'rename', 'overwrite'] + + +class Setter(object): + _downloadKit: DownloadKit = ... + + def __init__(self, downloadKit: DownloadKit): ... + + @property + def if_file_exists(self) -> FileExists: ... + + @property + def log(self) -> LogSet: ... + + def driver(self, driver: Union[Session, BasePage, SessionOptions]) -> None: ... + + def roads(self, num: int) -> None: ... + + def retry(self, times: int) -> None: ... + + def interval(self, seconds: float) -> None: ... + + def timeout(self, seconds: float) -> None: ... + + def goal_path(self, path: Union[str, Path]) -> None: ... + + def split(self, on_off: bool) -> None: ... + + def block_size(self, size: Union[str, int]) -> None: ... + + def proxies(self, http: str = None, https: str = None) -> None: ... + + +class LogSet(object): + _setter: Setter = ... + + def __init__(self, setter: Setter): ... + + def path(self, path: Union[str, Path]) -> None: ... + + def print_all(self) -> None: ... + + def print_failed(self) -> None: ... + + def print_nothing(self) -> None: ... + + def log_all(self) -> None: ... + + def log_failed(self) -> None: ... + + def log_nothing(self) -> None: ... + + +class FileExists(object): + _setter: Setter = ... + + def __init__(self, setter: Setter): ... + + def __call__(self, mode: FILE_EXISTS): ... + + def skip(self) -> None: ... + + def rename(self) -> None: ... + + def overwrite(self) -> None: ... diff --git a/README.md b/README.md index 2649f3a3bad5cb862309fbb026fb4ec959b8f472..728c1affda78c2122df239965a9595293ce514e2 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,28 @@ -# 简介 +## 简介 -DownloadKit 是一个基于 python 的简洁易用的多线程文件下载工具。 -使用简单,只要不断往里添加下载任务,它会按顺序自行下载完成并返回结果。 +DownloadKit 是一个基于 python 的简洁易用的多线程文件下载工具。 +使用简单,功能强大。 -# 特性 +使用文档:[点击查看](http://g1879.gitee.io/downloadkit/) + +--- + +## 特性 - 多线程,可同时下载多个文件 - 大文件自动分块用多线程下载 - 自动任务调度,简易的任务添加方式 - 可使用已有`Session`对象,便于保持登录状态 +- 与 DrissionPage 良好兼容 - 自动创建目标路径 - 自动去除路径中的非法字符 - 自动处理文件名冲突 +- 可对现有文件追加内容 - 连接失败自动重试 -# 安装 - -```shell -pip install DownloadKit -``` - -# 导入 +--- -```python -from DownloadKit import DownloadKit -``` - -# 简单示例 +## 简单示例 ```python from DownloadKit import DownloadKit @@ -38,333 +34,14 @@ d = DownloadKit(r'.\files') url1 = 'https://gitee.com/static/images/logo.svg?t=158106664' url2 = 'https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png' -d.add(url1) -d.add(url2) -``` - -# 使用方法 - -## 创建`DownloadKit`对象 - -初始化参数: - -- goal_path:文件保存路径,默认当前路径 -- roads:可同时运行的线程数 -- session:使用的`Session`对象,或配置对象等 -- timeout:连接超时时间 -- file_exists:有同名文件名时的处理方式,可选`'skip'`,`'overwrite'`,`'rename'` - -**session 参数说明:** - -该参数可接收一个现成的`Session`对象,也可以接收`SessionOptions`、`MixPage`、`Drission`对象,生成或使用其中的`Session`对象。 若不传入以上对象,程序会自行生成一个。如果当前环境安装了 -DrissionPage,程序会读取其 ini 配置文件生成,如果没有,则生成一个空`Session`对象。 - -> `SessionOptions`、`MixPage`、`Drission`对象用法见: [DrissionPage]([DrissionPage (gitee.io)](http://g1879.gitee.io/drissionpage/)) - -直接创建: - -```python -d = DownloadKit() -``` - -接收`Session`对象 - -```python -from requests import Session - -session = Session() -d = DownloadKit(session=session) -``` - -接收`SessionOptions`对象 - -```python -from DrissionPage.config import SessionOptions - -so = SessionOptions() -d = DownloadKit(session=so) -``` - -接收`MixPage`对象 - -```python -from DrissionPage import MixPage - -page = MixPage('s') -d = DownloadKit(session=page) -``` - -接收`Drission`对象 - -```python -from DrissionPage import MixPage - -page = MixPage('s') -d = DownloadKit(session=page.drission) +d.download(url1) +d.download(url2) ``` -## `DownloadKit`属性 - -- goal_path:文件保存路径,可赋值 -- roads:可同时允许的线程数,没有任务运行时可赋值 -- block_size:大文件分块大小,默认 20MB -- retry:下载失败重试次数,可赋值 -- interval:下载失败重试间隔,可赋值 -- timeout:连接超时时间,可赋值 -- file_exists:遇到同名文件时的处理方式,可赋值,可选`'skip'`、`'overwrite'`、`'rename'` -- session:用于连接的`Session`对象 -- waiting_list:等待下载的队列 -- is_running:返回是否有线程还在运行 - -**`file_exists`属性说明:** - -- `skip`:跳过该文件 -- `overwrite`:覆盖该文件 -- `rename`:以在后面添加序号的方式给新文件重命名 - -**`block_size`属性说明:** - -该属性可接收`int`和`str`形式,接收`int`时以字节为单位; -接收`str`时格式有:`'10b'`、`'10k'`、`'10m'`、`'10g'`四种。不区分大小写。 - -## 下载设置 - -可使用以下属性进行配置: - -```python -d = DownloadKit() - -# 设置线程数,只能在没有任务在运行的时候进行 -d.roads = 20 - -# 大文件分块大小,默认 20MB -d.block_size = '50M' - -# 设置保存路径,设置后每个任务会使用这个路径,也可添加任务时单独设置 -d.goal_path = r'D:\tmp' - -# 设置重试次数,初始为3 -d.retry = 5 - -# 设置失败重试间隔,初始为5 -d.interval = 2 - -# 设置存在文件名冲突时的处理方式,可选 'skip', 'overwrite', 'rename' -d.file_exists = 'skip' -``` - - - -## 添加下载任务 - -使用`add()`方法添加下载任务。 - -参数: - -- file_url:文件网址 -- goal_path:保存路径 -- rename:重命名的文件名 -- file_exists:遇到同名文件时的处理方式,可选`'skip'`,`'overwrite'`,`'rename'`,默认跟随实例属性 -- split:是否允许多线分块下载 -- kwargs:连接参数,与 requests 的参数使用方法一致 - -返回:`Mission`对象 - -使用`add()`方法返回的`Mission`对象可便于后续查看任务状态和进度。 - -```python -from DownloadKit import DownloadKit - -d = DownloadKit() - -url = 'https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png' -mission = d.add(url) -``` - -## 添加连接参数 - -可以给`Session`对象添加整体参数,或每个任务设置独立的参数。 - -**整体参数:** - -```python -from requests import Session -from DownloadKit import DownloadKit - -session = Session() -session.headers={'xxxx': 'xxxx'} -d = DownloadKit(session=session) -``` - -更简便的方法是使用`SessionOptions`。该对象可使用保存在配置文件里的参数,免得每次在代码里设置复杂的`headers` -等参数,方便易用。详见:[DrissionPage]([🔧 Session 启动配置 (gitee.io)](http://g1879.gitee.io/drissionpage/#/使用方法\启动配置\Session启动配置)) - -```python -from DrissionPage.config import SessionOptions -from DownloadKit import DownloadKit - -so = SessionOptions().set_proxies({'http': 'http://127.0.0.1'}) -d = DownloadKit(session=so) -``` - -**任务独立设置参数:** - -```python -from DownloadKit import DownloadKit - -d = DownloadKit() - -url = 'https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png' -proxies = {'http': 'http://127.0.0.1'} -d.add(url, proxies=proxies) -``` - -## 任务连接方式 - -任务可以用 get 或 post 方式,默认使用 get 方式,添加任务时,传入`data`或`json`参数即可使用 post 方式。 - -```python -url = 'https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png' - -# 使用 get 方式 -d.add(url) - -# 使用 post 方式 -data = {'xxx': 'xxx'} -d.add(url, json=data) -# 或 -d.add(url, data=data) -``` - -**Tips:** `json`参数没有显式写在参数里,但直接调用即可。 - - - -## 观察下载过程 - -`show()`方法可实时显示所有线程下载过程。 - -**注意:** 若使用 pyCharm 运行,须在运行配置里勾选“模拟输出控制台中的终端”才能正常显示输出。 - -参数: - -- asyn:是否异步进行 -- keep:是否保持显示,为`True`时即使任务全部结束,也会保持显示,可按回车结束显示 - -返回:None - -```python -d = DownloadKit(r'.\files', size=3) -url = 'https://example.com/file/abc.zip' -mission = d.add(url) -d.show() -``` - -输出: - -```shell -等待任务数:0 -线程0:M1 D:\files\abc.zip -线程1:M1 D:\files\abc.zip -线程2:空闲 -``` - - - -## 等待任务结束 - -有时须要等待任务结束,以便获取结果,可用`DownloadKit`对象或`Mission`对象的`wait()`方法。 -当传入任务时,等待该任务结束并返回结果。不传入参数时等待所有任务结束,与`show()`方法一致。 - -`DownloadKit`对象的`wait()`方法: - -参数: - -- mission:任务对象或任务`id`,为`None`时等待所有任务结束 -- show:是否显示进度 - -返回: - -- 指定任务时,返回任务结果和信息组成的两位 tuple。其中任务结果`'success'`表示成功,`False`表示失败,`'skip'`表示跳过。成功和跳过时信息为文件绝对路径,失败时信息为失败原因 -- 不指定任务时,返回`None` - -`Mission`对象的`wait()`方法 - -参数: - -- show:是否显示进度 - -返回:返回任务结果和信息组成的两位 tuple。其中任务结果`'success'`表示成功,`False`表示失败,`'skip'`表示跳过。成功和跳过时信息为文件绝对路径,失败时信息为失败原因 - -```python -d = DownloadKit(r'.\files') -url = 'https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png' -mission = d.add(url) -d.wait(mission) -# 或 -mission.wait() -``` - -输出: - -```shell -url:https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png -文件名:PCfb_5bf082d29588c07f842ccde3f97243ea_4.png -目标路径:D:\files -100% 下载完成 D:\files\PCfb_5bf082d29588c07f842ccde3f97243ea_4.png -``` - -**Tips:** `Mission`对象也有`wait()`方法,作用与上述的一致。 - -```python -mission = d.add(url) -mission.wait() -``` - -## 获取某个任务结果 - -`Mission`对象用于管理下载任务,可查看该任务执行情况。 - -**`Mission`对象属性:** - -- id:任务 id -- file_name:要保存的文件名 -- path:要保存的路径,为Path对象 -- data:任务数据 -- state:任务状态,有`'waiting'`、`'running'`、`'done'`三种 -- rate:任务进度,以百分比显示 -- info:任务信息,成功会返回文件绝对路径,失败会显示原因 -- result:任务结果,`'success'`表示成功,`False`表示失败,`'skip'`表示跳过 - -```python -mission = page.download.add(url) -print(mission.state) -``` - -输出: - -```python -running -``` - - - -## 取消某个正在下载的任务 - -使用`Mission`对象的`cancel()`方法,取消会删除该任务已下载的文件。 - -```python -mission.cancel() -``` - - - -## 获取失败任务 - -使用`DownloadKit`对象的`get_failed_missions()`方法,可获取下载失败的任务。可以把失败的任务保存到文件,支持 txt、xlsx、txt、csv 四种格式。 +--- -参数: +## ☕ 请我喝咖啡 -- save_to:失败任务保存到文件的路径,默认为`None`表示不保存 +如果本项目对您有所帮助,不妨请作者我喝杯咖啡 :) -返回:`Mission`对象组成的列表 +![](http://g1879.gitee.io/drissionpagedocs/imgs/code.jpg) \ No newline at end of file diff --git a/docs/history.md b/docs/history.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b7c68d1dd4f8b2a115300d1f761264004b782829 100644 --- a/docs/history.md +++ b/docs/history.md @@ -0,0 +1,100 @@ +--- +hide: + - navigation +--- + +## v1.0.2 + +- 支持`DrissionPage` v3.2.31 版 +- 修改设置项 api,`set_xxxx()`改为`set.xxxx()`形式 +- `__init__()`方法的`session`用`driver`代替,但保留向后兼容 +- 可更准确显示下载进度 +- `Task`增加下载进度属性 +- 处理已存在文件的情况增加`add`模式 +- 增加日志设置 +- 优化程序逻辑,修复一些问题 + +--- + +## v0.5.3 + +- 支持`DrissionPage` v3.2.0 版 +- 增加`missions`属性 + +--- + +## v0.4.4 + +- 适配`DrissionPage` v3.1.0 版 +- 增加`split`全局 设置 + +--- + +## v0.4.1 + +- 支持`DrissionPage` v3.0 版 +- 增加`set_log()`、`set_print()`和`set_proxies()` +- 改用`ByteRecorder`保存数据 +- 新增`MissionData`类 +- 大量修改结构,优化逻辑 + +--- + +## v0.3.5 + +- 新增`MissionData`类 +- `add()`方法删除`session`参数 +- `__init__()`方法删除`timeout`参数 +- 优化`timeout`、`retry`、`interval`属性逻辑 + +--- + +## v0.3.3 + +- `referer`参数可从传入的页面对象获取 +- 大量优化 + +--- + +## v0.3.0 + +- 完成主要功能 +- 完善逻辑 + +--- + +## v0.1.0 + +- 完成基本框架 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/index.md b/docs/index.md index 52f989fde8313fa0e2af504a14ee18cfaf5c447c..2299152dd511444d316afa53054459a253e21caf 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,11 +1,18 @@ -## 简介 +--- +hide: + - navigation +--- + +## 💬 简介 DownloadKit 是一个基于 python 的简洁易用的多线程文件下载工具。 使用简单,功能强大。 +当前版本:v1.0.2 + --- -## 特性 +## 💖 特性 - 多线程,可同时下载多个文件 - 大文件自动分块用多线程下载 @@ -20,7 +27,7 @@ DownloadKit 是一个基于 python 的简洁易用的多线程文件下载工具 --- -## 简单示例 +## 💥 简单示例 ```python from DownloadKit import DownloadKit diff --git a/docs/install_and_import.md b/docs/install_and_import.md index df41e994bd43f4549106945081b0b6300c31974b..059c5f17a3362787d8dc2f339fa98522123857f7 100644 --- a/docs/install_and_import.md +++ b/docs/install_and_import.md @@ -1,4 +1,8 @@ -## 安装 +--- +hide: + - navigation +--- +## 🎟️ 安装 如果您安装过 DrissionPage,本库已自动安装。 @@ -8,7 +12,7 @@ pip install DownloadKit --- -## 导入 +## 🎫 导入 ```python from DownloadKit import DownloadKit diff --git a/docs/usage/APIs.md b/docs/usage/APIs.md new file mode 100644 index 0000000000000000000000000000000000000000..99cb015033a303cbf42085feafe40cc2b290b966 --- /dev/null +++ b/docs/usage/APIs.md @@ -0,0 +1,234 @@ +## ✅️️ `DownloadKit`对象方法 + +### 📌 `download()` + +此方法用于单线程阻塞式下载一个文件。 + +|参数名称|类型|默认值|说明| +|:---:|:---:|:---:|---| +|`file_url`|`str`|必填|文件网址| +|`goal_path`|`str`
`Path`|`None`|保存路径,为`None`时保存到当前文件夹| +|`rename`|`str`|`None`|指定文件另存的名称,可不带后缀,程序会自动补充| +|`file_exists`|`str`|`None`|遇到同名文件时的处理方式,可选`'skip'`, `'overwrite'`, `'rename'`, `'add'`,默认跟随实例属性| +|`show_msg`|`bool`|`True`|是否打印下载信息和进度| +|`**kwargs`|`Any`|无|requests 的连接参数| + +连接参数`**kwargs`与 requests 的`get()`方法一致。 + +|参数名称|类型|说明| +|:---:|:---:|---| +|`timeout`|`float`|连接超时时间| +|`params`|`dict`|查询参数字典| +|`headers`|`dict`|headers| +|`cookies`|`Any`|cookies| +|`data`|`Any`|data 数据| +|`json`|`Any`|json 数据| +|`files`|`Any`|文件数据| +|`auth`|`Tuple[str, str]`
`HTTPBasicAuth`|认证元组或对象| +|`allow_redirects`|`bool`|是否允许自动跳转| +|`proxies`|`dict`|代理 ip| +|`hooks`|`dict`|回调方法| +|`verify`|`bool`|是否验证SSL证书| +|`cert`|`str`
`Tuple[str, str]`|SSL客户端证书| + +|返回类型|说明| +|:---:|---| +|`tuple`|格式:(任务结果, 任务信息)| + +任务结果有如下几种: + +- `'success'`:下载成功 +- `'skipped'`:已跳过 +- `'canceled'`:被取消 +- `False`:任务失败 + +如果下载成功,任务信息返回文件路径,如果失败,返回失败原因。 + +--- + +### 📌 `add()` + +此方法添加一个并发任务。 + +|参数名称|类型|默认值|说明| +|:---:|:---:|:---:|---| +|`file_url`|`str`|必填|文件网址| +|`goal_path`|`str`
`Path`|`None`|保存路径,为`None`时保存到当前文件夹| +|`rename`|``str`|`None`|指定文件另存的名称,可不带后缀,程序会自动补充| +|`file_exists`|`str`|`None`|遇到同名文件时的处理方式,可选`'skip'`, `'overwrite'`, `'rename'`, `'add'`,默认跟随实例属性| +|`split`|`bool`|`None`|当前任务是否启用多线程分块下载,默认跟随实例属性| +|`**kwargs`|`Any`|无|requests 的连接参数| + +`**kwargs`参数与`download()`一致,见上文。 + +|返回类型|说明| +|:---:|---| +|`Mission`|任务对象,可用于观察任务状态、取消任务| + +--- + +### 📌 `wait()` + +此方法用于等待所有或指定任务完成。 + +|参数名称|类型|默认值|说明| +|:---:|:---:|:---:|---| +|`mission`|`Mission`
`int`|`None`|任务对象或任务 id,为`None`时等待所有任务结束| +|`show`|`bool`|`False`|是否显示进度| +|`timeout`|`float`
`None`|`None`|超时时间,`None`或`0`不限时| + +--- + +### 📌 `cancel()` + +此方法用于取消所有等待中或执行中的任务。 + +**参数:** 无 + +**返回:**`None` + +--- + +### 📌 `get_mission()` + +此方法根据id值获取一个任务。 + +|参数名称|类型|默认值|说明| +|:---:|:---:|:---:|---| +|`mission_or_id`|`Mission`
`int`|必填|任务或任务 id| + +|返回类型|说明| +|:---:|---| +|`Mission`|任务对象| +|`None`|没有找到该任务| + +--- + +### 📌 `get_failed_missions()` + +此方法返回失败任务列表。 + +**参数:** 无 + +|返回类型|说明| +|:---:|---| +|`List[Mission]`|任务对象组成的列表| + +--- + +## ✅️️`DownloadKit`属性 + +### 📌 `goal_path` + +此属性返回文件默认保存文件夹路径,默认程序当前路径。 + +**类型:** `str` + +--- + +### 📌 `file_exists` + +此属性返回遇到同名文件时的处理方式,有以下几种:`'skip'`, `'overwrite'`, `'rename'`, `'add'`。 + +默认`'rename'`。 + +**类型:** `str` + +--- + +### 📌 `split` + +此属性返回大文件是否分块下载,默认`True`。 + +**类型:** `bool` + +--- + +### 📌 `set` + +此属性返回用于设置`DownloadKit`对象的设置对象。 + +**类型:** `Setter` + +--- + +### 📌 `timeout` + +此属性返回连接超时时间,默认 20 秒,如果驱动是`DrissionPage`的页面对象,使用页面对象的`timeout`属性。 + +**类型:** `float` + +--- + +### 📌 `retry` + +此属性返回连接失败时重试次数,默认`3`。 + +**类型:** `int` + +--- + +### 📌 `interval` + +此属性返回连接失败时重试间隔,默认 5 次。 + +**类型:** `int` + +--- + +### 📌 `is_running` + +此属性返回是否有线程还在运行。 + +**类型:** `bool` + +--- + +### 📌 `missions` + +此属性返回所有任务对象。 + +**类型:** `bool` + +--- + +### 📌 `waiting_list` + +此属性返回返回等待执行的任务队列。 + +**类型:** `List[Mission]` + +--- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/usage/add_missions.md b/docs/usage/add_missions.md new file mode 100644 index 0000000000000000000000000000000000000000..b8ae6a6dffe920024b0ea9569d2738788898cb72 --- /dev/null +++ b/docs/usage/add_missions.md @@ -0,0 +1,180 @@ +本节介绍如何添加下载任务。 + +## ✅️️ 创建任务 + +### 📌 单线程任务 + +使用`download()`方法,可创建单线程阻塞式任务。 + +即使遇到大文件,`download()`也只有一个线程执行下载,不会分块。 + +该方法会在文件下载完成后才让程序继续往下运行。 + +`download()`返回任务结果和信息组成的`tuple`,第一位是任务结果,第二位是任务信息。 + +如果下载成功,任务信息返回文件路径,如果失败,返回失败原因。 + +任务结果有以下几种: + +- `'success'`:下载成功 +- `'skipped'`:已跳过 +- `'canceled'`:被取消 +- `False`:任务失败 + +**示例:** + +```python +from DownloadKit import DowwnloadKit + +d = DownloadKit() +url = 'https://gitee.com/static/images/logo-black.svg' + +d.download(url) +``` + +--- + +### 📌 多线程并发任务 + +使用`add()`方法,可添加并发任务。 + +`add()`方法返回`Mission`对象,可以用于任务管理,在任务管理章节介绍。 + +**示例:** + +```python +from DownloadKit import DowwnloadKit + +d = DownloadKit() +url1 = 'https://gitee.com/static/images/logo-black.svg' +url2 = 'https://gitee.com/static/images/logo-black.svg' + +m1 = d.add(url1) +m2 = d.add(url2) +``` + +--- + +### 📌 多线程阻塞式任务 + +如果想使用多线程下载大文件,且需要在这个文件下载完再执行后面的语句,可以在`add()`后面使用`wait()`方法,可创建单线程阻塞式任务。 + +`wait()`方法有`show_msg`参数,可指定是否打印下载进度。 + +**示例:** + +```python +from DownloadKit import DowwnloadKit + +d = DownloadKit() +url = 'https://gitee.com/static/images/logo-black.svg' + +d.add(url).wait(show_msg=False) +``` + +--- + +### 📌 大文件分块并行下载 + +除了多个任务并行执行,单个文件也可以分为多个子任务分块同时下载。 + +`add()`方法的`split`参数可以设置是否启用分块下载,默认为`True`。 + +除了`split`参数,还需符合两个条件,分块下载才会执行: + +- 服务器支持分块下载 + +- 目标文件大小小于设定的分块大小 + +分块大小默认为 50MB,可用`set.block_size()`设置。 + +**示例:** + +```python +from DownloadKit import DowwnloadKit + +d = DownloadKit() +d.set.block_size('30m') +url = 'https://dldir1.qq.com/qqfile/qq/TIM3.4.8/TIM3.4.8.22086.exe' + +d.add(url) # 默认启用分块下载 +d.add(url, split=False) # 禁用分块下载 +``` + +--- + +### 📌 post 方式 + +当`download()`或`add()`存在`data`或`json`参数时,会使用 post 方式进行连接。 + +不存在这两个参数时,用 get 方式连接。 + +**示例:** + +```pyton +data = {'abc': 123} +d.download(url, data=data) # 自动采用post方式 +``` + +--- + +## ✅️️ 任务参数 + +`download()`和`add()`方法参数基本一致,有微小差别。 + +### 📌 `download()` + +|参数名称|类型|默认值|说明| +|:---:|:---:|:---:|---| +|`file_url`|`str`|必填|文件网址| +|`goal_path`|`str`
`Path`|`None`|保存路径,为`None`时保存到当前文件夹| +|`rename`|`str`|`None`|指定文件另存的名称,可不带后缀,程序会自动补充| +|`file_exists`|`str`|`None`|遇到同名文件时的处理方式,可选`'skip'`, `'overwrite'`, `'rename'`, `'add'`,默认跟随实例属性| +|`show_msg`|`bool`|`True`|是否打印下载信息和进度| +|`**kwargs`|`Any`|无|requests 的连接参数| + +--- + +### 📌 `add()` + +|参数名称|类型|默认值|说明| +|:---:|:---:|:---:|---| +|`file_url`|`str`|必填|文件网址| +|`goal_path`|`str`
`Path`|`None`|保存路径,为`None`时保存到当前文件夹| +|`rename`|``str`|`None`|指定文件另存的名称,可不带后缀,程序会自动补充| +|`file_exists`|`str`|`None`|遇到同名文件时的处理方式,可选`'skip'`, `'overwrite'`, `'rename'`, `'add'`,默认跟随实例属性| +|`split`|`bool`|`None`|是否启用多线程分块下载,默认跟随实例属性| +|`**kwargs`|`Any`|无|requests 的连接参数| + +--- + +### 📌 连接参数 + +连接参数即`**kwargs`允许接收到参数,与 requests 的`get()`方法一致。 + +|参数名称|类型|说明| +|:---:|:---:|---| +|`timeout`|`float`|连接超时时间| +|`params`|`dict`|查询参数字典| +|`headers`|`dict`|headers| +|`cookies`|`Any`|cookies| +|`data`|`Any`|data 数据| +|`json`|`Any`|json 数据| +|`files`|`Any`|文件数据| +|`auth`|`Tuple[str, str]`
`HTTPBasicAuth`|认证元组或对象| +|`allow_redirects`|`bool`|是否允许自动跳转| +|`proxies`|`dict`|代理 ip| +|`hooks`|`dict`|回调方法| +|`verify`|`bool`|是否验证SSL证书| +|`cert`|`str`
`Tuple[str, str]`|SSL客户端证书| + + +**示例:** + +```python +from DownloadKit import DownloadKit + +d = DownloadKit() +h = {'referer': 'demourl.com'} +d.download(url, headers=h) +``` \ No newline at end of file diff --git a/docs/usage/create_object.md b/docs/usage/create_object.md new file mode 100644 index 0000000000000000000000000000000000000000..5167a757b9e704da811830c9fa93e29af927ef38 --- /dev/null +++ b/docs/usage/create_object.md @@ -0,0 +1,60 @@ +## ✅️️ 创建`DownloadKit`对象 + +创建`DownloadKit`对象时,`driver`参数可传入一个用于携带登录信息的对象,可以是多种类型。 + +当传入的是`DrissionPage`的页面对象时,还可以根据页面访问的 url 自动设置`referer`参数。 + +| 初始化参数 | 类型 | 默认值 | 说明 | +|:-------------:|:--------------------------------------------------------------------------------------------------------------:|:----------:|-------------------------------------------------------------| +| `goal_path` | `str`
`Path` | `None` | 文件保存路径 | +| `roads` | `int` | `10` | 可同时运行的线程数 | +| `driver` | `Session`
`SessionOptions`
`ChromiumPage`
`SessionPage`
`ChromiumTab`
`WebPage`
`WebPageTab` | `None` | 用于提供下载连接信息的页面或链接对象 | +| `file_exists` | `str` | `'renmae'` | 有同名文件名时的处理方式,可选`'skip'`, `'overwrite'`, `'rename'`, `'add'` | + +--- + +## ✅️️ 示例 + +### 📌 直接创建 + +```python +from DownloadKit import DownloadKit + +d = DownloadKit() +``` + +--- + +### 📌 接收`Session`对象 + +```python +from requests import Session +from DownloadKit import DownloadKit + +session = Session() +d = DownloadKit(session=session) +``` + +--- + +### 📌 接收`SessionOptions`对象 + +```python +from DrissionPage import SessionOptions +from DownloadKit import DownloadKit + +so = SessionOptions() +d = DownloadKit(session=so) +``` + +--- + +### 📌 接收页面对象 + +```python +from DrissionPage import ChromiumPage +from DownloadKit import DownloadKit + +p = ChromiumPage() +d = DownloadKit(session=p) +``` \ No newline at end of file diff --git a/docs/usage/misssions.md b/docs/usage/misssions.md new file mode 100644 index 0000000000000000000000000000000000000000..bfa00ca02e6ad631d8a1363f81a468593c7acfc4 --- /dev/null +++ b/docs/usage/misssions.md @@ -0,0 +1,276 @@ +本节介绍下载任务的管理。 + +`add()`方法会返回一个`Mission`对象,该对象可用于查看任务信息和管理任务。 + +## ✅️️ 任务进度 + +### 📌 `rate` + +该属性返回任务完成的百分比。 + +**类型:**`float` + +**示例:** + +```python +d = DownloadKit() +m = d.add(url) + +print(m.rate) +``` + +--- + +### 📌 等待单个任务结束 + +`Mission`对象的`wait()`方法可等待该任务结束。 + +|参数名称|类型|默认值|说明| +|:---:|:---:|:---:|---| +|`show`|`bool`|`True`|是否打印下载信息| +|`timeout`|`float`|`0`|超时时间,`0`表示不限时| + +|返回类型|说明| +|`tuple`|任务结果和信息组成的`tuple`,格式:(任务结果, 任务信息)| + +**示例:** + +```python +d = DownloadKit() +m = d.add(url) + +m.wait() +``` + +--- + +### 📌 等待所有任务结束 + +`DownloadKit`对象的`wait()`方法,可等待所有任务结束。 + +|参数名称|类型|默认值|说明| +|:---:|:---:|:---:|---| +|`mission`|`Mission`
`int`|`None`|任务对象或任务 id,为`None`时等待所有任务结束| +|`show`|`bool`|`False`|是否显示进度| +|`timeout`|`float`
`None`|`None`|超时时间,`None`或`0`不限时| + +**示例:** + +```python +d = DownloadKit() +d.add(url1) +d.add(url2) + +d.wait() +``` + +--- + +### 📌 取消任务 + +`cancel()`用于中途取消任务。 + +**参数:** 无 + +**返回:**`None` + +--- + +### 📌 删除已下载文件 + +`del_file()`用于删除任务已下载的文件。 + +**参数:** 无 + +**返回:**`None` + +--- + +## ✅️️ 任务信息 + +### 📌 任务状态 + +`state`属性返回任务状态,有以下三种: + +- `'waiting'`:等待开始 +- `'running'`:运行中 +- `'done'`:已结束 + +任务状态不能看出任务是否成功,只能显示任务是否在运行。 + +--- + +### 📌 任务结果 + +`result`属性返回任务结果,有以下几种: + +- `'success'`:下载成功 +- `'skipped'`:跳过,存在同名文件,且设置为跳过时 +- `'canceled'`:被取消 +- `False`:任务失败 +- `None`:未知,任务还没结束 + +--- + +### 📌 任务信息 + +`info`属性返回任务信息,在任务不同阶段,会返回不同信息。 + +`info`是对当前状态的文字解释,如任务失败时,会返回失败原因,成功时会返回文件保存路径。 + +--- + +## ✅️️ 获取任务对象 + +### 📌 获取所有任务对象 + +`DownloadKit`对象的`missions`属性以`liist`方式返回所有任务对象。 + +**示例:** + +```python +d = DownloadKit() +d.add(url) +print(d.missions) +``` + +--- + +### 📌 查找任务 + +`DownloadKit`对象的`get_mission()`方法可根据任务 id 获取任务对象。 + +|参数名称|类型|默认值|说明| +|:---:|:---:|:---:|---| +|`mission_or_id`|`Mission`
`int`|必填|任务或任务 id| + +|返回类型|说明| +|:---:|---| +|`Mission`|任务对象| +|`None`|没有找到该任务| + +--- + +### 📌 获取失败的任务 + +`DownloadKit`对象的`get_failed_missions()`方法可以`list`方式返回失败的任务。 + +**参数:** 无 + +|返回类型|说明| +|:---:|---| +|`List[Mission]`|任务对象组成的列表| + +--- + +## ✅️️ `Mission`对象的属性 + +### 📌 `id` + +此属性返回任务 id。 + +**类型:**`int` + +--- + +### 📌 `data` + +此属性返回任务使用的数据,即创建任务时输入的参数。 + +**类型:**`MissionData` + +--- + +### 📌 `state` + +此属性返回任务状态,有三种:`'waiting'`、`'running'`、`'done'`。 + +**类型:**`str` + +--- + +### 📌 `result` + +此属性返回任务结果,有以下几种:`'success'`、`'skipped'`、`'canceled'`、`False`、`None` + +**类型:**`str` + +--- + +### 📌 `info` + +此属性返回任务描述信息。 + +**类型:**`str` + +--- + +### 📌 `is_done` + +此属性返回任务是否已完成。 + +**类型:**`bool` + +--- + +### 📌 `size` + +此属性返回文件大小。 + +**类型:**`int`或`None` + +--- + +### 📌 `tasks` + +此属性以`list`方式返回所有子任务 + +**类型:**`List[Task]` + +--- + +### 📌 `tasks_count` + +此属性返回子任务数量。 + +**类型:**`int` + +--- + +### 📌 `done_tasks_count` + +此属性返回已完成的子任务数量。 + +**类型:**`int` + +--- + +### 📌 `file_name` + +此属性返回文件名。 + +**类型:**`str`或`None` + +--- + +### 📌 `method` + +此属性返回连接方式,`'get'`或`'post'`。 + +**类型:**`str` + +--- + +### 📌 `path` + +此属性返回文件保存路径。 + +**类型:**`str` + +--- + +### 📌 `rate` + +此属性以百分比方式返回下载进度。 + +**类型:**`float` diff --git a/docs/usage/settings.md b/docs/usage/settings.md new file mode 100644 index 0000000000000000000000000000000000000000..0a464a4470cd1e8f0584f18148b8eda1ecf39ed6 --- /dev/null +++ b/docs/usage/settings.md @@ -0,0 +1,265 @@ +本节介绍`DownloadKit`对象相关设置。 + +## ✅️️ 使用方法 + +### 📌 全局设置 + +使用`DownloadKit`对象的`set.xxxx()`方法,可对各种允许参数进行设置。 + +这种方法设置的参数时全局有效的,之后新建的任务会默认使用。 + +```python +from DownloadKit import DownloadKit + +d = DownloadKit() +d.set.block_size('10m') # 设置分块大小 +``` + +--- + +### 📌 每个任务独立设置 + +每次新建任务时,可设置当前项目有效的设置,覆盖全局设置。 + +```python +from DownloadKit import DownloadKit + +d = DownloadKit() +d.set.goal_path('tmp1') # 设置全局保存路径 + +d.add(url, goal_path='tmp2') # 创建任务时指定保存路径 +``` + +--- + +## ✅️️ 运行设置 + +### 📌 `set.driver()` + +此方法用于设置提供下载连接信息的页面或链接对象。 + +支持 DrissionPage 所有页面对象、`Session`对象、`SessionOptions`对象。 + +程序可从传入的对象中自动获取登录信息,如传入页面对象,还能自动设置`Referer`参数。 + +| 参数名称 | 类型 | 默认值 | 说明 | +|:--------:|:--------------------------------------------------------------------------------------------------------------:|:---:|-------------| +| `driver` | `Session`
`SessionOptions`
`ChromiumPage`
`SessionPage`
`ChromiumTab`
`WebPage`
`WebPageTab` | 必填 | 用于提供连接信息的对象 | + +**返回:**`None` + +--- + +### 📌 `set.goal_path()` + +此方法用于设置文件保存路径。 + +| 参数名称 | 类型 | 默认值 | 说明 | +|:-----------:|:---------------:|:---:|--------| +| `goal_path` | `str`
`Path` | 必填 | 文件保存路径 | + +**返回:**`None` + +--- + +### 📌 `set.if_file_exists()` + +此方法用于设置路径存在同名文件时的处理方式。 + +可选`'skip'`, `'rename'`, `'overwrite'`, `'add'`。 + +| 参数名称 | 类型 | 默认值 | 说明 | +|:------:|:-----:|:---:|---------| +| `mode` | `str` | 必填 | 处理方式字符串 | + +- `skip`:跳过,不下载 +- `overwrite`:覆盖原有文件 +- `rename`:以在后面添加序号的方式给新文件重命名 +- `add`:在原有文件末尾追加内容 + +**返回:**`None` + +--- + +### 📌 `set.if_file_exists.xxxx()` + +这几个方法用于设置路径存在同名文件时的处理方式。 + +效果与`set.if_file_exists()`一致。 + +- `skip()`:跳过,不下载 +- `overwrite()`:覆盖原有文件 +- `rename()`:以在后面添加序号的方式给新文件重命名 +- `add()`:在原有文件末尾追加内容 + +**示例:** + +```python +from DownloadKit import DownloadKit + +d = DownloadKit() +d.set.if_file_exists.skip() +``` + +--- + +### 📌 `set.roads()` + +此方法用于设置可同时运行的线程数。 + +| 参数名称 | 类型 | 默认值 | 说明 | +|:-----:|:-----:|:---:|------| +| `num` | `int` | 必填 | 线程数量 | + +**返回:**`None` + +--- + +### 📌 `set.retry()` + +此方法用于设置连接失败时重试次数。 + +| 参数名称 | 类型 | 默认值 | 说明 | +|:-------:|:-----:|:---:|------| +| `times` | `int` | 必填 | 重试次数 | + +**返回:**`None` + +--- + +### 📌 `set.interval()` + +此方法用于设置连接失败时重试间隔。 + +| 参数名称 | 类型 | 默认值 | 说明 | +|:---------:|:-------:|:---:|--------------| +| `seconds` | `float` | 必填 | 连接失败时重试间隔(秒) | + +**返回:**`None` + +--- + +### 📌 `set.timeout()` + +此方法用于设置连接超时时间。 + +| 参数名称 | 类型 | 默认值 | 说明 | +|:---------:|:-------:|:---:|---------| +| `seconds` | `float` | 必填 | 超时时间(秒) | + +**返回:**`None` + +--- + +### 📌 `set.split()` + +此方法用于设置大文件是否分块下载。 + +| 参数名称 | 类型 | 默认值 | 说明 | +|:--------:|:------:|:---:|------------| +| `on_off` | `bool` | 必填 | `bool`代表开关 | + +**返回:**`None` + +--- + +### 📌 `set.block_size()` + +此方法用于设置设置分块大小。 + +| 参数名称 | 类型 | 默认值 | 说明 | +|:------:|:--------------:|:---:|---------------------------------| +| `size` | `str`
`int` | 必填 | 可接收`int`和`str`形式,接收`int`时以字节为单位;接收`str`时格式有:`'10b'`、`'10k'`、`'10m'`、`'10g'`四种,不区分大小写 | + +**返回:**`None` + +--- + +### 📌 `set.proxies()` + +此方法用于设置代理地址及端口,例:'127.0.0.1:1080'。 + +| 参数名称 | 类型 | 默认值 | 说明 | +|:-------:|:-----:|:------:|---------------| +| `http` | `str` | `None` | http 代理地址及端口 | +| `https` | `str` | `None` | https 代理地址及端口 | + +**返回:**`None` + +--- + +## ✅️️ 日志设置 + +日志设置方法在`set.log`属性中。 + +### 📌 `set.log.path()` + +此方法用于设置日志文件路径。 + +| 参数名称 | 类型 | 默认值 | 说明 | +|:------:|:---------------:|:---:|------| +| `path` | `str`
`Path` | 必填 | 文件路径 | + +**返回:**`None` + +--- + +### 📌 `set.log.print_all()` + +此方法用于设置打印所有任务信息。 + +**参数:** 无 + +**返回:**`None` + +--- + +### 📌 `set.log.print_failed()` + +此方法用于设置打印失败的任务。 + +**参数:** 无 + +**返回:**`None` + +--- + +### 📌 `set.log.print_nothing()` + +此方法用于设置不打印任何信息。 + +**参数:** 无 + +**返回:**`None` + +--- + +### 📌 `set.log.log_all()` + +此方法用于记录打印所有任务信息到文件。 + +**参数:** 无 + +**返回:**`None` + +--- + +### 📌 `set.log.log_failed()` + +此方法用于设置记录失败的任务到文件。 + +**参数:** 无 + +**返回:**`None` + +--- + +### 📌 `set.log.log_nothing()` + +此方法用于设置不记录任何信息到文件。 + +**参数:** 无 + +**返回:**`None` + +--- \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000000000000000000000000000000000000..16b0d317ff9850c8f68e1e460fb4cf79ba30a03d --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,80 @@ +site_name: DownloadKit +site_url: http://g1879.gitee.io/DownloadKit/ +site_author: g1879 +site_description: DownloadKit是一个简洁易用的多线程文件下载工具,支持多线程,功能丰富使用简单。 +repo_url: https://gitee.com/g1879/DownloadKit +markdown_extensions: + - admonition # 提示块 + + - pymdownx.details + - pymdownx.superfences + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences + - def_list + + - pymdownx.tasklist: # 待办列表 + custom_checkbox: true + + - tables + +theme: + name: material + font: + code: Roboto Mono + icon: + admonition: + note: octicons/tag-16 + abstract: octicons/checklist-16 + info: octicons/info-16 + tip: octicons/squirrel-16 + success: octicons/check-16 + question: octicons/question-16 + warning: octicons/alert-16 + failure: octicons/x-circle-16 + danger: octicons/zap-16 + bug: octicons/bug-16 + example: octicons/beaker-16 + quote: octicons/quote-16 + + palette: + - scheme: default + primary: brown + toggle: + icon: material/brightness-7 + name: Switch to dark mode + + # Palette toggle for dark mode + - scheme: slate + primary: brown + toggle: + icon: material/brightness-4 + name: Switch to light mode + + features: + - navigation.top # 返回顶部按钮 + - navigation.tracking + - toc.follow + - content.code.copy # 代码复制按钮 + - navigation.tabs # 使用标签页 + - navigation.tabs.sticky # 标签页不消失 + - header.autohide # 自动隐藏标题栏 + - navigation.footer # 上一页和下一页 + +nav: + - 欢迎: index.md + + - 安装和导入: install_and_import.md + + - 使用方法: + - 🐘 创建对象: usage/create_object.md + - 🐎 添加任务: usage/add_missions.md + - 🐒 任务管理: usage/misssions.md + - 🦍 运行设置: usage/settings.md + - 🐇 APIs: usage/APIs.md + + - 版本历史: history.md + + - 意见建议: https://gitee.com/g1879/DownloadKit/issues diff --git a/setup.py b/setup.py index c5b4d008711e95b91ff7f24dd915ab1249e2043a..794c809d32d6bb0cd51d8c32c4b5744b48e99556 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh: setup( name="DownloadKit", - version="1.0.0", + version="1.0.2", author="g1879", author_email="g1879@qq.com", description="一个简洁易用的多线程文件下载工具。", diff --git a/site/404.html b/site/404.html new file mode 100644 index 0000000000000000000000000000000000000000..9b36032cefe13cf109bd882041bd860e0eb9a955 --- /dev/null +++ b/site/404.html @@ -0,0 +1,582 @@ + + + + + + + + + + + + + + + + + + + + + + DownloadKit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/site/assets/images/favicon.png b/site/assets/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf13b9f9d978896599290a74f77d5dbe7d1655c Binary files /dev/null and b/site/assets/images/favicon.png differ diff --git a/site/assets/javascripts/bundle.fc8c2696.min.js b/site/assets/javascripts/bundle.fc8c2696.min.js new file mode 100644 index 0000000000000000000000000000000000000000..359c24cd84bb69dddeea5eb0b6f10273af59587f --- /dev/null +++ b/site/assets/javascripts/bundle.fc8c2696.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Ri=Object.create;var gr=Object.defineProperty;var ki=Object.getOwnPropertyDescriptor;var Hi=Object.getOwnPropertyNames,kt=Object.getOwnPropertySymbols,Pi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,on=Object.prototype.propertyIsEnumerable;var nn=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&nn(e,r,t[r]);if(kt)for(var r of kt(t))on.call(t,r)&&nn(e,r,t[r]);return e};var an=(e,t)=>{var r={};for(var n in e)yr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&kt)for(var n of kt(e))t.indexOf(n)<0&&on.call(e,n)&&(r[n]=e[n]);return r};var Ht=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var $i=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Hi(t))!yr.call(e,o)&&o!==r&&gr(e,o,{get:()=>t[o],enumerable:!(n=ki(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Ri(Pi(e)):{},$i(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var cn=Ht((xr,sn)=>{(function(e,t){typeof xr=="object"&&typeof sn!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(T){return!!(T&&T!==document&&T.nodeName!=="HTML"&&T.nodeName!=="BODY"&&"classList"in T&&"contains"in T.classList)}function c(T){var Qe=T.type,De=T.tagName;return!!(De==="INPUT"&&s[Qe]&&!T.readOnly||De==="TEXTAREA"&&!T.readOnly||T.isContentEditable)}function f(T){T.classList.contains("focus-visible")||(T.classList.add("focus-visible"),T.setAttribute("data-focus-visible-added",""))}function u(T){T.hasAttribute("data-focus-visible-added")&&(T.classList.remove("focus-visible"),T.removeAttribute("data-focus-visible-added"))}function p(T){T.metaKey||T.altKey||T.ctrlKey||(a(r.activeElement)&&f(r.activeElement),n=!0)}function m(T){n=!1}function d(T){a(T.target)&&(n||c(T.target))&&f(T.target)}function h(T){a(T.target)&&(T.target.classList.contains("focus-visible")||T.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(T.target))}function v(T){document.visibilityState==="hidden"&&(o&&(n=!0),G())}function G(){document.addEventListener("mousemove",N),document.addEventListener("mousedown",N),document.addEventListener("mouseup",N),document.addEventListener("pointermove",N),document.addEventListener("pointerdown",N),document.addEventListener("pointerup",N),document.addEventListener("touchmove",N),document.addEventListener("touchstart",N),document.addEventListener("touchend",N)}function oe(){document.removeEventListener("mousemove",N),document.removeEventListener("mousedown",N),document.removeEventListener("mouseup",N),document.removeEventListener("pointermove",N),document.removeEventListener("pointerdown",N),document.removeEventListener("pointerup",N),document.removeEventListener("touchmove",N),document.removeEventListener("touchstart",N),document.removeEventListener("touchend",N)}function N(T){T.target.nodeName&&T.target.nodeName.toLowerCase()==="html"||(n=!1,oe())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),G(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var fn=Ht(Er=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(f){return!1}},r=t(),n=function(f){var u={next:function(){var p=f.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(f){return encodeURIComponent(f).replace(/%20/g,"+")},i=function(f){return decodeURIComponent(String(f).replace(/\+/g," "))},s=function(){var f=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof f){var d=this;p.forEach(function(oe,N){d.append(N,oe)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),f._entries&&(f._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(c,f){typeof c!="string"&&(c=String(c)),f&&typeof f!="string"&&(f=String(f));var u=document,p;if(f&&(e.location===void 0||f!==e.location.href)){f=f.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=f,u.head.appendChild(p);try{if(p.href.indexOf(f)!==0)throw new Error(p.href)}catch(T){throw new Error("URL unable to set base "+f+" due to "+T)}}var m=u.createElement("a");m.href=c,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=c,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!f)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,G=!0,oe=this;["append","delete","set"].forEach(function(T){var Qe=h[T];h[T]=function(){Qe.apply(h,arguments),v&&(G=!1,oe.search=h.toString(),G=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var N=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==N&&(N=this.search,G&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},s=i.prototype,a=function(c){Object.defineProperty(s,c,{get:function(){return this._anchorElement[c]},set:function(f){this._anchorElement[c]=f},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(c){a(c)}),Object.defineProperty(s,"search",{get:function(){return this._anchorElement.search},set:function(c){this._anchorElement.search=c,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(s,{toString:{get:function(){var c=this;return function(){return c.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(c){this._anchorElement.href=c,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(c){this._anchorElement.pathname=c},enumerable:!0},origin:{get:function(){var c={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],f=this._anchorElement.port!=c&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(f?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(c){},enumerable:!0},username:{get:function(){return""},set:function(c){},enumerable:!0}}),i.createObjectURL=function(c){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(c){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er)});var Kr=Ht((Mt,qr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Mt=="object"&&typeof qr=="object"?qr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Mt=="object"?Mt.ClipboardJS=r():t.ClipboardJS=r()})(Mt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return Ci}});var s=i(279),a=i.n(s),c=i(370),f=i.n(c),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(O){return!1}}var d=function(O){var E=p()(O);return m("cut"),E},h=d;function v(j){var O=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[O?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=j,E}var G=function(O,E){var H=v(O);E.container.appendChild(H);var I=p()(H);return m("copy"),H.remove(),I},oe=function(O){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof O=="string"?H=G(O,E):O instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(O==null?void 0:O.type)?H=G(O.value,E):(H=p()(O),m("copy")),H},N=oe;function T(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?T=function(E){return typeof E}:T=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},T(j)}var Qe=function(){var O=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=O.action,H=E===void 0?"copy":E,I=O.container,q=O.target,Me=O.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&T(q)==="object"&&q.nodeType===1){if(H==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return N(Me,{container:I});if(q)return H==="cut"?h(q):N(q,{container:I})},De=Qe;function $e(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$e=function(E){return typeof E}:$e=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},$e(j)}function wi(j,O){if(!(j instanceof O))throw new TypeError("Cannot call a class as a function")}function rn(j,O){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=$e(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var q=this;this.listener=f()(I,"click",function(Me){return q.onClick(Me)})}},{key:"onClick",value:function(I){var q=I.delegateTarget||I.currentTarget,Me=this.action(q)||"copy",Rt=De({action:Me,container:this.container,target:this.target(q),text:this.text(q)});this.emit(Rt?"success":"error",{action:Me,text:Rt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(I){return vr("action",I)}},{key:"defaultTarget",value:function(I){var q=vr("target",I);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(I){return vr("text",I)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(I){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return N(I,q)}},{key:"cut",value:function(I){return h(I)}},{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof I=="string"?[I]:I,Me=!!document.queryCommandSupported;return q.forEach(function(Rt){Me=Me&&!!document.queryCommandSupported(Rt)}),Me}}]),E}(a()),Ci=Ai},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==o;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}n.exports=s},438:function(n,o,i){var s=i(828);function a(u,p,m,d,h){var v=f.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function c(u,p,m,d,h){return typeof u.addEventListener=="function"?a.apply(null,arguments):typeof m=="function"?a.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return a(v,p,m,d,h)}))}function f(u,p,m,d){return function(h){h.delegateTarget=s(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=c},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(n,o,i){var s=i(879),a=i(438);function c(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(h))throw new TypeError("Third argument must be a Function");if(s.node(m))return f(m,d,h);if(s.nodeList(m))return u(m,d,h);if(s.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function f(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return a(document.body,m,d,h)}n.exports=c},817:function(n){function o(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),f=document.createRange();f.selectNodeContents(i),c.removeAllRanges(),c.addRange(f),s=c.toString()}return s}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function f(){c.off(i,f),s.apply(a,arguments)}return f._=s,this.on(i,f,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,f=a.length;for(c;c{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var ns=/["'&<>]/;Go.exports=os;function os(e){var t=""+e,r=ns.exec(t);if(!r)return t;var n,o="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(f[0]===6||f[0]===2)){r=0;continue}if(f[0]===3&&(!i||f[1]>i[0]&&f[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],s;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(a){s={error:a}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(s)throw s.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||a(m,d)})})}function a(m,d){try{c(n[m](d))}catch(h){p(i[0][3],h)}}function c(m){m.value instanceof et?Promise.resolve(m.value.v).then(f,u):p(i[0][2],m)}function f(m){a("next",m)}function u(m){a("throw",m)}function p(m,d){m(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function ln(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Ee=="function"?Ee(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),o(a,c,s.done,s.value)})}}function o(i,s,a,c){Promise.resolve(c).then(function(f){i({value:f,done:a})},s)}}function A(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var $t=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Ee(s),c=a.next();!c.done;c=a.next()){var f=c.value;f.remove(this)}}catch(v){t={error:v}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var u=this.initialTeardown;if(A(u))try{u()}catch(v){i=v instanceof $t?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=Ee(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{mn(h)}catch(v){i=i!=null?i:[],v instanceof $t?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new $t(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)mn(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Sr=Ie.EMPTY;function It(e){return e instanceof Ie||e&&"closed"in e&&A(e.remove)&&A(e.add)&&A(e.unsubscribe)}function mn(e){A(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,s=o.isStopped,a=o.observers;return i||s?Sr:(this.currentObservers=null,a.push(r),new Ie(function(){n.currentObservers=null,Ve(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,s=n.isStopped;o?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,n){return new En(r,n)},t}(F);var En=function(e){ie(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Sr},t}(x);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ie(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,s=n._infiniteTimeWindow,a=n._timestampProvider,c=n._windowTime;o||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,s=o._buffer,a=s.slice(),c=0;c0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var s=r.actions;n!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Ut);var Tn=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Wt);var Te=new Tn(Sn);var _=new F(function(e){return e.complete()});function Dt(e){return e&&A(e.schedule)}function Cr(e){return e[e.length-1]}function Ye(e){return A(Cr(e))?e.pop():void 0}function Oe(e){return Dt(Cr(e))?e.pop():void 0}function Vt(e,t){return typeof Cr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function zt(e){return A(e==null?void 0:e.then)}function Nt(e){return A(e[ft])}function qt(e){return Symbol.asyncIterator&&A(e==null?void 0:e[Symbol.asyncIterator])}function Kt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Ni(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Qt=Ni();function Yt(e){return A(e==null?void 0:e[Qt])}function Gt(e){return pn(this,arguments,function(){var r,n,o,i;return Pt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,et(r.read())];case 3:return n=s.sent(),o=n.value,i=n.done,i?[4,et(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,et(o)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Bt(e){return A(e==null?void 0:e.getReader)}function U(e){if(e instanceof F)return e;if(e!=null){if(Nt(e))return qi(e);if(pt(e))return Ki(e);if(zt(e))return Qi(e);if(qt(e))return On(e);if(Yt(e))return Yi(e);if(Bt(e))return Gi(e)}throw Kt(e)}function qi(e){return new F(function(t){var r=e[ft]();if(A(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Ki(e){return new F(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?L(function(o,i){return e(o,i,n)}):de,ge(1),r?He(t):Vn(function(){return new Xt}))}}function zn(){for(var e=[],t=0;t=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(f){var u,p,m,d=0,h=!1,v=!1,G=function(){p==null||p.unsubscribe(),p=void 0},oe=function(){G(),u=m=void 0,h=v=!1},N=function(){var T=u;oe(),T==null||T.unsubscribe()};return y(function(T,Qe){d++,!v&&!h&&G();var De=m=m!=null?m:r();Qe.add(function(){d--,d===0&&!v&&!h&&(p=$r(N,c))}),De.subscribe(Qe),!u&&d>0&&(u=new rt({next:function($e){return De.next($e)},error:function($e){v=!0,G(),p=$r(oe,o,$e),De.error($e)},complete:function(){h=!0,G(),p=$r(oe,s),De.complete()}}),U(T).subscribe(u))})(f)}}function $r(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function z(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function er(e){return C(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),V(e===_e()),B())}function Xe(e){return{x:e.offsetLeft,y:e.offsetTop}}function Qn(e){return C(b(window,"load"),b(window,"resize")).pipe(Ce(0,Te),l(()=>Xe(e)),V(Xe(e)))}function tr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return C(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,Te),l(()=>tr(e)),V(tr(e)))}var Gn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Dr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),ga?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Dr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=va.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Bn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Xn=typeof WeakMap!="undefined"?new WeakMap:new Gn,Zn=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=ya.getInstance(),n=new Aa(t,r,this);Xn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Zn.prototype[e]=function(){var t;return(t=Xn.get(this))[e].apply(t,arguments)}});var Ca=function(){return typeof rr.ResizeObserver!="undefined"?rr.ResizeObserver:Zn}(),eo=Ca;var to=new x,Ra=$(()=>k(new eo(e=>{for(let t of e)to.next(t)}))).pipe(g(e=>C(ze,k(e)).pipe(R(()=>e.disconnect()))),J(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ye(e){return Ra.pipe(S(t=>t.observe(e)),g(t=>to.pipe(L(({target:r})=>r===e),R(()=>t.unobserve(e)),l(()=>he(e)))),V(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ir(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var ro=new x,ka=$(()=>k(new IntersectionObserver(e=>{for(let t of e)ro.next(t)},{threshold:0}))).pipe(g(e=>C(ze,k(e)).pipe(R(()=>e.disconnect()))),J(1));function ar(e){return ka.pipe(S(t=>t.observe(e)),g(t=>ro.pipe(L(({target:r})=>r===e),R(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function no(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=he(e),o=bt(e);return r>=o.height-n.height-t}),B())}var sr={drawer:z("[data-md-toggle=drawer]"),search:z("[data-md-toggle=search]")};function oo(e){return sr[e].checked}function Ke(e,t){sr[e].checked!==t&&sr[e].click()}function Ue(e){let t=sr[e];return b(t,"change").pipe(l(()=>t.checked),V(t.checked))}function Ha(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Pa(){return C(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(V(!1))}function io(){let e=b(window,"keydown").pipe(L(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:oo("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),L(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!Ha(n,r)}return!0}),pe());return Pa().pipe(g(t=>t?_:e))}function le(){return new URL(location.href)}function ot(e){location.href=e.href}function ao(){return new x}function so(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)so(e,r)}function M(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)so(n,o);return n}function cr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function co(){return location.hash.substring(1)}function Vr(e){let t=M("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function $a(){return b(window,"hashchange").pipe(l(co),V(co()),L(e=>e.length>0),J(1))}function fo(){return $a().pipe(l(e=>ce(`[id="${e}"]`)),L(e=>typeof e!="undefined"))}function zr(e){let t=matchMedia(e);return Zt(r=>t.addListener(()=>r(t.matches))).pipe(V(t.matches))}function uo(){let e=matchMedia("print");return C(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(V(e.matches))}function Nr(e,t){return e.pipe(g(r=>r?t():_))}function fr(e,t={credentials:"same-origin"}){return ue(fetch(`${e}`,t)).pipe(fe(()=>_),g(r=>r.status!==200?Tt(()=>new Error(r.statusText)):k(r)))}function We(e,t){return fr(e,t).pipe(g(r=>r.json()),J(1))}function po(e,t){let r=new DOMParser;return fr(e,t).pipe(g(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),J(1))}function ur(e){let t=M("script",{src:e});return $(()=>(document.head.appendChild(t),C(b(t,"load"),b(t,"error").pipe(g(()=>Tt(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),R(()=>document.head.removeChild(t)),ge(1))))}function lo(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function mo(){return C(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(lo),V(lo()))}function ho(){return{width:innerWidth,height:innerHeight}}function bo(){return b(window,"resize",{passive:!0}).pipe(l(ho),V(ho()))}function vo(){return Q([mo(),bo()]).pipe(l(([e,t])=>({offset:e,size:t})),J(1))}function pr(e,{viewport$:t,header$:r}){let n=t.pipe(Z("size")),o=Q([n,r]).pipe(l(()=>Xe(e)));return Q([r,t,o]).pipe(l(([{height:i},{offset:s,size:a},{x:c,y:f}])=>({offset:{x:s.x-c,y:s.y-f+i},size:a})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(s=>{let a=document.createElement("script");a.src=i,a.onload=s,document.body.appendChild(a)})),Promise.resolve())}var r=class extends EventTarget{constructor(n){super(),this.url=n,this.m=i=>{i.source===this.w&&(this.dispatchEvent(new MessageEvent("message",{data:i.data})),this.onmessage&&this.onmessage(i))},this.e=(i,s,a,c,f)=>{if(s===`${this.url}`){let u=new ErrorEvent("error",{message:i,filename:s,lineno:a,colno:c,error:f});this.dispatchEvent(u),this.onerror&&this.onerror(u)}};let o=document.createElement("iframe");o.hidden=!0,document.body.appendChild(this.iframe=o),this.w.document.open(),this.w.document.write(` + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + + + + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

版本历史

+ +

v1.0.2

+
    +
  • 支持DrissionPage v3.2.31 版
  • +
  • 修改设置项 api,set_xxxx()改为set.xxxx()形式
  • +
  • __init__()方法的sessiondriver代替,但保留向后兼容
  • +
  • 可更准确显示下载进度
  • +
  • Task增加下载进度属性
  • +
  • 处理已存在文件的情况增加add模式
  • +
  • 增加日志设置
  • +
  • 优化程序逻辑,修复一些问题
  • +
+
+

v0.5.3

+
    +
  • 支持DrissionPage v3.2.0 版
  • +
  • 增加missions属性
  • +
+
+

v0.4.4

+
    +
  • 适配DrissionPage v3.1.0 版
  • +
  • 增加split全局 设置
  • +
+
+

v0.4.1

+
    +
  • 支持DrissionPage v3.0 版
  • +
  • 增加set_log()set_print()set_proxies()
  • +
  • 改用ByteRecorder保存数据
  • +
  • 新增MissionData
  • +
  • 大量修改结构,优化逻辑
  • +
+
+

v0.3.5

+
    +
  • 新增MissionData
  • +
  • add()方法删除session参数
  • +
  • __init__()方法删除timeout参数
  • +
  • 优化timeoutretryinterval属性逻辑
  • +
+
+

v0.3.3

+
    +
  • referer参数可从传入的页面对象获取
  • +
  • 大量优化
  • +
+
+

v0.3.0

+
    +
  • 完成主要功能
  • +
  • 完善逻辑
  • +
+
+

v0.1.0

+
    +
  • 完成基本框架
  • +
+ + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000000000000000000000000000000000000..b1c30fd11fcd2485f331ca44d18f619a43f7d141 --- /dev/null +++ b/site/index.html @@ -0,0 +1,761 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + DownloadKit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + + + + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

欢迎

+ +

💬 简介

+

DownloadKit 是一个基于 python 的简洁易用的多线程文件下载工具。 +使用简单,功能强大。

+

当前版本:v1.0.2

+
+

💖 特性

+
    +
  • 多线程,可同时下载多个文件
  • +
  • 大文件自动分块用多线程下载
  • +
  • 自动任务调度,简易的任务添加方式
  • +
  • 可使用已有Session对象,便于保持登录状态
  • +
  • 与 DrissionPage 良好兼容
  • +
  • 自动创建目标路径
  • +
  • 自动去除路径中的非法字符
  • +
  • 自动处理文件名冲突
  • +
  • 可对现有文件追加内容
  • +
  • 连接失败自动重试
  • +
+
+

💥 简单示例

+
from DownloadKit import DownloadKit
+
+# 创建下载器对象
+d = DownloadKit(r'.\files')
+
+# 添加多个任务
+url1 = 'https://gitee.com/static/images/logo.svg?t=158106664'
+url2 = 'https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png'
+
+d.download(url1)
+d.download(url2)
+
+
+

☕ 请我喝咖啡

+

如果本项目对您有所帮助,不妨请作者我喝杯咖啡 :)

+

+ + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/site/install_and_import/index.html b/site/install_and_import/index.html new file mode 100644 index 0000000000000000000000000000000000000000..a1296ab5a361398c0d64bf8b52e6e6e4c2de11b3 --- /dev/null +++ b/site/install_and_import/index.html @@ -0,0 +1,722 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 安装和导入 - DownloadKit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + + + + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

安装和导入

+ +

🎟️ 安装

+

如果您安装过 DrissionPage,本库已自动安装。

+
pip install DownloadKit
+
+
+

🎫 导入

+
from DownloadKit import DownloadKit
+
+ + + + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/site/search/search_index.json b/site/search/search_index.json new file mode 100644 index 0000000000000000000000000000000000000000..58a92b2b3739077aa30084b7ec821b0279a7a160 --- /dev/null +++ b/site/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"\u6b22\u8fce","text":""},{"location":"#_1","title":"\ud83d\udcac \u7b80\u4ecb","text":"

DownloadKit \u662f\u4e00\u4e2a\u57fa\u4e8e python \u7684\u7b80\u6d01\u6613\u7528\u7684\u591a\u7ebf\u7a0b\u6587\u4ef6\u4e0b\u8f7d\u5de5\u5177\u3002 \u4f7f\u7528\u7b80\u5355\uff0c\u529f\u80fd\u5f3a\u5927\u3002

\u5f53\u524d\u7248\u672c\uff1av1.0.2

"},{"location":"#_2","title":"\ud83d\udc96 \u7279\u6027","text":"
  • \u591a\u7ebf\u7a0b\uff0c\u53ef\u540c\u65f6\u4e0b\u8f7d\u591a\u4e2a\u6587\u4ef6
  • \u5927\u6587\u4ef6\u81ea\u52a8\u5206\u5757\u7528\u591a\u7ebf\u7a0b\u4e0b\u8f7d
  • \u81ea\u52a8\u4efb\u52a1\u8c03\u5ea6\uff0c\u7b80\u6613\u7684\u4efb\u52a1\u6dfb\u52a0\u65b9\u5f0f
  • \u53ef\u4f7f\u7528\u5df2\u6709Session\u5bf9\u8c61\uff0c\u4fbf\u4e8e\u4fdd\u6301\u767b\u5f55\u72b6\u6001
  • \u4e0e DrissionPage \u826f\u597d\u517c\u5bb9
  • \u81ea\u52a8\u521b\u5efa\u76ee\u6807\u8def\u5f84
  • \u81ea\u52a8\u53bb\u9664\u8def\u5f84\u4e2d\u7684\u975e\u6cd5\u5b57\u7b26
  • \u81ea\u52a8\u5904\u7406\u6587\u4ef6\u540d\u51b2\u7a81
  • \u53ef\u5bf9\u73b0\u6709\u6587\u4ef6\u8ffd\u52a0\u5185\u5bb9
  • \u8fde\u63a5\u5931\u8d25\u81ea\u52a8\u91cd\u8bd5
"},{"location":"#_3","title":"\ud83d\udca5 \u7b80\u5355\u793a\u4f8b","text":"
from DownloadKit import DownloadKit\n# \u521b\u5efa\u4e0b\u8f7d\u5668\u5bf9\u8c61\nd = DownloadKit(r'.\\files')\n# \u6dfb\u52a0\u591a\u4e2a\u4efb\u52a1\nurl1 = 'https://gitee.com/static/images/logo.svg?t=158106664'\nurl2 = 'https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png'\nd.download(url1)\nd.download(url2)\n
"},{"location":"#_4","title":"\u2615 \u8bf7\u6211\u559d\u5496\u5561","text":"

\u5982\u679c\u672c\u9879\u76ee\u5bf9\u60a8\u6709\u6240\u5e2e\u52a9\uff0c\u4e0d\u59a8\u8bf7\u4f5c\u8005\u6211\u559d\u676f\u5496\u5561 \uff1a\uff09

"},{"location":"history/","title":"\u7248\u672c\u5386\u53f2","text":""},{"location":"history/#v102","title":"v1.0.2","text":"
  • \u652f\u6301DrissionPage v3.2.31 \u7248
  • \u4fee\u6539\u8bbe\u7f6e\u9879 api\uff0cset_xxxx()\u6539\u4e3aset.xxxx()\u5f62\u5f0f
  • __init__()\u65b9\u6cd5\u7684session\u7528driver\u4ee3\u66ff\uff0c\u4f46\u4fdd\u7559\u5411\u540e\u517c\u5bb9
  • \u53ef\u66f4\u51c6\u786e\u663e\u793a\u4e0b\u8f7d\u8fdb\u5ea6
  • Task\u589e\u52a0\u4e0b\u8f7d\u8fdb\u5ea6\u5c5e\u6027
  • \u5904\u7406\u5df2\u5b58\u5728\u6587\u4ef6\u7684\u60c5\u51b5\u589e\u52a0add\u6a21\u5f0f
  • \u589e\u52a0\u65e5\u5fd7\u8bbe\u7f6e
  • \u4f18\u5316\u7a0b\u5e8f\u903b\u8f91\uff0c\u4fee\u590d\u4e00\u4e9b\u95ee\u9898
"},{"location":"history/#v053","title":"v0.5.3","text":"
  • \u652f\u6301DrissionPage v3.2.0 \u7248
  • \u589e\u52a0missions\u5c5e\u6027
"},{"location":"history/#v044","title":"v0.4.4","text":"
  • \u9002\u914dDrissionPage v3.1.0 \u7248
  • \u589e\u52a0split\u5168\u5c40 \u8bbe\u7f6e
"},{"location":"history/#v041","title":"v0.4.1","text":"
  • \u652f\u6301DrissionPage v3.0 \u7248
  • \u589e\u52a0set_log()\u3001set_print()\u548cset_proxies()
  • \u6539\u7528ByteRecorder\u4fdd\u5b58\u6570\u636e
  • \u65b0\u589eMissionData\u7c7b
  • \u5927\u91cf\u4fee\u6539\u7ed3\u6784\uff0c\u4f18\u5316\u903b\u8f91
"},{"location":"history/#v035","title":"v0.3.5","text":"
  • \u65b0\u589eMissionData\u7c7b
  • add()\u65b9\u6cd5\u5220\u9664session\u53c2\u6570
  • __init__()\u65b9\u6cd5\u5220\u9664timeout\u53c2\u6570
  • \u4f18\u5316timeout\u3001retry\u3001interval\u5c5e\u6027\u903b\u8f91
"},{"location":"history/#v033","title":"v0.3.3","text":"
  • referer\u53c2\u6570\u53ef\u4ece\u4f20\u5165\u7684\u9875\u9762\u5bf9\u8c61\u83b7\u53d6
  • \u5927\u91cf\u4f18\u5316
"},{"location":"history/#v030","title":"v0.3.0","text":"
  • \u5b8c\u6210\u4e3b\u8981\u529f\u80fd
  • \u5b8c\u5584\u903b\u8f91
"},{"location":"history/#v010","title":"v0.1.0","text":"
  • \u5b8c\u6210\u57fa\u672c\u6846\u67b6
"},{"location":"install_and_import/","title":"\u5b89\u88c5\u548c\u5bfc\u5165","text":""},{"location":"install_and_import/#_1","title":"\ud83c\udf9f\ufe0f \u5b89\u88c5","text":"

\u5982\u679c\u60a8\u5b89\u88c5\u8fc7 DrissionPage\uff0c\u672c\u5e93\u5df2\u81ea\u52a8\u5b89\u88c5\u3002

pip install DownloadKit\n
"},{"location":"install_and_import/#_2","title":"\ud83c\udfab \u5bfc\u5165","text":"
from DownloadKit import DownloadKit\n
"},{"location":"usage/APIs/","title":"\ud83d\udc07 APIs","text":""},{"location":"usage/APIs/#downloadkit","title":"\u2705\ufe0f\ufe0f DownloadKit\u5bf9\u8c61\u65b9\u6cd5","text":""},{"location":"usage/APIs/#download","title":"\ud83d\udccc download()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u5355\u7ebf\u7a0b\u963b\u585e\u5f0f\u4e0b\u8f7d\u4e00\u4e2a\u6587\u4ef6\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e file_url str \u5fc5\u586b \u6587\u4ef6\u7f51\u5740 goal_path strPath None \u4fdd\u5b58\u8def\u5f84\uff0c\u4e3aNone\u65f6\u4fdd\u5b58\u5230\u5f53\u524d\u6587\u4ef6\u5939 rename str None \u6307\u5b9a\u6587\u4ef6\u53e6\u5b58\u7684\u540d\u79f0\uff0c\u53ef\u4e0d\u5e26\u540e\u7f00\uff0c\u7a0b\u5e8f\u4f1a\u81ea\u52a8\u8865\u5145 file_exists str None \u9047\u5230\u540c\u540d\u6587\u4ef6\u65f6\u7684\u5904\u7406\u65b9\u5f0f\uff0c\u53ef\u9009'skip', 'overwrite', 'rename', 'add'\uff0c\u9ed8\u8ba4\u8ddf\u968f\u5b9e\u4f8b\u5c5e\u6027 show_msg bool True \u662f\u5426\u6253\u5370\u4e0b\u8f7d\u4fe1\u606f\u548c\u8fdb\u5ea6 **kwargs Any \u65e0 requests \u7684\u8fde\u63a5\u53c2\u6570

\u8fde\u63a5\u53c2\u6570**kwargs\u4e0e requests \u7684get()\u65b9\u6cd5\u4e00\u81f4\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u8bf4\u660e timeout float \u8fde\u63a5\u8d85\u65f6\u65f6\u95f4 params dict \u67e5\u8be2\u53c2\u6570\u5b57\u5178 headers dict headers cookies Any cookies data Any data \u6570\u636e json Any json \u6570\u636e files Any \u6587\u4ef6\u6570\u636e auth Tuple[str, str]HTTPBasicAuth \u8ba4\u8bc1\u5143\u7ec4\u6216\u5bf9\u8c61 allow_redirects bool \u662f\u5426\u5141\u8bb8\u81ea\u52a8\u8df3\u8f6c proxies dict \u4ee3\u7406 ip hooks dict \u56de\u8c03\u65b9\u6cd5 verify bool \u662f\u5426\u9a8c\u8bc1SSL\u8bc1\u4e66 cert strTuple[str, str] SSL\u5ba2\u6237\u7aef\u8bc1\u4e66 \u8fd4\u56de\u7c7b\u578b \u8bf4\u660e tuple \u683c\u5f0f\uff1a(\u4efb\u52a1\u7ed3\u679c, \u4efb\u52a1\u4fe1\u606f)

\u4efb\u52a1\u7ed3\u679c\u6709\u5982\u4e0b\u51e0\u79cd\uff1a

  • 'success'\uff1a\u4e0b\u8f7d\u6210\u529f
  • 'skipped'\uff1a\u5df2\u8df3\u8fc7
  • 'canceled'\uff1a\u88ab\u53d6\u6d88
  • False\uff1a\u4efb\u52a1\u5931\u8d25

\u5982\u679c\u4e0b\u8f7d\u6210\u529f\uff0c\u4efb\u52a1\u4fe1\u606f\u8fd4\u56de\u6587\u4ef6\u8def\u5f84\uff0c\u5982\u679c\u5931\u8d25\uff0c\u8fd4\u56de\u5931\u8d25\u539f\u56e0\u3002

"},{"location":"usage/APIs/#add","title":"\ud83d\udccc add()","text":"

\u6b64\u65b9\u6cd5\u6dfb\u52a0\u4e00\u4e2a\u5e76\u53d1\u4efb\u52a1\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e file_url str \u5fc5\u586b \u6587\u4ef6\u7f51\u5740 goal_path strPath None \u4fdd\u5b58\u8def\u5f84\uff0c\u4e3aNone\u65f6\u4fdd\u5b58\u5230\u5f53\u524d\u6587\u4ef6\u5939 rename `str|None \u6307\u5b9a\u6587\u4ef6\u53e6\u5b58\u7684\u540d\u79f0\uff0c\u53ef\u4e0d\u5e26\u540e\u7f00\uff0c\u7a0b\u5e8f\u4f1a\u81ea\u52a8\u8865\u5145 file_exists str None \u9047\u5230\u540c\u540d\u6587\u4ef6\u65f6\u7684\u5904\u7406\u65b9\u5f0f\uff0c\u53ef\u9009'skip', 'overwrite', 'rename', 'add'\uff0c\u9ed8\u8ba4\u8ddf\u968f\u5b9e\u4f8b\u5c5e\u6027 split bool None \u5f53\u524d\u4efb\u52a1\u662f\u5426\u542f\u7528\u591a\u7ebf\u7a0b\u5206\u5757\u4e0b\u8f7d\uff0c\u9ed8\u8ba4\u8ddf\u968f\u5b9e\u4f8b\u5c5e\u6027 **kwargs Any \u65e0 requests \u7684\u8fde\u63a5\u53c2\u6570

**kwargs\u53c2\u6570\u4e0edownload()\u4e00\u81f4\uff0c\u89c1\u4e0a\u6587\u3002

\u8fd4\u56de\u7c7b\u578b \u8bf4\u660e Mission \u4efb\u52a1\u5bf9\u8c61\uff0c\u53ef\u7528\u4e8e\u89c2\u5bdf\u4efb\u52a1\u72b6\u6001\u3001\u53d6\u6d88\u4efb\u52a1"},{"location":"usage/APIs/#wait","title":"\ud83d\udccc wait()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u7b49\u5f85\u6240\u6709\u6216\u6307\u5b9a\u4efb\u52a1\u5b8c\u6210\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e mission Missionint None \u4efb\u52a1\u5bf9\u8c61\u6216\u4efb\u52a1 id\uff0c\u4e3aNone\u65f6\u7b49\u5f85\u6240\u6709\u4efb\u52a1\u7ed3\u675f show bool False \u662f\u5426\u663e\u793a\u8fdb\u5ea6 timeout floatNone None \u8d85\u65f6\u65f6\u95f4\uff0cNone\u62160\u4e0d\u9650\u65f6"},{"location":"usage/APIs/#cancel","title":"\ud83d\udccc cancel()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u53d6\u6d88\u6240\u6709\u7b49\u5f85\u4e2d\u6216\u6267\u884c\u4e2d\u7684\u4efb\u52a1\u3002

\u53c2\u6570\uff1a \u65e0

\u8fd4\u56de\uff1aNone

"},{"location":"usage/APIs/#get_mission","title":"\ud83d\udccc get_mission()","text":"

\u6b64\u65b9\u6cd5\u6839\u636eid\u503c\u83b7\u53d6\u4e00\u4e2a\u4efb\u52a1\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e mission_or_id Missionint \u5fc5\u586b \u4efb\u52a1\u6216\u4efb\u52a1 id \u8fd4\u56de\u7c7b\u578b \u8bf4\u660e Mission \u4efb\u52a1\u5bf9\u8c61 None \u6ca1\u6709\u627e\u5230\u8be5\u4efb\u52a1"},{"location":"usage/APIs/#get_failed_missions","title":"\ud83d\udccc get_failed_missions()","text":"

\u6b64\u65b9\u6cd5\u8fd4\u56de\u5931\u8d25\u4efb\u52a1\u5217\u8868\u3002

\u53c2\u6570\uff1a \u65e0

\u8fd4\u56de\u7c7b\u578b \u8bf4\u660e List[Mission] \u4efb\u52a1\u5bf9\u8c61\u7ec4\u6210\u7684\u5217\u8868"},{"location":"usage/APIs/#downloadkit_1","title":"\u2705\ufe0f\ufe0fDownloadKit\u5c5e\u6027","text":""},{"location":"usage/APIs/#goal_path","title":"\ud83d\udccc goal_path","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u6587\u4ef6\u9ed8\u8ba4\u4fdd\u5b58\u6587\u4ef6\u5939\u8def\u5f84\uff0c\u9ed8\u8ba4\u7a0b\u5e8f\u5f53\u524d\u8def\u5f84\u3002

\u7c7b\u578b\uff1a str

"},{"location":"usage/APIs/#file_exists","title":"\ud83d\udccc file_exists","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u9047\u5230\u540c\u540d\u6587\u4ef6\u65f6\u7684\u5904\u7406\u65b9\u5f0f\uff0c\u6709\u4ee5\u4e0b\u51e0\u79cd\uff1a'skip', 'overwrite', 'rename', 'add'\u3002

\u9ed8\u8ba4'rename'\u3002

\u7c7b\u578b\uff1a str

"},{"location":"usage/APIs/#split","title":"\ud83d\udccc split","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u5927\u6587\u4ef6\u662f\u5426\u5206\u5757\u4e0b\u8f7d\uff0c\u9ed8\u8ba4True\u3002

\u7c7b\u578b\uff1a bool

"},{"location":"usage/APIs/#set","title":"\ud83d\udccc set","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u7528\u4e8e\u8bbe\u7f6eDownloadKit\u5bf9\u8c61\u7684\u8bbe\u7f6e\u5bf9\u8c61\u3002

\u7c7b\u578b\uff1a Setter

"},{"location":"usage/APIs/#timeout","title":"\ud83d\udccc timeout","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u8fde\u63a5\u8d85\u65f6\u65f6\u95f4\uff0c\u9ed8\u8ba4 20 \u79d2\uff0c\u5982\u679c\u9a71\u52a8\u662fDrissionPage\u7684\u9875\u9762\u5bf9\u8c61\uff0c\u4f7f\u7528\u9875\u9762\u5bf9\u8c61\u7684timeout\u5c5e\u6027\u3002

\u7c7b\u578b\uff1a float

"},{"location":"usage/APIs/#retry","title":"\ud83d\udccc retry","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u8fde\u63a5\u5931\u8d25\u65f6\u91cd\u8bd5\u6b21\u6570\uff0c\u9ed8\u8ba43\u3002

\u7c7b\u578b\uff1a int

"},{"location":"usage/APIs/#interval","title":"\ud83d\udccc interval","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u8fde\u63a5\u5931\u8d25\u65f6\u91cd\u8bd5\u95f4\u9694\uff0c\u9ed8\u8ba4 5 \u6b21\u3002

\u7c7b\u578b\uff1a int

"},{"location":"usage/APIs/#is_running","title":"\ud83d\udccc is_running","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u662f\u5426\u6709\u7ebf\u7a0b\u8fd8\u5728\u8fd0\u884c\u3002

\u7c7b\u578b\uff1a bool

"},{"location":"usage/APIs/#missions","title":"\ud83d\udccc missions","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u6240\u6709\u4efb\u52a1\u5bf9\u8c61\u3002

\u7c7b\u578b\uff1a bool

"},{"location":"usage/APIs/#waiting_list","title":"\ud83d\udccc waiting_list","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u8fd4\u56de\u7b49\u5f85\u6267\u884c\u7684\u4efb\u52a1\u961f\u5217\u3002

\u7c7b\u578b\uff1a List[Mission]

"},{"location":"usage/add_missions/","title":"\ud83d\udc0e \u6dfb\u52a0\u4efb\u52a1","text":"

\u672c\u8282\u4ecb\u7ecd\u5982\u4f55\u6dfb\u52a0\u4e0b\u8f7d\u4efb\u52a1\u3002

"},{"location":"usage/add_missions/#_1","title":"\u2705\ufe0f\ufe0f \u521b\u5efa\u4efb\u52a1","text":""},{"location":"usage/add_missions/#_2","title":"\ud83d\udccc \u5355\u7ebf\u7a0b\u4efb\u52a1","text":"

\u4f7f\u7528download()\u65b9\u6cd5\uff0c\u53ef\u521b\u5efa\u5355\u7ebf\u7a0b\u963b\u585e\u5f0f\u4efb\u52a1\u3002

\u5373\u4f7f\u9047\u5230\u5927\u6587\u4ef6\uff0cdownload()\u4e5f\u53ea\u6709\u4e00\u4e2a\u7ebf\u7a0b\u6267\u884c\u4e0b\u8f7d\uff0c\u4e0d\u4f1a\u5206\u5757\u3002

\u8be5\u65b9\u6cd5\u4f1a\u5728\u6587\u4ef6\u4e0b\u8f7d\u5b8c\u6210\u540e\u624d\u8ba9\u7a0b\u5e8f\u7ee7\u7eed\u5f80\u4e0b\u8fd0\u884c\u3002

download()\u8fd4\u56de\u4efb\u52a1\u7ed3\u679c\u548c\u4fe1\u606f\u7ec4\u6210\u7684tuple\uff0c\u7b2c\u4e00\u4f4d\u662f\u4efb\u52a1\u7ed3\u679c\uff0c\u7b2c\u4e8c\u4f4d\u662f\u4efb\u52a1\u4fe1\u606f\u3002

\u5982\u679c\u4e0b\u8f7d\u6210\u529f\uff0c\u4efb\u52a1\u4fe1\u606f\u8fd4\u56de\u6587\u4ef6\u8def\u5f84\uff0c\u5982\u679c\u5931\u8d25\uff0c\u8fd4\u56de\u5931\u8d25\u539f\u56e0\u3002

\u4efb\u52a1\u7ed3\u679c\u6709\u4ee5\u4e0b\u51e0\u79cd\uff1a

  • 'success'\uff1a\u4e0b\u8f7d\u6210\u529f
  • 'skipped'\uff1a\u5df2\u8df3\u8fc7
  • 'canceled'\uff1a\u88ab\u53d6\u6d88
  • False\uff1a\u4efb\u52a1\u5931\u8d25

\u793a\u4f8b\uff1a

from DownloadKit import DowwnloadKit\nd = DownloadKit()\nurl = 'https://gitee.com/static/images/logo-black.svg'\nd.download(url)\n
"},{"location":"usage/add_missions/#_3","title":"\ud83d\udccc \u591a\u7ebf\u7a0b\u5e76\u53d1\u4efb\u52a1","text":"

\u4f7f\u7528add()\u65b9\u6cd5\uff0c\u53ef\u6dfb\u52a0\u5e76\u53d1\u4efb\u52a1\u3002

add()\u65b9\u6cd5\u8fd4\u56deMission\u5bf9\u8c61\uff0c\u53ef\u4ee5\u7528\u4e8e\u4efb\u52a1\u7ba1\u7406\uff0c\u5728\u4efb\u52a1\u7ba1\u7406\u7ae0\u8282\u4ecb\u7ecd\u3002

\u793a\u4f8b\uff1a

from DownloadKit import DowwnloadKit\nd = DownloadKit()\nurl1 = 'https://gitee.com/static/images/logo-black.svg'\nurl2 = 'https://gitee.com/static/images/logo-black.svg'\nm1 = d.add(url1)\nm2 = d.add(url2)\n
"},{"location":"usage/add_missions/#_4","title":"\ud83d\udccc \u591a\u7ebf\u7a0b\u963b\u585e\u5f0f\u4efb\u52a1","text":"

\u5982\u679c\u60f3\u4f7f\u7528\u591a\u7ebf\u7a0b\u4e0b\u8f7d\u5927\u6587\u4ef6\uff0c\u4e14\u9700\u8981\u5728\u8fd9\u4e2a\u6587\u4ef6\u4e0b\u8f7d\u5b8c\u518d\u6267\u884c\u540e\u9762\u7684\u8bed\u53e5\uff0c\u53ef\u4ee5\u5728add()\u540e\u9762\u4f7f\u7528wait()\u65b9\u6cd5\uff0c\u53ef\u521b\u5efa\u5355\u7ebf\u7a0b\u963b\u585e\u5f0f\u4efb\u52a1\u3002

wait()\u65b9\u6cd5\u6709show_msg\u53c2\u6570\uff0c\u53ef\u6307\u5b9a\u662f\u5426\u6253\u5370\u4e0b\u8f7d\u8fdb\u5ea6\u3002

\u793a\u4f8b\uff1a

from DownloadKit import DowwnloadKit\nd = DownloadKit()\nurl = 'https://gitee.com/static/images/logo-black.svg'\nd.add(url).wait(show_msg=False)\n
"},{"location":"usage/add_missions/#_5","title":"\ud83d\udccc \u5927\u6587\u4ef6\u5206\u5757\u5e76\u884c\u4e0b\u8f7d","text":"

\u9664\u4e86\u591a\u4e2a\u4efb\u52a1\u5e76\u884c\u6267\u884c\uff0c\u5355\u4e2a\u6587\u4ef6\u4e5f\u53ef\u4ee5\u5206\u4e3a\u591a\u4e2a\u5b50\u4efb\u52a1\u5206\u5757\u540c\u65f6\u4e0b\u8f7d\u3002

add()\u65b9\u6cd5\u7684split\u53c2\u6570\u53ef\u4ee5\u8bbe\u7f6e\u662f\u5426\u542f\u7528\u5206\u5757\u4e0b\u8f7d\uff0c\u9ed8\u8ba4\u4e3aTrue\u3002

\u9664\u4e86split\u53c2\u6570\uff0c\u8fd8\u9700\u7b26\u5408\u4e24\u4e2a\u6761\u4ef6\uff0c\u5206\u5757\u4e0b\u8f7d\u624d\u4f1a\u6267\u884c\uff1a

  • \u670d\u52a1\u5668\u652f\u6301\u5206\u5757\u4e0b\u8f7d

  • \u76ee\u6807\u6587\u4ef6\u5927\u5c0f\u5c0f\u4e8e\u8bbe\u5b9a\u7684\u5206\u5757\u5927\u5c0f

\u5206\u5757\u5927\u5c0f\u9ed8\u8ba4\u4e3a 50MB\uff0c\u53ef\u7528set.block_size()\u8bbe\u7f6e\u3002

\u793a\u4f8b\uff1a

from DownloadKit import DowwnloadKit\nd = DownloadKit()\nd.set.block_size('30m')\nurl = 'https://dldir1.qq.com/qqfile/qq/TIM3.4.8/TIM3.4.8.22086.exe'\nd.add(url)  # \u9ed8\u8ba4\u542f\u7528\u5206\u5757\u4e0b\u8f7d\nd.add(url, split=False)  # \u7981\u7528\u5206\u5757\u4e0b\u8f7d\n
"},{"location":"usage/add_missions/#post","title":"\ud83d\udccc post \u65b9\u5f0f","text":"

\u5f53download()\u6216add()\u5b58\u5728data\u6216json\u53c2\u6570\u65f6\uff0c\u4f1a\u4f7f\u7528 post \u65b9\u5f0f\u8fdb\u884c\u8fde\u63a5\u3002

\u4e0d\u5b58\u5728\u8fd9\u4e24\u4e2a\u53c2\u6570\u65f6\uff0c\u7528 get \u65b9\u5f0f\u8fde\u63a5\u3002

\u793a\u4f8b\uff1a

data = {'abc': 123}\nd.download(url, data=data)  # \u81ea\u52a8\u91c7\u7528post\u65b9\u5f0f\n
"},{"location":"usage/add_missions/#_6","title":"\u2705\ufe0f\ufe0f \u4efb\u52a1\u53c2\u6570","text":"

download()\u548cadd()\u65b9\u6cd5\u53c2\u6570\u57fa\u672c\u4e00\u81f4\uff0c\u6709\u5fae\u5c0f\u5dee\u522b\u3002

"},{"location":"usage/add_missions/#download","title":"\ud83d\udccc download()","text":"\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e file_url str \u5fc5\u586b \u6587\u4ef6\u7f51\u5740 goal_path strPath None \u4fdd\u5b58\u8def\u5f84\uff0c\u4e3aNone\u65f6\u4fdd\u5b58\u5230\u5f53\u524d\u6587\u4ef6\u5939 rename str None \u6307\u5b9a\u6587\u4ef6\u53e6\u5b58\u7684\u540d\u79f0\uff0c\u53ef\u4e0d\u5e26\u540e\u7f00\uff0c\u7a0b\u5e8f\u4f1a\u81ea\u52a8\u8865\u5145 file_exists str None \u9047\u5230\u540c\u540d\u6587\u4ef6\u65f6\u7684\u5904\u7406\u65b9\u5f0f\uff0c\u53ef\u9009'skip', 'overwrite', 'rename', 'add'\uff0c\u9ed8\u8ba4\u8ddf\u968f\u5b9e\u4f8b\u5c5e\u6027 show_msg bool True \u662f\u5426\u6253\u5370\u4e0b\u8f7d\u4fe1\u606f\u548c\u8fdb\u5ea6 **kwargs Any \u65e0 requests \u7684\u8fde\u63a5\u53c2\u6570"},{"location":"usage/add_missions/#add","title":"\ud83d\udccc add()","text":"\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e file_url str \u5fc5\u586b \u6587\u4ef6\u7f51\u5740 goal_path strPath None \u4fdd\u5b58\u8def\u5f84\uff0c\u4e3aNone\u65f6\u4fdd\u5b58\u5230\u5f53\u524d\u6587\u4ef6\u5939 rename `str|None \u6307\u5b9a\u6587\u4ef6\u53e6\u5b58\u7684\u540d\u79f0\uff0c\u53ef\u4e0d\u5e26\u540e\u7f00\uff0c\u7a0b\u5e8f\u4f1a\u81ea\u52a8\u8865\u5145 file_exists str None \u9047\u5230\u540c\u540d\u6587\u4ef6\u65f6\u7684\u5904\u7406\u65b9\u5f0f\uff0c\u53ef\u9009'skip', 'overwrite', 'rename', 'add'\uff0c\u9ed8\u8ba4\u8ddf\u968f\u5b9e\u4f8b\u5c5e\u6027 split bool None \u662f\u5426\u542f\u7528\u591a\u7ebf\u7a0b\u5206\u5757\u4e0b\u8f7d\uff0c\u9ed8\u8ba4\u8ddf\u968f\u5b9e\u4f8b\u5c5e\u6027 **kwargs Any \u65e0 requests \u7684\u8fde\u63a5\u53c2\u6570"},{"location":"usage/add_missions/#_7","title":"\ud83d\udccc \u8fde\u63a5\u53c2\u6570","text":"

\u8fde\u63a5\u53c2\u6570\u5373**kwargs\u5141\u8bb8\u63a5\u6536\u5230\u53c2\u6570\uff0c\u4e0e requests \u7684get()\u65b9\u6cd5\u4e00\u81f4\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u8bf4\u660e timeout float \u8fde\u63a5\u8d85\u65f6\u65f6\u95f4 params dict \u67e5\u8be2\u53c2\u6570\u5b57\u5178 headers dict headers cookies Any cookies data Any data \u6570\u636e json Any json \u6570\u636e files Any \u6587\u4ef6\u6570\u636e auth Tuple[str, str]HTTPBasicAuth \u8ba4\u8bc1\u5143\u7ec4\u6216\u5bf9\u8c61 allow_redirects bool \u662f\u5426\u5141\u8bb8\u81ea\u52a8\u8df3\u8f6c proxies dict \u4ee3\u7406 ip hooks dict \u56de\u8c03\u65b9\u6cd5 verify bool \u662f\u5426\u9a8c\u8bc1SSL\u8bc1\u4e66 cert strTuple[str, str] SSL\u5ba2\u6237\u7aef\u8bc1\u4e66

\u793a\u4f8b\uff1a

from DownloadKit import DownloadKit\nd = DownloadKit()\nh = {'referer': 'demourl.com'}\nd.download(url, headers=h)\n
"},{"location":"usage/create_object/","title":"\ud83d\udc18 \u521b\u5efa\u5bf9\u8c61","text":""},{"location":"usage/create_object/#downloadkit","title":"\u2705\ufe0f\ufe0f \u521b\u5efaDownloadKit\u5bf9\u8c61","text":"

\u521b\u5efaDownloadKit\u5bf9\u8c61\u65f6\uff0cdriver\u53c2\u6570\u53ef\u4f20\u5165\u4e00\u4e2a\u7528\u4e8e\u643a\u5e26\u767b\u5f55\u4fe1\u606f\u7684\u5bf9\u8c61\uff0c\u53ef\u4ee5\u662f\u591a\u79cd\u7c7b\u578b\u3002

\u5f53\u4f20\u5165\u7684\u662fDrissionPage\u7684\u9875\u9762\u5bf9\u8c61\u65f6\uff0c\u8fd8\u53ef\u4ee5\u6839\u636e\u9875\u9762\u8bbf\u95ee\u7684 url \u81ea\u52a8\u8bbe\u7f6ereferer\u53c2\u6570\u3002

\u521d\u59cb\u5316\u53c2\u6570 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e goal_path strPath None \u6587\u4ef6\u4fdd\u5b58\u8def\u5f84 roads int 10 \u53ef\u540c\u65f6\u8fd0\u884c\u7684\u7ebf\u7a0b\u6570 driver SessionSessionOptionsChromiumPageSessionPageChromiumTabWebPageWebPageTab None \u7528\u4e8e\u63d0\u4f9b\u4e0b\u8f7d\u8fde\u63a5\u4fe1\u606f\u7684\u9875\u9762\u6216\u94fe\u63a5\u5bf9\u8c61 file_exists str 'renmae' \u6709\u540c\u540d\u6587\u4ef6\u540d\u65f6\u7684\u5904\u7406\u65b9\u5f0f\uff0c\u53ef\u9009'skip', 'overwrite', 'rename', 'add'"},{"location":"usage/create_object/#_1","title":"\u2705\ufe0f\ufe0f \u793a\u4f8b","text":""},{"location":"usage/create_object/#_2","title":"\ud83d\udccc \u76f4\u63a5\u521b\u5efa","text":"
from DownloadKit import DownloadKit\nd = DownloadKit()\n
"},{"location":"usage/create_object/#session","title":"\ud83d\udccc \u63a5\u6536Session\u5bf9\u8c61","text":"
from requests import Session\nfrom DownloadKit import DownloadKit\nsession = Session()\nd = DownloadKit(session=session)\n
"},{"location":"usage/create_object/#sessionoptions","title":"\ud83d\udccc \u63a5\u6536SessionOptions\u5bf9\u8c61","text":"
from DrissionPage import SessionOptions\nfrom DownloadKit import DownloadKit\nso = SessionOptions()\nd = DownloadKit(session=so)\n
"},{"location":"usage/create_object/#_3","title":"\ud83d\udccc \u63a5\u6536\u9875\u9762\u5bf9\u8c61","text":"
from DrissionPage import ChromiumPage\nfrom DownloadKit import DownloadKit\np = ChromiumPage()\nd = DownloadKit(session=p)\n
"},{"location":"usage/misssions/","title":"\ud83d\udc12 \u4efb\u52a1\u7ba1\u7406","text":"

\u672c\u8282\u4ecb\u7ecd\u4e0b\u8f7d\u4efb\u52a1\u7684\u7ba1\u7406\u3002

add()\u65b9\u6cd5\u4f1a\u8fd4\u56de\u4e00\u4e2aMission\u5bf9\u8c61\uff0c\u8be5\u5bf9\u8c61\u53ef\u7528\u4e8e\u67e5\u770b\u4efb\u52a1\u4fe1\u606f\u548c\u7ba1\u7406\u4efb\u52a1\u3002

"},{"location":"usage/misssions/#_1","title":"\u2705\ufe0f\ufe0f \u4efb\u52a1\u8fdb\u5ea6","text":""},{"location":"usage/misssions/#rate","title":"\ud83d\udccc rate","text":"

\u8be5\u5c5e\u6027\u8fd4\u56de\u4efb\u52a1\u5b8c\u6210\u7684\u767e\u5206\u6bd4\u3002

\u7c7b\u578b\uff1afloat

\u793a\u4f8b\uff1a

d = DownloadKit()\nm = d.add(url)\nprint(m.rate)\n
"},{"location":"usage/misssions/#_2","title":"\ud83d\udccc \u7b49\u5f85\u5355\u4e2a\u4efb\u52a1\u7ed3\u675f","text":"

Mission\u5bf9\u8c61\u7684wait()\u65b9\u6cd5\u53ef\u7b49\u5f85\u8be5\u4efb\u52a1\u7ed3\u675f\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e show bool True \u662f\u5426\u6253\u5370\u4e0b\u8f7d\u4fe1\u606f timeout float 0 \u8d85\u65f6\u65f6\u95f4\uff0c0\u8868\u793a\u4e0d\u9650\u65f6

|\u8fd4\u56de\u7c7b\u578b|\u8bf4\u660e| |tuple|\u4efb\u52a1\u7ed3\u679c\u548c\u4fe1\u606f\u7ec4\u6210\u7684tuple\uff0c\u683c\u5f0f\uff1a(\u4efb\u52a1\u7ed3\u679c, \u4efb\u52a1\u4fe1\u606f)|

\u793a\u4f8b\uff1a

d = DownloadKit()\nm = d.add(url)\nm.wait()\n
"},{"location":"usage/misssions/#_3","title":"\ud83d\udccc \u7b49\u5f85\u6240\u6709\u4efb\u52a1\u7ed3\u675f","text":"

DownloadKit\u5bf9\u8c61\u7684wait()\u65b9\u6cd5\uff0c\u53ef\u7b49\u5f85\u6240\u6709\u4efb\u52a1\u7ed3\u675f\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e mission Missionint None \u4efb\u52a1\u5bf9\u8c61\u6216\u4efb\u52a1 id\uff0c\u4e3aNone\u65f6\u7b49\u5f85\u6240\u6709\u4efb\u52a1\u7ed3\u675f show bool False \u662f\u5426\u663e\u793a\u8fdb\u5ea6 timeout floatNone None \u8d85\u65f6\u65f6\u95f4\uff0cNone\u62160\u4e0d\u9650\u65f6

\u793a\u4f8b\uff1a

d = DownloadKit()\nd.add(url1)\nd.add(url2)\nd.wait()\n
"},{"location":"usage/misssions/#_4","title":"\ud83d\udccc \u53d6\u6d88\u4efb\u52a1","text":"

cancel()\u7528\u4e8e\u4e2d\u9014\u53d6\u6d88\u4efb\u52a1\u3002

\u53c2\u6570\uff1a \u65e0

\u8fd4\u56de\uff1aNone

"},{"location":"usage/misssions/#_5","title":"\ud83d\udccc \u5220\u9664\u5df2\u4e0b\u8f7d\u6587\u4ef6","text":"

del_file()\u7528\u4e8e\u5220\u9664\u4efb\u52a1\u5df2\u4e0b\u8f7d\u7684\u6587\u4ef6\u3002

\u53c2\u6570\uff1a \u65e0

\u8fd4\u56de\uff1aNone

"},{"location":"usage/misssions/#_6","title":"\u2705\ufe0f\ufe0f \u4efb\u52a1\u4fe1\u606f","text":""},{"location":"usage/misssions/#_7","title":"\ud83d\udccc \u4efb\u52a1\u72b6\u6001","text":"

state\u5c5e\u6027\u8fd4\u56de\u4efb\u52a1\u72b6\u6001\uff0c\u6709\u4ee5\u4e0b\u4e09\u79cd\uff1a

  • 'waiting'\uff1a\u7b49\u5f85\u5f00\u59cb
  • 'running'\uff1a\u8fd0\u884c\u4e2d
  • 'done'\uff1a\u5df2\u7ed3\u675f

\u4efb\u52a1\u72b6\u6001\u4e0d\u80fd\u770b\u51fa\u4efb\u52a1\u662f\u5426\u6210\u529f\uff0c\u53ea\u80fd\u663e\u793a\u4efb\u52a1\u662f\u5426\u5728\u8fd0\u884c\u3002

"},{"location":"usage/misssions/#_8","title":"\ud83d\udccc \u4efb\u52a1\u7ed3\u679c","text":"

result\u5c5e\u6027\u8fd4\u56de\u4efb\u52a1\u7ed3\u679c\uff0c\u6709\u4ee5\u4e0b\u51e0\u79cd\uff1a

  • 'success'\uff1a\u4e0b\u8f7d\u6210\u529f
  • 'skipped'\uff1a\u8df3\u8fc7\uff0c\u5b58\u5728\u540c\u540d\u6587\u4ef6\uff0c\u4e14\u8bbe\u7f6e\u4e3a\u8df3\u8fc7\u65f6
  • 'canceled'\uff1a\u88ab\u53d6\u6d88
  • False\uff1a\u4efb\u52a1\u5931\u8d25
  • None\uff1a\u672a\u77e5\uff0c\u4efb\u52a1\u8fd8\u6ca1\u7ed3\u675f
"},{"location":"usage/misssions/#_9","title":"\ud83d\udccc \u4efb\u52a1\u4fe1\u606f","text":"

info\u5c5e\u6027\u8fd4\u56de\u4efb\u52a1\u4fe1\u606f\uff0c\u5728\u4efb\u52a1\u4e0d\u540c\u9636\u6bb5\uff0c\u4f1a\u8fd4\u56de\u4e0d\u540c\u4fe1\u606f\u3002

info\u662f\u5bf9\u5f53\u524d\u72b6\u6001\u7684\u6587\u5b57\u89e3\u91ca\uff0c\u5982\u4efb\u52a1\u5931\u8d25\u65f6\uff0c\u4f1a\u8fd4\u56de\u5931\u8d25\u539f\u56e0\uff0c\u6210\u529f\u65f6\u4f1a\u8fd4\u56de\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84\u3002

"},{"location":"usage/misssions/#_10","title":"\u2705\ufe0f\ufe0f \u83b7\u53d6\u4efb\u52a1\u5bf9\u8c61","text":""},{"location":"usage/misssions/#_11","title":"\ud83d\udccc \u83b7\u53d6\u6240\u6709\u4efb\u52a1\u5bf9\u8c61","text":"

DownloadKit\u5bf9\u8c61\u7684missions\u5c5e\u6027\u4ee5liist\u65b9\u5f0f\u8fd4\u56de\u6240\u6709\u4efb\u52a1\u5bf9\u8c61\u3002

\u793a\u4f8b\uff1a

d = DownloadKit()\nd.add(url)\nprint(d.missions)\n
"},{"location":"usage/misssions/#_12","title":"\ud83d\udccc \u67e5\u627e\u4efb\u52a1","text":"

DownloadKit\u5bf9\u8c61\u7684get_mission()\u65b9\u6cd5\u53ef\u6839\u636e\u4efb\u52a1 id \u83b7\u53d6\u4efb\u52a1\u5bf9\u8c61\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e mission_or_id Missionint \u5fc5\u586b \u4efb\u52a1\u6216\u4efb\u52a1 id \u8fd4\u56de\u7c7b\u578b \u8bf4\u660e Mission \u4efb\u52a1\u5bf9\u8c61 None \u6ca1\u6709\u627e\u5230\u8be5\u4efb\u52a1"},{"location":"usage/misssions/#_13","title":"\ud83d\udccc \u83b7\u53d6\u5931\u8d25\u7684\u4efb\u52a1","text":"

DownloadKit\u5bf9\u8c61\u7684get_failed_missions()\u65b9\u6cd5\u53ef\u4ee5list\u65b9\u5f0f\u8fd4\u56de\u5931\u8d25\u7684\u4efb\u52a1\u3002

\u53c2\u6570\uff1a \u65e0

\u8fd4\u56de\u7c7b\u578b \u8bf4\u660e List[Mission] \u4efb\u52a1\u5bf9\u8c61\u7ec4\u6210\u7684\u5217\u8868"},{"location":"usage/misssions/#mission","title":"\u2705\ufe0f\ufe0f Mission\u5bf9\u8c61\u7684\u5c5e\u6027","text":""},{"location":"usage/misssions/#id","title":"\ud83d\udccc id","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u4efb\u52a1 id\u3002

\u7c7b\u578b\uff1aint

"},{"location":"usage/misssions/#data","title":"\ud83d\udccc data","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u4efb\u52a1\u4f7f\u7528\u7684\u6570\u636e\uff0c\u5373\u521b\u5efa\u4efb\u52a1\u65f6\u8f93\u5165\u7684\u53c2\u6570\u3002

\u7c7b\u578b\uff1aMissionData

"},{"location":"usage/misssions/#state","title":"\ud83d\udccc state","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u4efb\u52a1\u72b6\u6001\uff0c\u6709\u4e09\u79cd\uff1a'waiting'\u3001'running'\u3001'done'\u3002

\u7c7b\u578b\uff1astr

"},{"location":"usage/misssions/#result","title":"\ud83d\udccc result","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u4efb\u52a1\u7ed3\u679c\uff0c\u6709\u4ee5\u4e0b\u51e0\u79cd\uff1a'success'\u3001'skipped'\u3001'canceled'\u3001False\u3001None

\u7c7b\u578b\uff1astr

"},{"location":"usage/misssions/#info","title":"\ud83d\udccc info","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u4efb\u52a1\u63cf\u8ff0\u4fe1\u606f\u3002

\u7c7b\u578b\uff1astr

"},{"location":"usage/misssions/#is_done","title":"\ud83d\udccc is_done","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u4efb\u52a1\u662f\u5426\u5df2\u5b8c\u6210\u3002

\u7c7b\u578b\uff1abool

"},{"location":"usage/misssions/#size","title":"\ud83d\udccc size","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u6587\u4ef6\u5927\u5c0f\u3002

\u7c7b\u578b\uff1aint\u6216None

"},{"location":"usage/misssions/#tasks","title":"\ud83d\udccc tasks","text":"

\u6b64\u5c5e\u6027\u4ee5list\u65b9\u5f0f\u8fd4\u56de\u6240\u6709\u5b50\u4efb\u52a1

\u7c7b\u578b\uff1aList[Task]

"},{"location":"usage/misssions/#tasks_count","title":"\ud83d\udccc tasks_count","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u5b50\u4efb\u52a1\u6570\u91cf\u3002

\u7c7b\u578b\uff1aint

"},{"location":"usage/misssions/#done_tasks_count","title":"\ud83d\udccc done_tasks_count","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u5df2\u5b8c\u6210\u7684\u5b50\u4efb\u52a1\u6570\u91cf\u3002

\u7c7b\u578b\uff1aint

"},{"location":"usage/misssions/#file_name","title":"\ud83d\udccc file_name","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u6587\u4ef6\u540d\u3002

\u7c7b\u578b\uff1astr\u6216None

"},{"location":"usage/misssions/#method","title":"\ud83d\udccc method","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u8fde\u63a5\u65b9\u5f0f\uff0c'get'\u6216'post'\u3002

\u7c7b\u578b\uff1astr

"},{"location":"usage/misssions/#path","title":"\ud83d\udccc path","text":"

\u6b64\u5c5e\u6027\u8fd4\u56de\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84\u3002

\u7c7b\u578b\uff1astr

"},{"location":"usage/misssions/#rate_1","title":"\ud83d\udccc rate","text":"

\u6b64\u5c5e\u6027\u4ee5\u767e\u5206\u6bd4\u65b9\u5f0f\u8fd4\u56de\u4e0b\u8f7d\u8fdb\u5ea6\u3002

\u7c7b\u578b\uff1afloat

"},{"location":"usage/settings/","title":"\ud83e\udd8d \u8fd0\u884c\u8bbe\u7f6e","text":"

\u672c\u8282\u4ecb\u7ecdDownloadKit\u5bf9\u8c61\u76f8\u5173\u8bbe\u7f6e\u3002

"},{"location":"usage/settings/#_1","title":"\u2705\ufe0f\ufe0f \u4f7f\u7528\u65b9\u6cd5","text":""},{"location":"usage/settings/#_2","title":"\ud83d\udccc \u5168\u5c40\u8bbe\u7f6e","text":"

\u4f7f\u7528DownloadKit\u5bf9\u8c61\u7684set.xxxx()\u65b9\u6cd5\uff0c\u53ef\u5bf9\u5404\u79cd\u5141\u8bb8\u53c2\u6570\u8fdb\u884c\u8bbe\u7f6e\u3002

\u8fd9\u79cd\u65b9\u6cd5\u8bbe\u7f6e\u7684\u53c2\u6570\u65f6\u5168\u5c40\u6709\u6548\u7684\uff0c\u4e4b\u540e\u65b0\u5efa\u7684\u4efb\u52a1\u4f1a\u9ed8\u8ba4\u4f7f\u7528\u3002

from DownloadKit import DownloadKit\nd = DownloadKit()\nd.set.block_size('10m')  # \u8bbe\u7f6e\u5206\u5757\u5927\u5c0f\n
"},{"location":"usage/settings/#_3","title":"\ud83d\udccc \u6bcf\u4e2a\u4efb\u52a1\u72ec\u7acb\u8bbe\u7f6e","text":"

\u6bcf\u6b21\u65b0\u5efa\u4efb\u52a1\u65f6\uff0c\u53ef\u8bbe\u7f6e\u5f53\u524d\u9879\u76ee\u6709\u6548\u7684\u8bbe\u7f6e\uff0c\u8986\u76d6\u5168\u5c40\u8bbe\u7f6e\u3002

from DownloadKit import DownloadKit\nd = DownloadKit()\nd.set.goal_path('tmp1')  # \u8bbe\u7f6e\u5168\u5c40\u4fdd\u5b58\u8def\u5f84\nd.add(url, goal_path='tmp2')  # \u521b\u5efa\u4efb\u52a1\u65f6\u6307\u5b9a\u4fdd\u5b58\u8def\u5f84\n
"},{"location":"usage/settings/#_4","title":"\u2705\ufe0f\ufe0f \u8fd0\u884c\u8bbe\u7f6e","text":""},{"location":"usage/settings/#setdriver","title":"\ud83d\udccc set.driver()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u63d0\u4f9b\u4e0b\u8f7d\u8fde\u63a5\u4fe1\u606f\u7684\u9875\u9762\u6216\u94fe\u63a5\u5bf9\u8c61\u3002

\u652f\u6301 DrissionPage \u6240\u6709\u9875\u9762\u5bf9\u8c61\u3001Session\u5bf9\u8c61\u3001SessionOptions\u5bf9\u8c61\u3002

\u7a0b\u5e8f\u53ef\u4ece\u4f20\u5165\u7684\u5bf9\u8c61\u4e2d\u81ea\u52a8\u83b7\u53d6\u767b\u5f55\u4fe1\u606f\uff0c\u5982\u4f20\u5165\u9875\u9762\u5bf9\u8c61\uff0c\u8fd8\u80fd\u81ea\u52a8\u8bbe\u7f6eReferer\u53c2\u6570\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e driver SessionSessionOptionsChromiumPageSessionPageChromiumTabWebPageWebPageTab \u5fc5\u586b \u7528\u4e8e\u63d0\u4f9b\u8fde\u63a5\u4fe1\u606f\u7684\u5bf9\u8c61

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setgoal_path","title":"\ud83d\udccc set.goal_path()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e goal_path strPath \u5fc5\u586b \u6587\u4ef6\u4fdd\u5b58\u8def\u5f84

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setif_file_exists","title":"\ud83d\udccc set.if_file_exists()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u8def\u5f84\u5b58\u5728\u540c\u540d\u6587\u4ef6\u65f6\u7684\u5904\u7406\u65b9\u5f0f\u3002

\u53ef\u9009'skip', 'rename', 'overwrite', 'add'\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e mode str \u5fc5\u586b \u5904\u7406\u65b9\u5f0f\u5b57\u7b26\u4e32
  • skip\uff1a\u8df3\u8fc7\uff0c\u4e0d\u4e0b\u8f7d
  • overwrite\uff1a\u8986\u76d6\u539f\u6709\u6587\u4ef6
  • rename\uff1a\u4ee5\u5728\u540e\u9762\u6dfb\u52a0\u5e8f\u53f7\u7684\u65b9\u5f0f\u7ed9\u65b0\u6587\u4ef6\u91cd\u547d\u540d
  • add\uff1a\u5728\u539f\u6709\u6587\u4ef6\u672b\u5c3e\u8ffd\u52a0\u5185\u5bb9

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setif_file_existsxxxx","title":"\ud83d\udccc set.if_file_exists.xxxx()","text":"

\u8fd9\u51e0\u4e2a\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u8def\u5f84\u5b58\u5728\u540c\u540d\u6587\u4ef6\u65f6\u7684\u5904\u7406\u65b9\u5f0f\u3002

\u6548\u679c\u4e0eset.if_file_exists()\u4e00\u81f4\u3002

  • skip()\uff1a\u8df3\u8fc7\uff0c\u4e0d\u4e0b\u8f7d
  • overwrite()\uff1a\u8986\u76d6\u539f\u6709\u6587\u4ef6
  • rename()\uff1a\u4ee5\u5728\u540e\u9762\u6dfb\u52a0\u5e8f\u53f7\u7684\u65b9\u5f0f\u7ed9\u65b0\u6587\u4ef6\u91cd\u547d\u540d
  • add()\uff1a\u5728\u539f\u6709\u6587\u4ef6\u672b\u5c3e\u8ffd\u52a0\u5185\u5bb9

\u793a\u4f8b\uff1a

from DownloadKit import DownloadKit\nd = DownloadKit()\nd.set.if_file_exists.skip()\n
"},{"location":"usage/settings/#setroads","title":"\ud83d\udccc set.roads()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u53ef\u540c\u65f6\u8fd0\u884c\u7684\u7ebf\u7a0b\u6570\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e num int \u5fc5\u586b \u7ebf\u7a0b\u6570\u91cf

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setretry","title":"\ud83d\udccc set.retry()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u8fde\u63a5\u5931\u8d25\u65f6\u91cd\u8bd5\u6b21\u6570\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e times int \u5fc5\u586b \u91cd\u8bd5\u6b21\u6570

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setinterval","title":"\ud83d\udccc set.interval()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u8fde\u63a5\u5931\u8d25\u65f6\u91cd\u8bd5\u95f4\u9694\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e seconds float \u5fc5\u586b \u8fde\u63a5\u5931\u8d25\u65f6\u91cd\u8bd5\u95f4\u9694\uff08\u79d2\uff09

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#settimeout","title":"\ud83d\udccc set.timeout()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u8fde\u63a5\u8d85\u65f6\u65f6\u95f4\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e seconds float \u5fc5\u586b \u8d85\u65f6\u65f6\u95f4\uff08\u79d2\uff09

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setsplit","title":"\ud83d\udccc set.split()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u5927\u6587\u4ef6\u662f\u5426\u5206\u5757\u4e0b\u8f7d\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e on_off bool \u5fc5\u586b bool\u4ee3\u8868\u5f00\u5173

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setblock_size","title":"\ud83d\udccc set.block_size()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u8bbe\u7f6e\u5206\u5757\u5927\u5c0f\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e size strint \u5fc5\u586b \u53ef\u63a5\u6536int\u548cstr\u5f62\u5f0f\uff0c\u63a5\u6536int\u65f6\u4ee5\u5b57\u8282\u4e3a\u5355\u4f4d\uff1b\u63a5\u6536str\u65f6\u683c\u5f0f\u6709\uff1a'10b'\u3001'10k'\u3001'10m'\u3001'10g'\u56db\u79cd\uff0c\u4e0d\u533a\u5206\u5927\u5c0f\u5199

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setproxies","title":"\ud83d\udccc set.proxies()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u4ee3\u7406\u5730\u5740\u53ca\u7aef\u53e3\uff0c\u4f8b\uff1a'127.0.0.1:1080'\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e http str None http \u4ee3\u7406\u5730\u5740\u53ca\u7aef\u53e3 https str None https \u4ee3\u7406\u5730\u5740\u53ca\u7aef\u53e3

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#_5","title":"\u2705\ufe0f\ufe0f \u65e5\u5fd7\u8bbe\u7f6e","text":"

\u65e5\u5fd7\u8bbe\u7f6e\u65b9\u6cd5\u5728set.log\u5c5e\u6027\u4e2d\u3002

"},{"location":"usage/settings/#setlogpath","title":"\ud83d\udccc set.log.path()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u65e5\u5fd7\u6587\u4ef6\u8def\u5f84\u3002

\u53c2\u6570\u540d\u79f0 \u7c7b\u578b \u9ed8\u8ba4\u503c \u8bf4\u660e path strPath \u5fc5\u586b \u6587\u4ef6\u8def\u5f84

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setlogprint_all","title":"\ud83d\udccc set.log.print_all()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u6253\u5370\u6240\u6709\u4efb\u52a1\u4fe1\u606f\u3002

\u53c2\u6570\uff1a \u65e0

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setlogprint_failed","title":"\ud83d\udccc set.log.print_failed()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u6253\u5370\u5931\u8d25\u7684\u4efb\u52a1\u3002

\u53c2\u6570\uff1a \u65e0

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setlogprint_nothing","title":"\ud83d\udccc set.log.print_nothing()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u4e0d\u6253\u5370\u4efb\u4f55\u4fe1\u606f\u3002

\u53c2\u6570\uff1a \u65e0

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setloglog_all","title":"\ud83d\udccc set.log.log_all()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bb0\u5f55\u6253\u5370\u6240\u6709\u4efb\u52a1\u4fe1\u606f\u5230\u6587\u4ef6\u3002

\u53c2\u6570\uff1a \u65e0

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setloglog_failed","title":"\ud83d\udccc set.log.log_failed()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u8bb0\u5f55\u5931\u8d25\u7684\u4efb\u52a1\u5230\u6587\u4ef6\u3002

\u53c2\u6570\uff1a \u65e0

\u8fd4\u56de\uff1aNone

"},{"location":"usage/settings/#setloglog_nothing","title":"\ud83d\udccc set.log.log_nothing()","text":"

\u6b64\u65b9\u6cd5\u7528\u4e8e\u8bbe\u7f6e\u4e0d\u8bb0\u5f55\u4efb\u4f55\u4fe1\u606f\u5230\u6587\u4ef6\u3002

\u53c2\u6570\uff1a \u65e0

\u8fd4\u56de\uff1aNone

"}]} \ No newline at end of file diff --git a/site/sitemap.xml b/site/sitemap.xml new file mode 100644 index 0000000000000000000000000000000000000000..a8cea5639ca19f33e999da1afd7323cb4f35e554 --- /dev/null +++ b/site/sitemap.xml @@ -0,0 +1,43 @@ + + + + http://g1879.gitee.io/DownloadKit/ + 2023-08-19 + daily + + + http://g1879.gitee.io/DownloadKit/history/ + 2023-08-19 + daily + + + http://g1879.gitee.io/DownloadKit/install_and_import/ + 2023-08-19 + daily + + + http://g1879.gitee.io/DownloadKit/usage/APIs/ + 2023-08-19 + daily + + + http://g1879.gitee.io/DownloadKit/usage/add_missions/ + 2023-08-19 + daily + + + http://g1879.gitee.io/DownloadKit/usage/create_object/ + 2023-08-19 + daily + + + http://g1879.gitee.io/DownloadKit/usage/misssions/ + 2023-08-19 + daily + + + http://g1879.gitee.io/DownloadKit/usage/settings/ + 2023-08-19 + daily + + \ No newline at end of file diff --git a/site/sitemap.xml.gz b/site/sitemap.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..5f79c9244680ef38fd4cc5fb0bf470e7c75a7265 Binary files /dev/null and b/site/sitemap.xml.gz differ diff --git a/site/usage/APIs/index.html b/site/usage/APIs/index.html new file mode 100644 index 0000000000000000000000000000000000000000..ec757a4931e6d9f4e7d7899f7150db3bb58f2095 --- /dev/null +++ b/site/usage/APIs/index.html @@ -0,0 +1,1310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 🐇 APIs - DownloadKit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

🐇 APIs

+ +

✅️️ DownloadKit对象方法

+

📌 download()

+

此方法用于单线程阻塞式下载一个文件。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
file_urlstr必填文件网址
goal_pathstr
Path
None保存路径,为None时保存到当前文件夹
renamestrNone指定文件另存的名称,可不带后缀,程序会自动补充
file_existsstrNone遇到同名文件时的处理方式,可选'skip', 'overwrite', 'rename', 'add',默认跟随实例属性
show_msgboolTrue是否打印下载信息和进度
**kwargsAnyrequests 的连接参数
+

连接参数**kwargs与 requests 的get()方法一致。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数名称类型说明
timeoutfloat连接超时时间
paramsdict查询参数字典
headersdictheaders
cookiesAnycookies
dataAnydata 数据
jsonAnyjson 数据
filesAny文件数据
authTuple[str, str]
HTTPBasicAuth
认证元组或对象
allow_redirectsbool是否允许自动跳转
proxiesdict代理 ip
hooksdict回调方法
verifybool是否验证SSL证书
certstr
Tuple[str, str]
SSL客户端证书
+ + + + + + + + + + + + + +
返回类型说明
tuple格式:(任务结果, 任务信息)
+

任务结果有如下几种:

+
    +
  • 'success':下载成功
  • +
  • 'skipped':已跳过
  • +
  • 'canceled':被取消
  • +
  • False:任务失败
  • +
+

如果下载成功,任务信息返回文件路径,如果失败,返回失败原因。

+
+

📌 add()

+

此方法添加一个并发任务。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
file_urlstr必填文件网址
goal_pathstr
Path
None保存路径,为None时保存到当前文件夹
rename`str|None指定文件另存的名称,可不带后缀,程序会自动补充
file_existsstrNone遇到同名文件时的处理方式,可选'skip', 'overwrite', 'rename', 'add',默认跟随实例属性
splitboolNone当前任务是否启用多线程分块下载,默认跟随实例属性
**kwargsAnyrequests 的连接参数
+

**kwargs参数与download()一致,见上文。

+ + + + + + + + + + + + + +
返回类型说明
Mission任务对象,可用于观察任务状态、取消任务
+
+

📌 wait()

+

此方法用于等待所有或指定任务完成。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
missionMission
int
None任务对象或任务 id,为None时等待所有任务结束
showboolFalse是否显示进度
timeoutfloat
None
None超时时间,None0不限时
+
+

📌 cancel()

+

此方法用于取消所有等待中或执行中的任务。

+

参数:

+

返回:None

+
+

📌 get_mission()

+

此方法根据id值获取一个任务。

+ + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
mission_or_idMission
int
必填任务或任务 id
+ + + + + + + + + + + + + + + + + +
返回类型说明
Mission任务对象
None没有找到该任务
+
+

📌 get_failed_missions()

+

此方法返回失败任务列表。

+

参数:

+ + + + + + + + + + + + + +
返回类型说明
List[Mission]任务对象组成的列表
+
+

✅️️DownloadKit属性

+

📌 goal_path

+

此属性返回文件默认保存文件夹路径,默认程序当前路径。

+

类型: str

+
+

📌 file_exists

+

此属性返回遇到同名文件时的处理方式,有以下几种:'skip', 'overwrite', 'rename', 'add'

+

默认'rename'

+

类型: str

+
+

📌 split

+

此属性返回大文件是否分块下载,默认True

+

类型: bool

+
+

📌 set

+

此属性返回用于设置DownloadKit对象的设置对象。

+

类型: Setter

+
+

📌 timeout

+

此属性返回连接超时时间,默认 20 秒,如果驱动是DrissionPage的页面对象,使用页面对象的timeout属性。

+

类型: float

+
+

📌 retry

+

此属性返回连接失败时重试次数,默认3

+

类型: int

+
+

📌 interval

+

此属性返回连接失败时重试间隔,默认 5 次。

+

类型: int

+
+

📌 is_running

+

此属性返回是否有线程还在运行。

+

类型: bool

+
+

📌 missions

+

此属性返回所有任务对象。

+

类型: bool

+
+

📌 waiting_list

+

此属性返回返回等待执行的任务队列。

+

类型: List[Mission]

+
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/site/usage/add_missions/index.html b/site/usage/add_missions/index.html new file mode 100644 index 0000000000000000000000000000000000000000..77a63bfbc43e043a683ffc7ac8735c15ae98a147 --- /dev/null +++ b/site/usage/add_missions/index.html @@ -0,0 +1,1113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 🐎 添加任务 - DownloadKit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

🐎 添加任务

+ +

本节介绍如何添加下载任务。

+

✅️️ 创建任务

+

📌 单线程任务

+

使用download()方法,可创建单线程阻塞式任务。

+

即使遇到大文件,download()也只有一个线程执行下载,不会分块。

+

该方法会在文件下载完成后才让程序继续往下运行。

+

download()返回任务结果和信息组成的tuple,第一位是任务结果,第二位是任务信息。

+

如果下载成功,任务信息返回文件路径,如果失败,返回失败原因。

+

任务结果有以下几种:

+
    +
  • 'success':下载成功
  • +
  • 'skipped':已跳过
  • +
  • 'canceled':被取消
  • +
  • False:任务失败
  • +
+

示例:

+
from DownloadKit import DowwnloadKit
+
+d = DownloadKit()
+url = 'https://gitee.com/static/images/logo-black.svg'
+
+d.download(url)
+
+
+

📌 多线程并发任务

+

使用add()方法,可添加并发任务。

+

add()方法返回Mission对象,可以用于任务管理,在任务管理章节介绍。

+

示例:

+
from DownloadKit import DowwnloadKit
+
+d = DownloadKit()
+url1 = 'https://gitee.com/static/images/logo-black.svg'
+url2 = 'https://gitee.com/static/images/logo-black.svg'
+
+m1 = d.add(url1)
+m2 = d.add(url2)
+
+
+

📌 多线程阻塞式任务

+

如果想使用多线程下载大文件,且需要在这个文件下载完再执行后面的语句,可以在add()后面使用wait()方法,可创建单线程阻塞式任务。

+

wait()方法有show_msg参数,可指定是否打印下载进度。

+

示例:

+
from DownloadKit import DowwnloadKit
+
+d = DownloadKit()
+url = 'https://gitee.com/static/images/logo-black.svg'
+
+d.add(url).wait(show_msg=False)
+
+
+

📌 大文件分块并行下载

+

除了多个任务并行执行,单个文件也可以分为多个子任务分块同时下载。

+

add()方法的split参数可以设置是否启用分块下载,默认为True

+

除了split参数,还需符合两个条件,分块下载才会执行:

+
    +
  • +

    服务器支持分块下载

    +
  • +
  • +

    目标文件大小小于设定的分块大小

    +
  • +
+

分块大小默认为 50MB,可用set.block_size()设置。

+

示例:

+
from DownloadKit import DowwnloadKit
+
+d = DownloadKit()
+d.set.block_size('30m')
+url = 'https://dldir1.qq.com/qqfile/qq/TIM3.4.8/TIM3.4.8.22086.exe'
+
+d.add(url)  # 默认启用分块下载
+d.add(url, split=False)  # 禁用分块下载
+
+
+

📌 post 方式

+

download()add()存在datajson参数时,会使用 post 方式进行连接。

+

不存在这两个参数时,用 get 方式连接。

+

示例:

+
data = {'abc': 123}
+d.download(url, data=data)  # 自动采用post方式
+
+
+

✅️️ 任务参数

+

download()add()方法参数基本一致,有微小差别。

+

📌 download()

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
file_urlstr必填文件网址
goal_pathstr
Path
None保存路径,为None时保存到当前文件夹
renamestrNone指定文件另存的名称,可不带后缀,程序会自动补充
file_existsstrNone遇到同名文件时的处理方式,可选'skip', 'overwrite', 'rename', 'add',默认跟随实例属性
show_msgboolTrue是否打印下载信息和进度
**kwargsAnyrequests 的连接参数
+
+

📌 add()

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
file_urlstr必填文件网址
goal_pathstr
Path
None保存路径,为None时保存到当前文件夹
rename`str|None指定文件另存的名称,可不带后缀,程序会自动补充
file_existsstrNone遇到同名文件时的处理方式,可选'skip', 'overwrite', 'rename', 'add',默认跟随实例属性
splitboolNone是否启用多线程分块下载,默认跟随实例属性
**kwargsAnyrequests 的连接参数
+
+

📌 连接参数

+

连接参数即**kwargs允许接收到参数,与 requests 的get()方法一致。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数名称类型说明
timeoutfloat连接超时时间
paramsdict查询参数字典
headersdictheaders
cookiesAnycookies
dataAnydata 数据
jsonAnyjson 数据
filesAny文件数据
authTuple[str, str]
HTTPBasicAuth
认证元组或对象
allow_redirectsbool是否允许自动跳转
proxiesdict代理 ip
hooksdict回调方法
verifybool是否验证SSL证书
certstr
Tuple[str, str]
SSL客户端证书
+

示例:

+
from DownloadKit import DownloadKit
+
+d = DownloadKit()
+h = {'referer': 'demourl.com'}
+d.download(url, headers=h)
+
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/site/usage/create_object/index.html b/site/usage/create_object/index.html new file mode 100644 index 0000000000000000000000000000000000000000..0eace463cea3c4d26a957bbc4a3d2e87f7efd7f1 --- /dev/null +++ b/site/usage/create_object/index.html @@ -0,0 +1,846 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 🐘 创建对象 - DownloadKit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + +

🐘 创建对象

+ +

✅️️ 创建DownloadKit对象

+

创建DownloadKit对象时,driver参数可传入一个用于携带登录信息的对象,可以是多种类型。

+

当传入的是DrissionPage的页面对象时,还可以根据页面访问的 url 自动设置referer参数。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
初始化参数类型默认值说明
goal_pathstr
Path
None文件保存路径
roadsint10可同时运行的线程数
driverSession
SessionOptions
ChromiumPage
SessionPage
ChromiumTab
WebPage
WebPageTab
None用于提供下载连接信息的页面或链接对象
file_existsstr'renmae'有同名文件名时的处理方式,可选'skip', 'overwrite', 'rename', 'add'
+
+

✅️️ 示例

+

📌 直接创建

+
from DownloadKit import DownloadKit
+
+d = DownloadKit()
+
+
+

📌 接收Session对象

+
from requests import Session
+from DownloadKit import DownloadKit
+
+session = Session()
+d = DownloadKit(session=session)
+
+
+

📌 接收SessionOptions对象

+
from DrissionPage import SessionOptions
+from DownloadKit import DownloadKit
+
+so = SessionOptions()
+d = DownloadKit(session=so)
+
+
+

📌 接收页面对象

+
from DrissionPage import ChromiumPage
+from DownloadKit import DownloadKit
+
+p = ChromiumPage()
+d = DownloadKit(session=p)
+
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/site/usage/misssions/index.html b/site/usage/misssions/index.html new file mode 100644 index 0000000000000000000000000000000000000000..0b28344a1bc46bbf9d844a15dfbbec5a1d3333a3 --- /dev/null +++ b/site/usage/misssions/index.html @@ -0,0 +1,1378 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 🐒 任务管理 - DownloadKit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

🐒 任务管理

+ +

本节介绍下载任务的管理。

+

add()方法会返回一个Mission对象,该对象可用于查看任务信息和管理任务。

+

✅️️ 任务进度

+

📌 rate

+

该属性返回任务完成的百分比。

+

类型:float

+

示例:

+
d = DownloadKit()
+m = d.add(url)
+
+print(m.rate)
+
+
+

📌 等待单个任务结束

+

Mission对象的wait()方法可等待该任务结束。

+ + + + + + + + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
showboolTrue是否打印下载信息
timeoutfloat0超时时间,0表示不限时
+

|返回类型|说明| +|tuple|任务结果和信息组成的tuple,格式:(任务结果, 任务信息)|

+

示例:

+
d = DownloadKit()
+m = d.add(url)
+
+m.wait()
+
+
+

📌 等待所有任务结束

+

DownloadKit对象的wait()方法,可等待所有任务结束。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
missionMission
int
None任务对象或任务 id,为None时等待所有任务结束
showboolFalse是否显示进度
timeoutfloat
None
None超时时间,None0不限时
+

示例:

+
d = DownloadKit()
+d.add(url1)
+d.add(url2)
+
+d.wait()
+
+
+

📌 取消任务

+

cancel()用于中途取消任务。

+

参数:

+

返回:None

+
+

📌 删除已下载文件

+

del_file()用于删除任务已下载的文件。

+

参数:

+

返回:None

+
+

✅️️ 任务信息

+

📌 任务状态

+

state属性返回任务状态,有以下三种:

+
    +
  • 'waiting':等待开始
  • +
  • 'running':运行中
  • +
  • 'done':已结束
  • +
+

任务状态不能看出任务是否成功,只能显示任务是否在运行。

+
+

📌 任务结果

+

result属性返回任务结果,有以下几种:

+
    +
  • 'success':下载成功
  • +
  • 'skipped':跳过,存在同名文件,且设置为跳过时
  • +
  • 'canceled':被取消
  • +
  • False:任务失败
  • +
  • None:未知,任务还没结束
  • +
+
+

📌 任务信息

+

info属性返回任务信息,在任务不同阶段,会返回不同信息。

+

info是对当前状态的文字解释,如任务失败时,会返回失败原因,成功时会返回文件保存路径。

+
+

✅️️ 获取任务对象

+

📌 获取所有任务对象

+

DownloadKit对象的missions属性以liist方式返回所有任务对象。

+

示例:

+
d = DownloadKit()
+d.add(url)
+print(d.missions)
+
+
+

📌 查找任务

+

DownloadKit对象的get_mission()方法可根据任务 id 获取任务对象。

+ + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
mission_or_idMission
int
必填任务或任务 id
+ + + + + + + + + + + + + + + + + +
返回类型说明
Mission任务对象
None没有找到该任务
+
+

📌 获取失败的任务

+

DownloadKit对象的get_failed_missions()方法可以list方式返回失败的任务。

+

参数:

+ + + + + + + + + + + + + +
返回类型说明
List[Mission]任务对象组成的列表
+
+

✅️️ Mission对象的属性

+

📌 id

+

此属性返回任务 id。

+

类型:int

+
+

📌 data

+

此属性返回任务使用的数据,即创建任务时输入的参数。

+

类型:MissionData

+
+

📌 state

+

此属性返回任务状态,有三种:'waiting''running''done'

+

类型:str

+
+

📌 result

+

此属性返回任务结果,有以下几种:'success''skipped''canceled'FalseNone

+

类型:str

+
+

📌 info

+

此属性返回任务描述信息。

+

类型:str

+
+

📌 is_done

+

此属性返回任务是否已完成。

+

类型:bool

+
+

📌 size

+

此属性返回文件大小。

+

类型:intNone

+
+

📌 tasks

+

此属性以list方式返回所有子任务

+

类型:List[Task]

+
+

📌 tasks_count

+

此属性返回子任务数量。

+

类型:int

+
+

📌 done_tasks_count

+

此属性返回已完成的子任务数量。

+

类型:int

+
+

📌 file_name

+

此属性返回文件名。

+

类型:strNone

+
+

📌 method

+

此属性返回连接方式,'get''post'

+

类型:str

+
+

📌 path

+

此属性返回文件保存路径。

+

类型:str

+
+

📌 rate

+

此属性以百分比方式返回下载进度。

+

类型:float

+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/site/usage/settings/index.html b/site/usage/settings/index.html new file mode 100644 index 0000000000000000000000000000000000000000..869d0a1169ad947ca4cff74ec57f50ea54e3d950 --- /dev/null +++ b/site/usage/settings/index.html @@ -0,0 +1,1365 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 🦍 运行设置 - DownloadKit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

🦍 运行设置

+ +

本节介绍DownloadKit对象相关设置。

+

✅️️ 使用方法

+

📌 全局设置

+

使用DownloadKit对象的set.xxxx()方法,可对各种允许参数进行设置。

+

这种方法设置的参数时全局有效的,之后新建的任务会默认使用。

+
from DownloadKit import DownloadKit
+
+d = DownloadKit()
+d.set.block_size('10m')  # 设置分块大小
+
+
+

📌 每个任务独立设置

+

每次新建任务时,可设置当前项目有效的设置,覆盖全局设置。

+
from DownloadKit import DownloadKit
+
+d = DownloadKit()
+d.set.goal_path('tmp1')  # 设置全局保存路径
+
+d.add(url, goal_path='tmp2')  # 创建任务时指定保存路径
+
+
+

✅️️ 运行设置

+

📌 set.driver()

+

此方法用于设置提供下载连接信息的页面或链接对象。

+

支持 DrissionPage 所有页面对象、Session对象、SessionOptions对象。

+

程序可从传入的对象中自动获取登录信息,如传入页面对象,还能自动设置Referer参数。

+ + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
driverSession
SessionOptions
ChromiumPage
SessionPage
ChromiumTab
WebPage
WebPageTab
必填用于提供连接信息的对象
+

返回:None

+
+

📌 set.goal_path()

+

此方法用于设置文件保存路径。

+ + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
goal_pathstr
Path
必填文件保存路径
+

返回:None

+
+

📌 set.if_file_exists()

+

此方法用于设置路径存在同名文件时的处理方式。

+

可选'skip', 'rename', 'overwrite', 'add'

+ + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
modestr必填处理方式字符串
+
    +
  • skip:跳过,不下载
  • +
  • overwrite:覆盖原有文件
  • +
  • rename:以在后面添加序号的方式给新文件重命名
  • +
  • add:在原有文件末尾追加内容
  • +
+

返回:None

+
+

📌 set.if_file_exists.xxxx()

+

这几个方法用于设置路径存在同名文件时的处理方式。

+

效果与set.if_file_exists()一致。

+
    +
  • skip():跳过,不下载
  • +
  • overwrite():覆盖原有文件
  • +
  • rename():以在后面添加序号的方式给新文件重命名
  • +
  • add():在原有文件末尾追加内容
  • +
+

示例:

+
from DownloadKit import DownloadKit
+
+d = DownloadKit()
+d.set.if_file_exists.skip()
+
+
+

📌 set.roads()

+

此方法用于设置可同时运行的线程数。

+ + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
numint必填线程数量
+

返回:None

+
+

📌 set.retry()

+

此方法用于设置连接失败时重试次数。

+ + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
timesint必填重试次数
+

返回:None

+
+

📌 set.interval()

+

此方法用于设置连接失败时重试间隔。

+ + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
secondsfloat必填连接失败时重试间隔(秒)
+

返回:None

+
+

📌 set.timeout()

+

此方法用于设置连接超时时间。

+ + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
secondsfloat必填超时时间(秒)
+

返回:None

+
+

📌 set.split()

+

此方法用于设置大文件是否分块下载。

+ + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
on_offbool必填bool代表开关
+

返回:None

+
+

📌 set.block_size()

+

此方法用于设置设置分块大小。

+ + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
sizestr
int
必填可接收intstr形式,接收int时以字节为单位;接收str时格式有:'10b''10k''10m''10g'四种,不区分大小写
+

返回:None

+
+

📌 set.proxies()

+

此方法用于设置代理地址及端口,例:'127.0.0.1:1080'。

+ + + + + + + + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
httpstrNonehttp 代理地址及端口
httpsstrNonehttps 代理地址及端口
+

返回:None

+
+

✅️️ 日志设置

+

日志设置方法在set.log属性中。

+

📌 set.log.path()

+

此方法用于设置日志文件路径。

+ + + + + + + + + + + + + + + + + +
参数名称类型默认值说明
pathstr
Path
必填文件路径
+

返回:None

+
+

📌 set.log.print_all()

+

此方法用于设置打印所有任务信息。

+

参数:

+

返回:None

+
+

📌 set.log.print_failed()

+

此方法用于设置打印失败的任务。

+

参数:

+

返回:None

+
+

📌 set.log.print_nothing()

+

此方法用于设置不打印任何信息。

+

参数:

+

返回:None

+
+

📌 set.log.log_all()

+

此方法用于记录打印所有任务信息到文件。

+

参数:

+

返回:None

+
+

📌 set.log.log_failed()

+

此方法用于设置记录失败的任务到文件。

+

参数:

+

返回:None

+
+

📌 set.log.log_nothing()

+

此方法用于设置不记录任何信息到文件。

+

参数:

+

返回:None

+
+ + + + + + +
+
+ + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file