3.1.1修复浏览器弹出新标签页触发下载时的问题;修复easy_set()路径问题

This commit is contained in:
g1879 2023-01-28 14:51:43 +08:00
parent 207a420453
commit d0ed2a7767
16 changed files with 107 additions and 69 deletions

View File

@ -20,7 +20,3 @@ from .keys import Keys
from .mix_page import MixPage
from .drission import Drission
from .configs.driver_options import DriverOptions
from warnings import filterwarnings
filterwarnings('ignore')

View File

@ -7,11 +7,12 @@ from pathlib import Path
from platform import system
from threading import Thread
from time import perf_counter, sleep
from warnings import warn
from requests import Session
from .chromium_base import ChromiumBase, Timeout
from .chromium_driver import ChromiumDriver
from .chromium_driver import ChromiumDriver, CallMethodException
from .chromium_tab import ChromiumTab
from .configs.chromium_options import ChromiumOptions
from .configs.driver_options import DriverOptions
@ -30,6 +31,7 @@ class ChromiumPage(ChromiumBase):
:param timeout: 超时时间
"""
self._download_set = None
self._download_path = None
super().__init__(addr_driver_opts, tab_id, timeout)
def _connect_browser(self, addr_driver_opts=None, tab_id=None):
@ -93,10 +95,21 @@ class ChromiumPage(ChromiumBase):
:return: None
"""
super()._init_page(tab_id)
ws = self._control_session.get(f'http://{self.address}/json/version').json()['webSocketDebuggerUrl']
self._browser_driver = ChromiumDriver(ws.split('/')[-1], 'browser', self.address)
self._browser_driver.start()
self._tab_obj.Page.javascriptDialogOpening = self._on_alert_open
self._tab_obj.Page.javascriptDialogClosed = self._on_alert_close
self._main_tab = self.tab_id
self.download_set.by_DownloadKit()
try:
self.download_set.by_DownloadKit()
except RuntimeError:
pass
@property
def browser_driver(self):
"""返回用于控制浏览器cdp的driver"""
return self._browser_driver
@property
def tabs_count(self):
@ -106,7 +119,7 @@ class ChromiumPage(ChromiumBase):
@property
def tabs(self):
"""返回所有标签页id组成的列表"""
j = self._control_session.get(f'http://{self.address}/json').json()
j = self._control_session.get(f'http://{self.address}/json').json() # 不要改用cdp
return [i['id'] for i in j if i['type'] == 'page']
@property
@ -388,6 +401,9 @@ class ChromiumDownloadSetter(DownloadSetter):
"""用于设置下载参数的类"""
def __init__(self, page):
"""
:param page: ChromiumPage对象
"""
super().__init__(page)
self._behavior = 'allow'
self._download_th = None
@ -419,24 +435,33 @@ class ChromiumDownloadSetter(DownloadSetter):
path = str(path)
self._page._download_path = path
try:
self._page.run_cdp('Browser.setDownloadBehavior', behavior='allow', downloadPath=path, not_change=True)
except:
self._page.browser_driver.Browser.setDownloadBehavior(behavior='allow', downloadPath=path,
eventsEnabled=True)
except CallMethodException:
warn('\n您的浏览器版本太低,用新标签页下载文件可能崩溃,建议升级。')
self._page.run_cdp('Page.setDownloadBehavior', behavior='allow', downloadPath=path, not_change=True)
self.DownloadKit.goal_path = path
def by_browser(self):
"""设置使用浏览器下载文件"""
self._page.driver.Page.downloadWillBegin = self._download_by_browser
self._page.driver.Browser.downloadWillBegin = self._download_by_browser
self._page.driver.Browser.setDownloadBehavior(behavior='allow', downloadPath=self._page.download_path)
try:
self._page.browser_driver.Browser.setDownloadBehavior(behavior='allow', eventsEnabled=True,
downloadPath=self._page.download_path)
self._page.browser_driver.Browser.downloadWillBegin = self._download_by_browser
except CallMethodException:
self._page.driver.Page.setDownloadBehavior(behavior='allow', downloadPath=self._page.download_path)
self._page.driver.Page.downloadWillBegin = self._download_by_browser
self._behavior = 'allow'
def by_DownloadKit(self):
"""设置使用DownloadKit下载文件"""
self._page.driver.Page.downloadWillBegin = self._download_by_DownloadKit
self._page.driver.Browser.downloadWillBegin = self._download_by_DownloadKit
self._page.driver.Browser.setDownloadBehavior(behavior='deny')
try:
self._page.browser_driver.Browser.setDownloadBehavior(behavior='deny', eventsEnabled=True)
self._page.browser_driver.Browser.downloadWillBegin = self._download_by_DownloadKit
except CallMethodException:
raise RuntimeError('您的浏览器版本太低,不支持此方法,请升级。')
self._behavior = 'deny'
def wait_download_begin(self, timeout=None):
@ -465,7 +490,7 @@ class ChromiumDownloadSetter(DownloadSetter):
def _download_by_DownloadKit(self, **kwargs):
"""拦截浏览器下载并用downloadKit下载"""
self._page.run_cdp('Browser.cancelDownload', guid=kwargs['guid'], not_change=True)
self._page.browser_driver.Browser.cancelDownload(guid=kwargs['guid'])
self._page.download.add(file_url=kwargs['url'], goal_path=self._page.download_path,
rename=kwargs['suggestedFilename'])
if self._download_th is None or not self._download_th.is_alive():

View File

@ -32,6 +32,7 @@ class ChromiumPage(ChromiumBase):
self._alert: Alert = ...
self._download_path: str = ...
self._download_set: ChromiumDownloadSetter = ...
self._browser_driver: ChromiumDriver = ...
def _connect_browser(self,
addr_driver_opts: Union[str, ChromiumDriver, DriverOptions] = None,
@ -43,6 +44,9 @@ class ChromiumPage(ChromiumBase):
def _init_page(self, tab_id: str = None) -> None: ...
@property
def browser_driver(self) -> ChromiumDriver: ...
@property
def tabs_count(self) -> int: ...

View File

@ -58,7 +58,7 @@ def set_paths(driver_path=None,
om.set_item('paths', 'chromedriver_path', format_path(driver_path))
if chrome_path is not None:
om.set_item('chrome_options', 'binary_location', format_path(browser_path))
om.set_item('chrome_options', 'binary_location', format_path(chrome_path))
if browser_path is not None:
om.set_item('chrome_options', 'binary_location', format_path(browser_path))

View File

@ -5,13 +5,14 @@
"""
from pathlib import Path
from time import sleep
from warnings import warn
from requests import Session
from tldextract import extract
from .base import BasePage
from .chromium_base import ChromiumBase, Timeout
from .chromium_driver import ChromiumDriver
from .chromium_driver import ChromiumDriver, CallMethodException
from .chromium_page import ChromiumPage, ChromiumDownloadSetter
from .configs.chromium_options import ChromiumOptions
from .configs.driver_options import DriverOptions
@ -507,9 +508,10 @@ class WebPageDownloadSetter(ChromiumDownloadSetter):
if self._page._has_driver:
try:
self._page.run_cdp('Browser.setDownloadBehavior', behavior=self._behavior, downloadPath=path,
not_change=True)
except:
self._page.browser_driver.Browser.setDownloadBehavior(behavior=self._behavior, downloadPath=path,
eventsEnabled=True)
except CallMethodException:
warn('\n您的浏览器版本太低,用新标签页下载文件可能崩溃,建议升级。')
self._page.run_cdp('Page.setDownloadBehavior', behavior=self._behavior, downloadPath=path,
not_change=True)
@ -517,15 +519,26 @@ class WebPageDownloadSetter(ChromiumDownloadSetter):
"""设置使用浏览器下载文件"""
if not self._page._has_driver:
raise RuntimeError('浏览器未连接。')
self._page.driver.Page.downloadWillBegin = self._download_by_browser
self._page.driver.Browser.downloadWillBegin = self._download_by_browser
self._page.driver.Browser.setDownloadBehavior(behavior='allow', downloadPath=self._page.download_path)
try:
self._page.browser_driver.Browser.setDownloadBehavior(behavior='allow', eventsEnabled=True,
downloadPath=self._page.download_path)
self._page.browser_driver.Browser.downloadWillBegin = self._download_by_browser
except CallMethodException:
warn('\n您的浏览器版本太低,用新标签页下载文件可能崩溃,建议升级。')
self._page.driver.Page.setDownloadBehavior(behavior='allow', downloadPath=self._page.download_path)
self._page.driver.Page.downloadWillBegin = self._download_by_browser
self._behavior = 'allow'
def by_DownloadKit(self):
"""设置使用DownloadKit下载文件"""
if self._page._has_driver:
self._page.driver.Page.downloadWillBegin = self._download_by_DownloadKit
self._page.driver.Browser.downloadWillBegin = self._download_by_DownloadKit
self._page.driver.Browser.setDownloadBehavior(behavior='deny')
try:
self._page.browser_driver.Browser.setDownloadBehavior(behavior='deny', eventsEnabled=True)
self._page.browser_driver.Browser.downloadWillBegin = self._download_by_DownloadKit
except CallMethodException:
raise RuntimeError('您的浏览器版本太低,不支持此方法,请升级。')
self._behavior = 'deny'

View File

@ -37,11 +37,11 @@ page = SessionPage()
# ✔️ 通过配置信息创建
本库有两种管理配置信息的对象,`DriverOptions`和`SessionOptions`,分别对应控制浏览器和收发数据包的配置。须要时,可以创建相应的配置对象进行设置。
本库有两种管理配置信息的对象,`ChromiumOptions`和`SessionOptions`,分别对应控制浏览器和收发数据包的配置。须要时,可以创建相应的配置对象进行设置。
## 📍 `DriverOptions`
## 📍 `ChromiumOptions`
`DriverOptions`用于管理创建浏览器时的配置,内置了常用的配置,并能实现链式操作。详细使用方法见“启动配置”一节。
`ChromiumOptions`用于管理创建浏览器时的配置,内置了常用的配置,并能实现链式操作。详细使用方法见“启动配置”一节。
| 初始化参数 | 类型 | 默认值 | 说明 |
| ----------- | ------ | ------ | ------------------------ |
@ -51,11 +51,11 @@ page = SessionPage()
!>**注意:**<br>浏览器创建后再修改这个配置是没有效果的。
```python
# 导入 DriverOptions
from DrissionPage import WebPage, DriverOptions
# 导入 ChromiumOptions
from DrissionPage import WebPage, ChromiumOptions
# 创建浏览器配置对象,指定浏览器路径
do = DriverOptions().set_paths(browser_path=r'D:\chrome.exe')
do = ChromiumOptions().set_paths(browser_path=r'D:\chrome.exe')
# 用该配置创建页面对象
page = WebPage(driver_or_options=do)
```
@ -192,9 +192,9 @@ D:\chrome.exe --remote-debugging-port=9222
程序代码:
```python
from DrissionPage import WebPage, DriverOptions
from DrissionPage import WebPage, ChromiumOptions
do = DriverOptions().set_paths(local_port=9222)
do = ChromiumOptions().set_paths(local_port=9222)
page = WebPage(driver_or_options=do)
```
@ -216,18 +216,18 @@ page = WebPage(driver_or_options=do)
## 📍 用程序启动的浏览器
如果想要同时操作多个浏览器,或者自己在使用其中一个上网,同时控制另外几个跑自动化,就须要给这些被程序控制的浏览器设置单独的**端口**和**用户文件夹**,否则会造成冲突。具体用`DriverOptions`对象进行设置,示例如下:
如果想要同时操作多个浏览器,或者自己在使用其中一个上网,同时控制另外几个跑自动化,就须要给这些被程序控制的浏览器设置单独的**端口**和**用户文件夹**,否则会造成冲突。具体用`ChromiumOptions`对象进行设置,示例如下:
```python
from DrissionPage import ChromiumPage, DriverOptions
from DrissionPage import ChromiumPage, ChromiumOptions
# 创建多个配置对象,每个指定不同的端口号和用户文件夹路径
do1 = DriverOptions().set_paths(local_port=9111, user_data_path=r'D:\data1')
do2 = DriverOptions().set_paths(local_port=9222, user_data_path=r'D:\data2')
do1 = ChromiumOptions().set_paths(local_port=9111, user_data_path=r'D:\data1')
do2 = ChromiumOptions().set_paths(local_port=9222, user_data_path=r'D:\data2')
# 创建多个页面对象
page1 = ChromiumPage(driver_or_options=do1)
page2 = ChromiumPage(driver_or_options=do2)
page1 = ChromiumPage(addr_driver_opts=do1)
page2 = ChromiumPage(addr_driver_opts=do2)
# 每个页面对象控制一个浏览器
page1.get('https://www.baidu.com')
@ -255,24 +255,24 @@ bat 文件2
程序代码:
```python
from DrissionPage import ChromiumPage, DriverOptions
from DrissionPage import ChromiumPage, ChromiumOptions
do1 = DriverOptions().set_paths(local_port=9111)
do2 = DriverOptions().set_paths(local_port=9222)
do1 = ChromiumOptions().set_paths(local_port=9111)
do2 = ChromiumOptions().set_paths(local_port=9222)
page1 = ChromiumPage(addr_driver_opts=do1)
page2 = ChromiumPage(driver_or_options=do2)
page2 = ChromiumPage(addr_driver_opts=do2)
```
# ✔️ 页面对象初始化 API
## 📍 `ChromiumPage`
`ChroumiumPage`对象纯粹用于操作浏览器,不能切换模式。一个该对象对应的是浏览器上一个标签页
`ChroumiumPage`对象纯粹用于操作浏览器,不能切换模式。一个该对象对应一个浏览器
| 初始化参数 | 类型 | 默认值 | 说明 |
| ------------------ | -------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- |
| `addr_driver_opts` | `str`<br>`ChromiumDriver`<br>`DriverOptions` | `None` | 浏览器启动配置或接管信息。传入' ip:port' 字符串或`ChromiumDriver`时接管浏览器;传入`DriverOptions`时按配置启动浏览器;为`None`时使用配置文件配置启动浏览器 |
| `addr_driver_opts` | `str`<br>`ChromiumDriver` | `None` | 浏览器启动配置或接管信息。传入' ip:port' 字符串或`ChromiumDriver`时接管浏览器;传入`DriverOptions`时按配置启动浏览器;为`None`时使用配置文件配置启动浏览器 |
| `tab_id` | `str` | `None` | 要控制的标签页id用于 d 模式,为`None`则控制激活的标签页 |
| `timeout` | `float` | `None` | 整体超时时间,为`None`则从配置文件中读取 |
@ -294,7 +294,7 @@ page2 = ChromiumPage(driver_or_options=do2)
| `mode` | `str` | `'d'` | 启动时的模式,只能传入`'d'``'s'` |
| `timeout` | `float` | `None` | 整体超时时间,为`None`则从配置文件中读取 |
| `tab_id` | `str` | `None` | 要控制的标签页id用于 d 模式,为`None`则控制激活的标签页 |
| `driver_or_options` | `ChromiumDriver`<br>`DriverOptions`<br>`bool` | `None` | 浏览器控制对象或浏览器启动配置对象;为`None`时使用 ini 文件配置;为`False`时不读取 ini 文件。 |
| `driver_or_options` | `ChromiumDriver`<br>`bool` | `None` | 浏览器控制对象或浏览器启动配置对象;为`None`时使用 ini 文件配置;为`False`时不读取 ini 文件。 |
| `session_or_options` | `Session`<br>`SessionOptions`<br>`bool` | `None` | 收发数据包对象或`Session`启动配置对象;为`None`时使用 ini 文件配置;为`False`时不读取 ini 文件。 |
**◽ 说明:**

BIN
docs/imgs/baidu_1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
docs/imgs/baidu_2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

View File

@ -35,7 +35,7 @@ page.get('https://www.baidu.com')
```python
from DrissionPage.easy_set import set_paths
set_paths(chrome_path=r'这里修改为您的Chrome浏览器exe文件路径', check_version=False)
set_paths(browser_path=r'这里修改为您的Chrome浏览器exe文件路径')
```
执行这段代码会记录您电脑的 Chrome 浏览器路径到配置文件。

View File

@ -38,7 +38,7 @@ from DrissionPage import ChromiumPage
from DrissionPage import SessionPage
# 浏览启动参数管理器,用于控制浏览器启动参数
from DrissionPage import DriverOptions
from DrissionPage import ChromiumOptions
# Session对象启动参数管理器用于控制Session对象启动参数
from DrissionPage import SessionOptions

View File

@ -1,5 +1,5 @@
`SessionOptions`对象用于管理`Session`对象连接配置。
其使用逻辑与`DriverOptions`相似。
其使用逻辑与`ChromiumOptions`相似。
!> **注意:** <br>`SessionOptions`仅用于管理启动配置,程序启动后再修改无效。

View File

@ -96,12 +96,12 @@ page = WebPage()
这种方式一般用于加载配置后须要进一步修改。
```python
from DrissionPage import DriverOptions, SessionOptions, WebPage
from DrissionPage import ChromiumOptions, SessionOptions, WebPage
do = DriverOptions(ini_path='D:\\setting.ini')
do = ChromiumOptions(ini_path='D:\\setting.ini')
so = SessionOptions(ini_path='D:\\setting.ini')
page = WebPage(driver_or_options=do, session_or_option=so)
page = WebPage(driver_or_options=do, session_or_options=so)
```
## 📍 使用 Drission 对象加载
@ -120,9 +120,9 @@ page = MixPage(drission=ds)
# ✔️ 保存/另存 ini 文件
```python
from DrissionPage import DriverOptions
from DrissionPage import ChromiumOptions
do = DriverOptions()
do = ChromiumOptions()
# 设置不加载图片
do.set_no_imgs()

View File

@ -2,6 +2,6 @@
因此,本库提供了一些方法简化其使用。
- 使用 ini 文件记录常用配置,使配置便于复用,无须在代码中编写繁琐的配置。
- 使用`DriverOptions`对象管理浏览器配置。
- 使用`ChromiumOptions`对象管理浏览器配置。
- 使用`SessionOptions`对象管理`Session`对象配置。
- 提供 easy_set 方法,专门用于对 ini 文件中常用配置进行管理,简化配置操作。

View File

@ -1,4 +1,4 @@
# v3.1.0
# v3.1.1
- 增强下载功能

View File

@ -15,9 +15,9 @@
`WebPage`
```python
from DrissionPage import WebPage, DriverOptions, SessionOptions
from DrissionPage import WebPage, ChromiumOptions, SessionOptions
do = DriverOptions(ini_path=r'.\configs.ini')
do = ChromiumOptions(ini_path=r'.\configs.ini')
so = SessionOptions(ini_path=r'.\configs.ini')
page = WebPage(driver_or_options=do, session_or_options=so)
```
@ -38,9 +38,9 @@ page = MixPage(drission=drission)
`WebPage`
```python
from DrissionPage import WebPage, DriverOptions, SessionOptions
from DrissionPage import WebPage, ChromiumOptions, SessionOptions
do = DriverOptions(read_file=False) # 不读取文件方式新建配置对象
do = ChromiumOptions(read_file=False) # 不读取文件方式新建配置对象
so = SessionOptions(read_file=False)
do.set_paths(chrome_path=r'.\chrome.exe') # 输入配置信息
@ -70,11 +70,11 @@ page = WebPage(driver_or_options=do, session_or_options=False)
通常,我会把一个绿色浏览器和打包后的 exe 文件放在一起,程序中用相对路径指向该浏览器,这样拿到别的电脑也可以正常实用。
```python
from DrissionPage import WebPage, DriverOptions
from DrissionPage import WebPage, ChromiumOptions
do = DriverOptions(read_file=False).set_paths(local_port='9888',
chrome_path=r'.\Chrome\chrome.exe',
user_data_path=r'.\Chrome\userData')
do = ChromiumOptions(read_file=False).set_paths(local_port='9888',
browser_path=r'.\Chrome\chrome.exe',
user_data_path=r'.\Chrome\userData')
page = WebPage(driver_or_options=do, session_or_options=False)
# 注意session_or_options=False
@ -83,5 +83,5 @@ page.get('https://www.baidu.com')
注意以下两点,程序就会跳过读取 ini 文件:
- `DriverOptions()`里要设置`read_file=False`
- 如果不传入某个模式的配置(示例中为 s 模式),要在`MixPage()`初始化是设置对应参数为`False`
- `ChromiumOptions()`里要设置`read_file=False`
- 如果不传入某个模式的配置(示例中为 s 模式),要在页面对象初始化时设置对应参数为`False`

View File

@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh:
setup(
name="DrissionPage",
version="3.1.0",
version="3.1.1",
author="g1879",
author_email="g1879@qq.com",
description="A module that integrates selenium and requests session, encapsulates common page operations.",