浏览器没有为下载功能提供方便的程序接口,难以实现有效的下载管理,如检测下载状态、重命名、失败管理等。使用 requests 下载文件能较好实现以上功能,但代码较为繁琐。 因此 DrissionPage 内置了高效可靠的下载工具,提供任务管理、多线程、大文件分块、自动重连、文件名冲突处理等功能。 无论是控制浏览器,还是收发数据包的场景,都可以使用它。甚至可以拦截浏览器的下载动作,转用内置下载器进行下载。使用方式简洁高效。 ?> 该工具名为 DownloadKit,现已独立打包成一个库,详细用法见:[DownloadKit](https://gitee.com/g1879/DownloadKit)。这里只介绍和页面对象有关的用法。 # ✔️ 功能简介 `SessionPage`、`ChromiumPage`、`WebPage`都可以使用`download()`方法进行下载,还可以使用`download_set`属性对下载参数进行配置。内置下载器功能如下: - 支持多线程同时下载多个文件 - 大文件自动分块使用多线程下载 - 可拦截浏览器下载动作,自动调用下载器下载 - 自动创建目标路径 - 自动去除路径中的非法字符 - 下载时支持文件重命名 - 自动处理文件名冲突 - 自动去除文件名非法字符 - 支持 post 方式 - 支持自定义连接参数 - 任务失败自动重试 --- # ✔️ 简单示例 下载一个文件(单线程): ```python page.download('https://xxxxxx/file.pdf') ``` 添加下载任务,以多线程方式下载: ```python page.download.add('https://xxxxxx/file.pdf') ``` 拦截浏览器下载动作,改用 DwonloadKit 下载: ```python page.download_set.by_DownloadKit() page('#download_btn').click() ``` 下载设置: ```python # 设置默认保存路径 page.download_set.save_path('...') # 设置存在同名文件时处理方式 page.download_set.if_file_exists.skip() # 设置使用浏览器或DownloadKit下载 page.download_set.by_DownloadKit() page.download_set.by_browser() # 设置使用DownloadKit下载时是否允许多线程同时下载一个文件 page.download_set.split(True) ``` --- # ✔️ 单线程下载 直接调用页面对象的`download()`方法,可下载一个文件,该方法是阻塞式的,会等待下载完成再往下操作。下载时默认打印下载进度。 ### 🔸 `download()` | 参数名称 | 类型 | 默认值 | 说明 | |:-------------:|:---------------:|:------:| ------------------------------------------------ | | `file_url` | `str` | 必填 | 文件网址 | | `goal_path` | `str`
`Path` | `None` | 保存文件夹路径,为`None`则保存在当前目录 | | `rename` | `str` | `None` | 重命名文件名,可不包含后缀 | | `file_exists` | `str` | `None` | 遇到同名文件时的处理方式,可选`'skip'`、`'overwrite'`、`'rename'` | | `data` | `str`
`dict` | `None` | post 方式使用的数据,如不为`None`,使用 post 方式发送请求 | | `show_msg` | `bool` | `True` | 是否显示下载进度 | | `**kwargs` | - | 必填 | requests的`get()`方法参数 | | 返回类型 | 返回格式 | 说明 | |:-------:|:------------:| ------------------- | | `tuple` | (任务结果, 任务信息) | 返回任务结果和信息组成的`tuple` | 任务结果可能出现以下值: - `'success'`:表示下载成功 - `'skip'`:表示存在同名文件,跳过任务 - `'cancel'`:表示任务下载途中被取消 - `False`:表示下载失败 任务信息成功时返回文件绝对路径,其它情况返回相应说明。 **示例:** ```python from DrissionPage import WebPage page = WebPage('s') # 文件 url url = 'https://www.baidu.com/img/flexible/logo/pc/result.png' # 存放路径 save_path = r'C:\download' # 重命名为img.png,存在重名时自动在文件名末尾加上序号,显示下载进度 res = page.download(url, save_path, 'img', 'rename', show_msg=True) # 打印结果 print(res) ``` 显示: ```console url:https://www.baidu.com/img/flexible/logo/pc/result.png 文件名:img.png 目标路径:C:\download 100% 下载完成 C:\download\img.png ('success', 'C:\\download\\img.png') ``` --- # ✔️ 多线程并发下载 您可以添加数量不限的下载任务,程序会自动调配线程去完成这些任务。 默认设置下,页面对象最多使用 10 个下载线程,如进程已满,新任务会进入等待队列排队,待有空线程时自动开始。 添加多线程任务的方法是调用页面对象`donwload`属性的`add()`方法。 ### 🔸 `download.add()` | 参数名称 | 类型 | 默认值 | 说明 | |:-------------:|:---------------:|:------:| ----------------------------------------------------------------- | | `file_url` | `str` | 必填 | 文件网址 | | `goal_path` | `str`
`Path` | `None` | 保存文件夹路径,为`None`则保存在当前目录 | | `rename` | `str` | `None` | 重命名文件名,可不包含后缀 | | `file_exists` | `str` | `None` | 遇到同名文件时的处理方式,可选`'skip'`、`'overwrite'`、`'rename'` | | `data` | `str`
`dict` | `None` | post 方式使用的数据,如不为`None`,使用 post 方式发送请求 | | `split` | `bool` | `None` | 是否允许多线程分块下载,为`None`则使用下载器内置设置,默认为`True`
默认大于 50MB 的文件使用多线程分块下载 | | `**kwargs` | - | 必填 | requests的`get()`方法参数 | | 返回类型 | 说明 | |:---------:| ---------------------------------------------------------------------------- | | `Mission` | 返回任务对象,任务对象具体属性及方法详见 [DownloadKit](https://gitee.com/g1879/DownloadKit) 相关说明 | **示例:** ```python from DrissionPage import WebPage page = WebPage('s') # 文件 url url = 'https://www.baidu.com/img/flexible/logo/pc/result.png' # 存放路径 save_path = r'C:\download' # 返回一个任务对象 mission = page.download.add(url, save_path) # 通过任务对象查看状态 print(mission.rate, mission.info) ``` **输出:** ```console 90% '下载中' ``` --- # ✔️ 接管浏览器下载任务 ## 📍 切换下载方式 很多时候,网站会用某些非显式的方式触发浏览器下载,因此不能很好地获取文件 url,下载依赖浏览器功能。,页面对象可以设置用`DownloadKit`拦截浏览器的下载任务,使下载更快,下载过程更可控。 方法是使用`download_set.by_DownloadKit()`方法,指定使用`DownloadKit`接管浏览器的下载动作。 ```python page.download_set.by_DownloadKit() ``` 事实上,页面对象创建时就默认开启了此功能,如果想用浏览器本身的下载功能,可以这样写: ```python page.download_set.by_browser() ``` !>**注意:**
接管浏览器下载任务后会使用 get 方式下载,如果是需要 post 的请求,可能不能正确下载。 --- ## 📍 等待下载开始 在浏览器中点击下载按钮后,有时下载不会立即触发,这时如果过快进行其它操作,可能导致一些意想不到的问题。因此设计了`wait_download_begin()` 方法,用于等待下载动作的开始,以便正确接管。可控制浏览器的页面对象`ChromiumPage`和`WebPage`拥有此方法。 !>**注意:**
如果网站须要很长时间准备下载的文件,请设置一个足够长的超时时间。 ### 🔸 `wait_download_begin()` 此方法会阻塞程序,等待下载动作触发。如到达超时时间仍未触发,则返回`False`。 | 参数名称 | 类型 | 默认值 | 说明 | |:---------:|:----------------:|:------:| ------------------------------------- | | `timeout` | `int`
`float` | `None` | 等待下载开始的超时时间,为`None`则使用页面对象`timeout`属性 | | 返回类型 | 说明 | |:------:| -------- | | `bool` | 是否等到下载开始 | **示例:** ```python page('#download_btn').click() page.wait_download_begin() ``` --- # ✔️ 查看任务信息 用单线程方式下载,会阻塞程序直到下载完成,因此无须查看任务信息。 用多线程或接管浏览器下载任务的方式下载,可用以下方式查看任务信息。 ## 📍 获取单个任务对象 使用`download.add()` 添加任务时,会返回一个任务对象,后续程序可以使用该对象查询该任务下载进度、结果,也可以取消任务。这里不对该对象作详细说明,详情请移步:[DownloadKit](https://gitee.com/g1879/DownloadKit)。 **示例:** ```python mission = page.download.add('http://xxxx.pdf') print(mission.id) # 获取任务id print(mission.rate) # 打印下载进度(百分比) print(mission.state) # 打印任务状态,'waiting'、'running'、'done' print(mission.info) # 打印任务信息 print(mission.result) # 打印任务结果,'success'表示成功,False表示失败,'skip'表示跳过,'cancel'表示取消 ``` 除添加任务时获取对象,也可以使用`download.get_mission()`获取。在上一个示例中可以看到,任务对象有`id`属性,把任务的`id`传入此方法,会返回该任务对象。 **示例:** ```python mission_id = mission.id mission = page.download.get_mission(mission_id) ``` --- ## 📍 获取全部任务对象 使用页面对象的`download.missions`属性,可以获取所有下载任务。该属性返回一个`dict`,保存了所有下载任务。以任务对象的`id`为 key。 ```python page.download_set.save_path(r'D:\download') page.download('http://xxxxx/xxx1.pdf') page.download('http://xxxxx/xxx1.pdf') print(page.download.missions) ``` **输出:** ``` { 1: 2: ... } ``` --- ## 📍 获取下载失败的任务 使用`download.get_failed_missions()`方法,可以获取下载失败的任务列表。 ```python page.download_set.save_path(r'D:\download') page.download('http://xxxxx/xxx1.pdf') page.download('http://xxxxx/xxx1.pdf') print(page.download.get_failed_missions() ``` **输出:** ``` [ , ... ] ``` ?>**Tips:**
获取失败任务对象后,可从其`data`属性读取任务内容,以便记录日志或择机重试。 --- # ✔️ 下载设置 主要的下载设置使用`download_set`内置方法进行,更多运行参数使用`download`属性的子属性进行。 ## 📍 设置文件保存路径 ### 🔸 `download_set.save_path()` 此方法用于设置文件下载默认保存路径。 | 参数名称 | 类型 | 默认值 | 说明 | |:------:|:---------------:|:---:| ------------------ | | `path` | `str`
`Path` | 必填 | 文件保存路径,绝对路径和相对路径均可 | **返回:**`None` **示例:** ```python page.download_set.save_path(r'D:\tmp') ``` ?>**Tips:**
- 保存路径可指定不存在的文件夹,程序会自动创建。
- 设置默认保存路径后,每个任务仍可在创建时指定自己的保存路径,以覆盖默认设置。 --- ## 📍 设置下载方式 ### 🔸 `download_set.by_DownloadKit()` 此方法用于设置当前页面对象使用`DownloadKit`下载文件。 ### 🔸 `download_set.by_browser()` 此方法用于设置当前页面对象使用浏览器下载工具下载文件。 --- ## 📍 设置重名文件处理方法 下载过程中可能遇到保存路径已存在同名文件,`DownloadKit`提供 3 种处理方法。 !>**注意:**
这个设置只有在使用`DownloadKit`作为下载工具时有效。 ### 🔸 `download_set.if_file_exists.rename()` 此方式会对新文件进行重命名,在文件名后加上序号。 假如,保存路径已存在`abc.txt`文件,新的`abc.txt`文件会自动重命名为`abc_1.txt`,再下载一个`abc.txt`时,会命名为`abc_2.txt`,如此类推。 **示例:** 3 次下载同一个文件 ```python page.download_set.if_file_exists.rename() page.download('http://xxxxx/xxx.pdf') page.download('http://xxxxx/xxx.pdf') page.download('http://xxxxx/xxx.pdf') ``` 在文件夹会生成如下 3 个文件: ``` xxx.pdf xxx_1.pdf xxx_2.pdf ``` --- ### 🔸 `download_set.if_file_exists.skip()` 遇到同名文件时,跳过。同时任务对象的`result`属性设置为`'skip'`。 **示例:** 3 次下载同一个文件 ```python page.download_set.if_file_exists.skip() page.download('http://xxxxx/xxx.pdf') page.download('http://xxxxx/xxx.pdf') page.download('http://xxxxx/xxx.pdf') ``` 在文件夹只会生成如下 1 个文件: ``` xxx.pdf ``` --- ### 🔸 `download_set.if_file_exists.overwrite()` 遇到同名文件时,覆盖。 !>**注意:**
这个方式在多线程下载时要慎用,万一多个任务下载多个同名文件,会导致互相覆盖的现象。 ?>**Tips:**
- 除了整体设置,还可以在创建任务时单独设置该任务的处理方式。
- 文件名如遇到`'?'`、`'\'`等非法字符,会自动替换为空格。 --- ## 📍 设置大文件是否分块 `DownloadKit`具备多线程下载大文件功能,在文件超过指定大小时(默认 50MB),可对文件进行多线程分块下载,每个线程负责 50MB 的下载,以提高下载速度。这个功能默认是关闭的,您可以设置是否开启。 !>**注意:** 这个设置只有在使用`DownloadKit`作为下载工具时有效。 ### 🔸 `download_set.split()` ```python # 使用分块下载 page.download_set.split(on_off=True) # 禁用分块下载 page.download_set.split(on_off=False) ``` ?>**Tips:** 除了整体设置,还可以在创建任务时单独设置该任务是否使用分块下载。 --- ## 📍运行参数设置 运行参数主要包括可使用线程上限、连接失败重试次数、重试间隔。 ### 🔸 `download.roads` 此参数设置整个`DownloadKit`对象允许使用的线程数上限,默认为 10。 默认设置下,页面对象最多使用 10 个下载线程,如进程已满,新任务会进入等待队列排队,待有空线程时自动开始。 这个属性只能在没有任务在运行的时候设置。 ```python page.download.roads = 20 # 允许最多使用20个线程进行下载 ``` --- ### 🔸 `download.retry` 此属性用于设置连接失败时重试次数,默认为 3。 ```python page.download.roads = 5 # 设置连接失败时重试5次 ``` --- ### 🔸 `download.interval` 此属性用于设置连接失败时重试间隔,默认为 5 秒。 ```python page.download.interval = 10 # 设置连接失败时等待10秒再重试 ``` ?> **Tips:**
重试次数和间隔在初始化时继承页面对象的`retry_times`和`retry_interval`属性,可用上面例子的方法对下载的重试次数和间隔进行设置,设置后不会影响页面对象的设置。