💥 4.0 功能介绍
 
3.x 是自主研发底层的初步尝试,很多地方摸着石头过河,存在一些不太成熟的地方。
经过一段时间的使用,积累一些经验之后,4.0 在 3.x 的基础上对底层进行了大幅重构,新增大量功能,改善运行效率和稳定性,优化项目结构,解决很多存在的问题。对比旧版本有质的提高。
但同时不少 api 发生了变化,不能完全兼容旧版本。
api 的变化有些是功能优化必需的改变,有些则是本人对命名简洁的执念,趁着大版本的更新顺便把长期不太满意的命名给改了。
给使用者造成一定不便感到抱歉,但长痛不如短痛,趁着项目用的人不多,干脆舍弃历史包袱果断改掉。
有些原来的写法在 4.0.0 中还能正常使用,但 IDE 会提示无效,将在以后的版本中完全删除。推荐尽快更新为新写法。
本节仅简述功能变化,具体使用方法详见各对应章节。
✅️ 新的抓包功能
3.2 中,抓包功能主要由 FlowViewer 和wait.data_packets()提供。
FlowViewer 是本人的一个练手作品,写得比较随意,技术也还没到家。存在漏抓、信息不全、api 不够合理的问题。
4.0 中,每个页面对象都内置了监听器,能力全面升级,api 也更合理。
📌 旧 api 变化
- 弃用 FlowViewer,以后也不会再升级
- 删除wait.set_targets()
- 删除wait.stop_listening()方法
- 删除wait.data_packets()方法
- DrissionPage.common路径删除- FlowViewer
📌 新 api
- 每个标签页对象(包括ChromiumFrame)新增listen属性,内置监听功能
- 用listen.start()和listen.stop()启动和停止监听
- 用listen.wait()阻塞等待数据包
- 用listen.steps()同步获取监听结果
- 增加listen.wait_silent()等待所有请求完成(包含 targets 以外的)
- 监听结果结构优化,request 和 response 数据分开存放
📌 示例
下面示例可直接运行查看结果。这个示例会计时,用于与下个示例对比。
from DrissionPage import ChromiumPage
from TimePinner import Pinner
from pprint import pprint
page = ChromiumPage()
page.listen.start('api/getkeydata')  # 指定监听目标并启动监听
pinner = Pinner(True, False)
page.get('http://www.hao123.com/')  # 访问网站
packet = page.listen.wait()  # 等待数据包
pprint(packet.response.body)  # 打印数据包正文
pinner.pin('用时', True)
输出:
{'hao123.new.shishi.bangdan.recom': [{'index': '1',
                                      'pure_title': '以色列和哈马斯移交首批被扣押人员'},
                                     {'index': '2',
                                      'pure_title': '听到免签政策法国外长笑了'},
                                     ......
用时:3.3114853000151925
✅️ 新的页面访问逻辑
3.x 中存连接存在以下主要问题:
- 浏览器页面对象get()方法的timeout参数只对加载阶段生效,无法覆盖连接阶段;
- 加载策略none模式没有实际用处。
这两个问题都在 4.0 中解决,且能够让用户自主控制终止连接的时机。 另外还对连接逻辑进行了优化,避免卡死情况出现。
📌 api 变化
- 页面对象page_load_strategy属性改名为load_mode
- set.load_strategy改为- set.load_mode
📌 行为变化
- get()方法的- timeout参数现在可覆盖整个过程
- timeout参数对非- get()方法触发的加载(如点击链接)也能生效
- SessionPage和- WebPage的 s 模式,如收到空数据,也会重试
- SessionPage的- get()方法可以指向本地文件
📌 新的none加载模式
旧版中,none加载策略是当页面  连接成功就立刻停止加载,这在实际使用时没有什么意义。
新版中,这个模式改成:除非加载完成,否则程序不会主动将其停止(即使已超时),同时连接状态不再阻塞程序,而允许用户进行状态判断,主动停止加载。
这样提供给用户非常大的自由度,可等到关键数据包或元素出现就主动停止页面加载,大幅提升执行效率。
📌 示例
我们继续使用上一个示例的代码,但把加载模式设为none,且获取到数据时主动停止加载。
from DrissionPage import ChromiumPage
from TimePinner import Pinner
from pprint import pprint
page = ChromiumPage()
page.set.load_mode.none()  # 设置加载模式为none
page.listen.start('api/getkeydata')  # 指定监听目标并启 动监听
pinner = Pinner(True, False)
page.get('http://www.hao123.com/')  # 访问网站
packet = page.listen.wait()  # 等待数据包
page.stop_loading()  # 主动停止加载
pprint(packet.response.body)  # 打印数据包正文
pinner.pin('用时', True)
输出:
{'hao123.new.shishi.bangdan.recom': [{'index': '1',
                                      'pure_title': '以色列和哈马斯移交首批被扣押人员'},
                                     {'index': '2',
                                      'pure_title': '听到免签政策法国外长笑了'},
                                     ......
用时:1.2575092000188306
可见节省了2秒时间。 当网站要访问一些不稳定资源时,节省的时间相当客观,也能提高程序的稳定性。
✅️ 新的下载管理功能
在旧版中,下载管理功能存在以下问题:
- 浏览器下载管理和内置下载器DownloadKit的配置都使用download_set属性进行设置,容易造成混淆。
- 浏览器下载任务不能在下载前指定文件名
- 该功能有随着浏览器版本更新失效的风险
4.0 对浏览器下载管理功能进行了完完全全的重构,结构更为合理,功能更多。 同时,内置下载器的设置和浏览器下载任务设置进行了分离。
📌 api 变化
- 页面对象删除download_set属性
- 增加set.download_path()方法
- 增加set.download_file_name()方法
📌 新增功能
- Tab 对象和 Frame 对象也支持download()方法
- 每个 Tab 对象可单独设置下载路径和重命名文件名
- 可拦截浏览器下载任务并获取其信息
- 可取消浏览器下载任务、获取下载进度、等待任务完成
- 可设置遇到文件夹已存在时的处理方式
📌 行为变化
4.0 中默认不启用浏览器下载任务管理,只有在启动参数中设置了下载路径,或调用set.download_path()方法时才会启动。
未启动任务管理功能时,下载行为和普通使用一样。
📌 示例
以下示例可直接运行。
from DrissionPage import ChromiumPage
page = ChromiumPage()
page.get('https://office.qq.com/download.html')
page.set.download_path('tmp')  # 设置文件保存路径
page.set.download_file_name('qq')  # 设置文件名
page('#downloadWin').click()  # 点击触发下载
mission = page.wait.download_begin()  # 等待下载开始并获取任务对象
mission.wait()  # 等下下载任务完成
输出:
url:https://dldir1.qq.com/qqfile/qq/TIM3.4.8/TIM3.4.8.22124.exe
文件名:qq.exe
目标路径:D:\coding\projects\DrissionPage\tmp
100.0% 下载完成 D:\coding\projects\DrissionPage\tmp\qq.exe
✅️ 页面对象
这里说的页面对象包括 Page 对象(ChromiumPage、WebPage)、Tab 对象(ChromiumTab、WebPageTab)、ChromiumFrame对象。
📌 启动参数变化
4.0 中,创建WebPage和ChromiumPage对象时,不再接收ChromiumDriver对象。
意思是不再支持传递控制权的方式创建页面对象。
因为本身支持多个页面对象控制同一个标签页,如果需要多页面对象协同,只要get_tab()创建一个新对象就行,可和原有对象并行使用。
而且,传递控制权本身有稳定性方面隐患,因此新版中将其删除。
相应地,启动参数的名称也发生了变化:
- WebPage对象的- driver_or_options参数改名为- chromium_options
- ChromiumPage对象的- addr_driver_opts参数改名为- addr_or_opts
另外,ChromiumPage的启动参数addr_or_opts现在可以接收int数据,直接传入端口号。
📌 内置动作链
4.0 中,每个页面对象内置actions属性,即动作链。
内置的动作链与直接创建的动作链对象有一个不同点,每次操作会等待页面加载完成再执行。
示例:
page.actions.hold(ele).move(50).release()
📌 状态信息
旧版中,页面对象拥有ready_state、is_loading、is_alive属性,现在都合并到states属性中。
# ------ 旧版代码 ------
print(page.is_loading)
# ------ 新版代码 ------
print(page.states.is_loading)
📌 其它
- ChromiumPage和- WebPage改为固定单例
- get_tab()获取的 Tab 对象默认单例,可用- Settings设置允许多例
- 页面对象增加raw_data参数,s 模式下返回原始数据
- 所有页面对象增加close()方法,SessionPage用于关闭连接,浏览器页面对象用于关闭标签页
- 浏览器页面对象增加wait()方法,用于等待若干秒
- 浏览器页面对象增加wait.ele_loaded()方法,等待元素加载到DOM
- 浏览器页面对象增加wait.title_change()和wait.url_change()方法,用于等待 title 和 url 变化
- 浏览器页面对象增加wait.alert_closed()方法,用于等待弹窗被手动关闭
- 浏览器页面对象增加set.cookie()方法,可设置单个 cookie
- 浏览器页面对象增加set.blocked_urls()方法,可设置忽略的连接
- Tab 和 Page 对象增加disconnect()方法,用于断开与网页连接
- Tab 和 Page 对象增加reconnect()方法,用于断开并重新连接网页
- Tab 和 Page 对象增加save()方法,用于把网页保存为 mhtml
- Tab 和 Page 对象增加add_init_js()和remove_init_js()方法
- quit()方法增加- force参数,可强制关闭浏览器进程
- ChromiumFrame增加- ract属性
- ChromiumFrame的- frame_size属性改为- rect.size
- wait.ele_delete()方法改为- wait.ele_deleted()
- wait.ele_display()方法改为- wait.ele_displayed()
- wait.load_complete()方法改为- wait.doc_loaded()
- 优化SessionPage和WebPages 模式访问速度
- WebPage在 d 模式时,- post()返回- Response对象
✅️ cookies 设置
- set.cookies()可接收单个 cookie
- 增加set.cookies.clear()方法用于清除 cookies
- 增加set.cookies.remove()方法用于删除一个 cookie 项