⚙️ 下载文件
浏览器没有为下载功能提供方便的程序接口,难以实现有效的下载管理,如检测下载状态、重命名、失败管理等。使用 requests 下载文件能较好实现以上功能,但代码较为繁琐。
因此 DrissionPage 内置了高效可靠的下载工具,提供任务管理、多线程、大文件分块、自动重连、文件名冲突处理等功能。
无论是控制浏览器,还是收发数据包的场景,都可以使用它。甚至可以拦截浏览器的下载动作,转用内置下载器进行下载。使用方式简洁高效。
说明:
该工具名为 DownloadKit,现已独立打包成一个库,详细用法见:DownloadKit。这里只介绍和页面对象有关的用法。
✅️️ 功能简介
SessionPage
、ChromiumPage
、WebPage
都可以使用download()
方法进行下载,还可以使用download_set
属性对下载参数进行配置。内置下载器功能如下:
- 支持多线程同时下载多个文件
- 大文件自动分块使用多线程下载
- 可拦截浏览器下载动作,自动调用下载器下载
- 自动创建目标路径
- 自动去除路径中的非法字符
- 下载时支持文件重命名
- 自动处理文件名冲突
- 自动去除文件名非法字符
- 支持 post 方式
- 支持自定义连接参数
- 任务失败自动重试
✅️️ 简单示例
下载一个文件(单线程):
添加下载任务,以多线程方式下载:
拦截浏览器下载动作,改用 DwonloadKit 下载:
下载设置:
# 设置默认保存路径
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
:表示下载失败
任务信息成功时返回文件绝对路径,其它情况返回相应说明。
示例:
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)
显示:
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 相关说明 |
示例:
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)
输出:
✅️️ 接管浏览器下载任务
📌 切换下载方式
很多时候,网站会用某些非显式的方式触发浏览器下载,因此不能很好地获取文件 url,下载依赖浏览器功能。,页面对象可以设置用DownloadKit
拦截浏览器的下载任务,使下载更快,下载过程更可控。
方法是使用download_set.by_DownloadKit()
方法,指定使用DownloadKit
接管浏览器的下载动作。
事实上,页面对象创建时就默认开启了此功能,如果想用浏览器本身的下载功能,可以这样写:
注意
接管浏览器下载任务后会使用 get 方式下载,如果是需要 post 的请求,可能不能正确下载。
📌 等待下载开始
在浏览器中点击下载按钮后,有时下载不会立即触发,这时如果过快进行其它操作,可能导致一些意想不到的问题。因此设计了wait.download_begin()
方法,用于等待下载动作的开始,以便正确接管。可控制浏览器的页面对象ChromiumPage
和WebPage
拥有此方法。
注意
如果网站须要很长时间准备下载的文件,请设置一个足够长的超时时间。
🔸 wait.download_begin()
此方法会阻塞程序,等待下载动作触发。如到达超时时间仍未触发,则返回False
。
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
timeout |
float |
None |
等待下载开始的超时时间,为None 则使用页面对象timeout 属性 |
返回类型 | 说明 |
---|---|
bool |
是否等到下载开始 |
示例:
✅️️ 查看任务信息
用单线程方式下载,会阻塞程序直到下载完成,因此无须查看任务信息。
用多线程或接管浏览器下载任务的方式下载,可用以下方式查看任务信息。
📌 获取单个任务对象
使用download.add()
添加任务时,会返回一个任务对象,后续程序可以使用该对象查询该任务下载进度、结果,也可以取消任务。这里不对该对象作详细说明,详情请移步:DownloadKit。
示例:
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
传入此方法,会返回该任务对象。
示例:
📌 获取全部任务对象
使用页面对象的download.missions
属性,可以获取所有下载任务。该属性返回一个dict
,保存了所有下载任务。以任务对象的id
为 key。
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: <Mission 1 D:\download\xxx1.pdf xxx1.pdf>
2: <Mission 2 D:\download\xxx1_1.pdf xxx1_1.pdf>
...
}
📌 获取下载失败的任务
使用download.get_failed_missions()
方法,可以获取下载失败的任务列表。
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
示例:
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 次下载同一个文件
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 个文件:
🔸 download_set.if_file_exists.skip()
遇到同名文件时,跳过。同时任务对象的result
属性设置为'skip'
。
示例: 3 次下载同一个文件
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 个文件:
🔸 download_set.if_file_exists.overwrite()
遇到同名文件时,覆盖。
注意
这个方式在多线程下载时要慎用,万一多个任务下载多个同名文件,会导致互相覆盖的现象。
Tips
- 除了整体设置,还可以在创建任务时单独设置该任务的处理方式。
- 文件名如遇到
'?'
、'\'
等非法字符,会自动替换为空格。
📌 设置大文件是否分块
DownloadKit
具备多线程下载大文件功能,在文件超过指定大小时(默认 50MB),可对文件进行多线程分块下载,每个线程负责 50MB 的下载,以提高下载速度。这个功能默认是关闭的,您可以设置是否开启。
注意
这个设置只有在使用DownloadKit
作为下载工具时有效。
🔸 download_set.split()
Tips
除了整体设置,还可以在创建任务时单独设置该任务是否使用分块下载。
📌运行参数设置
运行参数主要包括可使用线程上限、连接失败重试次数、重试间隔。
🔸 download.roads
此参数设置整个DownloadKit
对象允许使用的线程数上限,默认为 10。
默认设置下,页面对象最多使用 10 个下载线程,如进程已满,新任务会进入等待队列排队,待有空线程时自动开始。
这个属性只能在没有任务在运行的时候设置。
🔸 download.retry
此属性用于设置连接失败时重试次数,默认为 3。
🔸 download.interval
此属性用于设置连接失败时重试间隔,默认为 5 秒。
Tips
重试次数和间隔在初始化时继承页面对象的retry_times
和retry_interval
属性,可用上面例子的方法对下载的重试次数和间隔进行设置,设置后不会影响页面对象的设置。