From 38dcc88dfa25eeaad4e49c79e23a9c8dfc90195c Mon Sep 17 00:00:00 2001
From: g1879 <g1879@qq.com>
Date: Thu, 30 Nov 2023 14:48:50 +0800
Subject: [PATCH] =?UTF-8?q?3.2.35=E4=BF=AE=E5=A4=8D=E9=97=AE=E9=A2=98?=
 =?UTF-8?q?=EF=BC=88=E8=AF=A6=EF=BC=89=20tabs=E5=B1=9E=E6=80=A7=E5=BF=BD?=
 =?UTF-8?q?=E7=95=A5=E9=9A=90=E7=A7=81=E5=A3=B0=E6=98=8E=20=E4=BF=AE?=
 =?UTF-8?q?=E5=A4=8D=208x=20=E7=89=88=E6=B5=8F=E8=A7=88=E5=99=A8=E9=80=89?=
 =?UTF-8?q?=E6=8B=A9=E4=B8=8B=E6=8B=89=E5=88=97=E8=A1=A8=E6=97=B6=E6=8A=A5?=
 =?UTF-8?q?=E9=94=99=E9=97=AE=E9=A2=98=20=E4=BF=AE=E5=A4=8D=E6=9F=90?=
 =?UTF-8?q?=E4=BA=9B=E6=83=85=E5=86=B5=E4=B8=8B=E4=B8=8B=E6=8B=89=E6=A1=86?=
 =?UTF-8?q?=E4=B8=8D=E8=A7=A6=E5=8F=91=E8=81=94=E5=8A=A8=E7=9A=84=E9=97=AE?=
 =?UTF-8?q?=E9=A2=98=20=E4=BF=AE=E5=A4=8D=E9=85=8D=E7=BD=AE=E6=96=87?=
 =?UTF-8?q?=E4=BB=B6=E6=8D=9F=E5=9D=8F=E6=97=B6=E5=87=BA=E7=8E=B0=E7=9A=84?=
 =?UTF-8?q?=E9=97=AE=E9=A2=98=20=E4=BF=AE=E5=A4=8Dget()=E6=96=B9=E6=B3=95u?=
 =?UTF-8?q?rl=E5=90=AB=E6=9F=90=E4=BA=9B=E7=89=B9=E6=AE=8A=E5=AD=97?=
 =?UTF-8?q?=E7=AC=A6=E6=97=B6=E8=BF=9E=E6=8E=A5=E5=A4=B1=E8=B4=A5=E7=9A=84?=
 =?UTF-8?q?=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 DrissionPage/__init__.py                    |  2 ++
 DrissionPage/base.py                        |  2 +-
 DrissionPage/chromium_element.py            |  4 ++--
 DrissionPage/chromium_page.py               |  3 ++-
 DrissionPage/commons/browser.py             | 15 +++++++------
 DrissionPage/commons/cli.py                 |  4 ++--
 DrissionPage/commons/constants.py           |  2 +-
 DrissionPage/configs/chromium_options.py    |  2 +-
 DrissionPage/configs/session_options.py     |  2 +-
 DrissionPage/easy_set.py                    |  2 +-
 DrissionPage/mixpage/base.py                |  4 ++--
 DrissionPage/mixpage/drission.py            | 12 +++++------
 DrissionPage/mixpage/driver_element.py      |  6 +++---
 DrissionPage/mixpage/driver_page.py         |  2 +-
 DrissionPage/mixpage/session_element.py     |  4 ++--
 DrissionPage/mixpage/session_page.py        |  4 ++--
 DrissionPage/mixpage/shadow_root_element.py |  2 +-
 README.md                                   | 24 ++++++++++++---------
 setup.py                                    |  2 +-
 19 files changed, 54 insertions(+), 44 deletions(-)

diff --git a/DrissionPage/__init__.py b/DrissionPage/__init__.py
index 335c6a4..2f87351 100644
--- a/DrissionPage/__init__.py
+++ b/DrissionPage/__init__.py
@@ -19,3 +19,5 @@ try:
     from .configs.driver_options import DriverOptions
 except ModuleNotFoundError:
     pass
+
+__version__ = '3.2.35'
diff --git a/DrissionPage/base.py b/DrissionPage/base.py
index 6800ca6..3bc3469 100644
--- a/DrissionPage/base.py
+++ b/DrissionPage/base.py
@@ -387,7 +387,7 @@ class BasePage(BaseParser):
         :param interval: 重试间隔
         :return: 重试次数和间隔组成的tuple
         """
-        self._url = quote(url, safe='/:&?=%;#@+![]')
+        self._url = quote(url, safe='-_.~!*\'"();:@&=+$,/\\?#[]%')
         retry = retry if retry is not None else self.retry_times
         interval = interval if interval is not None else self.retry_interval
         return retry, interval
diff --git a/DrissionPage/chromium_element.py b/DrissionPage/chromium_element.py
index f34b02e..353182b 100644
--- a/DrissionPage/chromium_element.py
+++ b/DrissionPage/chromium_element.py
@@ -1815,7 +1815,7 @@ class ChromiumSelect(object):
     @property
     def options(self):
         """返回所有选项元素组成的列表"""
-        return self._ele.eles('xpath://option')
+        return [e for e in self._ele.eles('xpath://option') if isinstance(e, ChromiumElement)]
 
     @property
     def selected_option(self):
@@ -2020,7 +2020,7 @@ class ChromiumSelect(object):
 
     def _dispatch_change(self):
         """触发修改动作"""
-        self._ele.run_js('this.dispatchEvent(new UIEvent("change"));')
+        self._ele.run_js('this.dispatchEvent(new Event("change", {bubbles: true}));')
 
 
 class ChromiumElementWaiter(object):
diff --git a/DrissionPage/chromium_page.py b/DrissionPage/chromium_page.py
index 240d776..c654f95 100644
--- a/DrissionPage/chromium_page.py
+++ b/DrissionPage/chromium_page.py
@@ -131,7 +131,8 @@ class ChromiumPage(ChromiumBase):
     def tabs(self):
         """返回所有标签页id组成的列表"""
         j = self._control_session.get(f'http://{self.address}/json').json()  # 不要改用cdp
-        return [i['id'] for i in j if i['type'] == 'page']
+        return [i['id'] for i in j if i['type'] == 'page' and not i['url'].startswith('devtools://') and i[
+            'url'] != 'chrome://privacy-sandbox-dialog/notice']
 
     @property
     def main_tab(self):
diff --git a/DrissionPage/commons/browser.py b/DrissionPage/commons/browser.py
index 5c4bf4e..368adb9 100644
--- a/DrissionPage/commons/browser.py
+++ b/DrissionPage/commons/browser.py
@@ -3,18 +3,18 @@
 @Author  :   g1879
 @Contact :   g1879@qq.com
 """
-from json import load, dump
+from json import load, dump, JSONDecodeError
 from pathlib import Path
+from platform import system
 from subprocess import Popen, DEVNULL
 from tempfile import gettempdir
 from time import perf_counter, sleep
-from platform import system
 
 from requests import get as requests_get
 
-from DrissionPage.configs.chromium_options import ChromiumOptions
-from DrissionPage.errors import BrowserConnectError
 from .tools import port_is_using
+from ..configs.chromium_options import ChromiumOptions
+from ..errors import BrowserConnectError
 
 
 def connect_browser(option):
@@ -43,7 +43,7 @@ def connect_browser(option):
 
     # 传入的路径找不到,主动在ini文件、注册表、系统变量中找
     except FileNotFoundError:
-        from DrissionPage.easy_set import get_chrome_path
+        from ..easy_set import get_chrome_path
         chrome_path = get_chrome_path(show_msg=False)
 
         if not chrome_path:
@@ -136,7 +136,10 @@ def set_prefs(opt):
             f.write('{}')
 
     with open(prefs_file, "r", encoding='utf-8') as f:
-        prefs_dict = load(f)
+        try:
+            prefs_dict = load(f)
+        except JSONDecodeError:
+            prefs_dict = {}
 
         for pref in prefs:
             value = prefs[pref]
diff --git a/DrissionPage/commons/cli.py b/DrissionPage/commons/cli.py
index cc82107..f9507db 100644
--- a/DrissionPage/commons/cli.py
+++ b/DrissionPage/commons/cli.py
@@ -1,7 +1,7 @@
 from click import command, option
 
-from DrissionPage import ChromiumPage
-from DrissionPage.easy_set import set_paths, configs_to_here as ch
+from ..chromium_page import ChromiumPage
+from ..easy_set import set_paths, configs_to_here as ch
 
 
 @command()
diff --git a/DrissionPage/commons/constants.py b/DrissionPage/commons/constants.py
index c06c2c4..612beb3 100644
--- a/DrissionPage/commons/constants.py
+++ b/DrissionPage/commons/constants.py
@@ -3,7 +3,7 @@
 @Author  :   g1879
 @Contact :   g1879@qq.com
 """
-from DrissionPage.errors import ElementNotFoundError
+from ..errors import ElementNotFoundError
 
 HANDLE_ALERT_METHOD = 'Page.handleJavaScriptDialog'
 FRAME_ELEMENT = ('iframe', 'frame')
diff --git a/DrissionPage/configs/chromium_options.py b/DrissionPage/configs/chromium_options.py
index f5d32b2..0ade900 100644
--- a/DrissionPage/configs/chromium_options.py
+++ b/DrissionPage/configs/chromium_options.py
@@ -6,8 +6,8 @@
 from pathlib import Path
 from tempfile import gettempdir, TemporaryDirectory
 
-from DrissionPage.commons.tools import port_is_using, clean_folder
 from .options_manage import OptionsManager
+from ..commons.tools import port_is_using, clean_folder
 
 
 class ChromiumOptions(object):
diff --git a/DrissionPage/configs/session_options.py b/DrissionPage/configs/session_options.py
index eaa763b..01cc3d3 100644
--- a/DrissionPage/configs/session_options.py
+++ b/DrissionPage/configs/session_options.py
@@ -8,8 +8,8 @@ from pathlib import Path
 from requests import Session
 from requests.structures import CaseInsensitiveDict
 
-from DrissionPage.commons.web import cookies_to_tuple, set_session_cookies
 from .options_manage import OptionsManager
+from ..commons.web import cookies_to_tuple, set_session_cookies
 
 
 class SessionOptions(object):
diff --git a/DrissionPage/easy_set.py b/DrissionPage/easy_set.py
index 2876e0c..b8defe1 100644
--- a/DrissionPage/easy_set.py
+++ b/DrissionPage/easy_set.py
@@ -16,7 +16,7 @@ from .session_page import SessionPage
 
 try:
     from selenium import webdriver
-    from DrissionPage.mixpage.drission import Drission
+    from .mixpage.drission import Drission
     from .configs.driver_options import DriverOptions
 except ModuleNotFoundError:
     pass
diff --git a/DrissionPage/mixpage/base.py b/DrissionPage/mixpage/base.py
index 1194326..d38527f 100644
--- a/DrissionPage/mixpage/base.py
+++ b/DrissionPage/mixpage/base.py
@@ -7,8 +7,8 @@ from abc import abstractmethod
 from re import sub
 from urllib.parse import quote
 
-from DrissionPage.commons.web import format_html
-from DrissionPage.commons.locator import get_loc
+from ..commons.locator import get_loc
+from ..commons.web import format_html
 
 
 class BaseParser(object):
diff --git a/DrissionPage/mixpage/drission.py b/DrissionPage/mixpage/drission.py
index c8a6f90..906fdda 100644
--- a/DrissionPage/mixpage/drission.py
+++ b/DrissionPage/mixpage/drission.py
@@ -14,11 +14,11 @@ from selenium.webdriver.chrome.options import Options
 from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
 from tldextract import extract
 
-from DrissionPage.commons.tools import get_pid_from_port, get_exe_from_port
-from DrissionPage.commons.browser import connect_browser
-from DrissionPage.commons.web import cookies_to_tuple
-from DrissionPage.configs.session_options import SessionOptions, session_options_to_dict
-from DrissionPage.configs.driver_options import DriverOptions
+from ..commons.browser import connect_browser
+from ..commons.tools import get_pid_from_port, get_exe_from_port
+from ..commons.web import cookies_to_tuple
+from ..configs.driver_options import DriverOptions
+from ..configs.session_options import SessionOptions, session_options_to_dict
 
 
 class Drission(object):
@@ -399,7 +399,7 @@ def create_driver(chrome_path, driver_path, options):
     # 若版本不对,获取对应 chromedriver 再试
     except (WebDriverException, SessionNotCreatedException):
         print('打开失败,尝试获取driver。\n')
-        from DrissionPage.easy_set import get_match_driver, get_chrome_path
+        from ..easy_set import get_match_driver, get_chrome_path
 
         if chrome_path == 'chrome':
             chrome_path = get_chrome_path(show_msg=False, from_ini=False)
diff --git a/DrissionPage/mixpage/driver_element.py b/DrissionPage/mixpage/driver_element.py
index d083961..e7c730c 100644
--- a/DrissionPage/mixpage/driver_element.py
+++ b/DrissionPage/mixpage/driver_element.py
@@ -15,10 +15,10 @@ from selenium.webdriver.support import expected_conditions as ec
 from selenium.webdriver.support.wait import WebDriverWait
 
 from .base import DrissionElement, BaseElement
-from DrissionPage.commons.locator import str_to_loc, get_loc
-from DrissionPage.commons.tools import get_usable_path
-from DrissionPage.commons.web import format_html, get_ele_txt
 from .session_element import make_session_ele
+from ..commons.locator import str_to_loc, get_loc
+from ..commons.tools import get_usable_path
+from ..commons.web import format_html, get_ele_txt
 
 
 class DriverElement(DrissionElement):
diff --git a/DrissionPage/mixpage/driver_page.py b/DrissionPage/mixpage/driver_page.py
index 2f9fcfd..0779b4b 100644
--- a/DrissionPage/mixpage/driver_page.py
+++ b/DrissionPage/mixpage/driver_page.py
@@ -13,9 +13,9 @@ from selenium.webdriver.remote.webelement import WebElement
 from selenium.webdriver.support.wait import WebDriverWait
 
 from .base import BasePage
-from DrissionPage.commons.tools import get_usable_path
 from .driver_element import DriverElement, make_driver_ele, Scroll, ElementWaiter
 from .session_element import make_session_ele
+from ..commons.tools import get_usable_path
 
 
 class DriverPage(BasePage):
diff --git a/DrissionPage/mixpage/session_element.py b/DrissionPage/mixpage/session_element.py
index 39b5232..a2eb6d0 100644
--- a/DrissionPage/mixpage/session_element.py
+++ b/DrissionPage/mixpage/session_element.py
@@ -10,8 +10,8 @@ from lxml.etree import tostring
 from lxml.html import HtmlElement, fromstring
 
 from .base import DrissionElement, BasePage, BaseElement
-from DrissionPage.commons.locator import get_loc
-from DrissionPage.commons.web import get_ele_txt, make_absolute_link
+from ..commons.locator import get_loc
+from ..commons.web import get_ele_txt, make_absolute_link
 
 
 class SessionElement(DrissionElement):
diff --git a/DrissionPage/mixpage/session_page.py b/DrissionPage/mixpage/session_page.py
index 1ca8c2c..b866346 100644
--- a/DrissionPage/mixpage/session_page.py
+++ b/DrissionPage/mixpage/session_page.py
@@ -13,9 +13,9 @@ from requests.structures import CaseInsensitiveDict
 from tldextract import extract
 
 from .base import BasePage
-from DrissionPage.configs.session_options import SessionOptions
-from DrissionPage.commons.web import cookie_to_dict, set_session_cookies
 from .session_element import SessionElement, make_session_ele
+from ..commons.web import cookie_to_dict, set_session_cookies
+from ..configs.session_options import SessionOptions
 
 
 class SessionPage(BasePage):
diff --git a/DrissionPage/mixpage/shadow_root_element.py b/DrissionPage/mixpage/shadow_root_element.py
index 1ce0860..227d39e 100644
--- a/DrissionPage/mixpage/shadow_root_element.py
+++ b/DrissionPage/mixpage/shadow_root_element.py
@@ -9,9 +9,9 @@ from typing import Union
 from selenium.webdriver.remote.webelement import WebElement
 
 from .base import BaseElement
-from DrissionPage.commons.locator import get_loc
 from .driver_element import make_driver_ele
 from .session_element import make_session_ele, SessionElement
+from ..commons.locator import get_loc
 
 
 class ShadowRootElement(BaseElement):
diff --git a/README.md b/README.md
index d3378ff..022a82c 100644
--- a/README.md
+++ b/README.md
@@ -30,13 +30,23 @@ python 版本:3.6 及以上
 
 **📖 使用文档:**  [点击查看](https://g1879.gitee.io/drissionpagedocs)
 
-**交流 QQ 群:**  897838127[已满]、558778073
+**交流 QQ 群:**  636361957
 
 ---
 
-# 🔥 新版预告
+# 🔥 新版尝鲜
 
-查看下一步开发计划:[新版预告](https://g1879.gitee.io/drissionpagedocs/whatsnew/3_3/)
+4.0 在 3.x 的基础上对底层进行了大幅重构,新增大量功能,改善运行效率和稳定性,优化项目结构,解决很多存在的问题。对比旧版本有质的提高。
+
+现已发布 beta 版,欢迎尝鲜。
+
+[4.0功能介绍](https://g1879.gitee.io/drissionpagedocs/whatsnew/4_0/)
+
+安装(目前是b14,关注文档,可能会有更新版本):
+
+```console
+pip install DrissionPage==4.0.0b14
+```
 
 ---
 
@@ -108,17 +118,11 @@ python 版本:3.6 及以上
 
 - 还有很多细节,这里不一一列举,欢迎实际使用中体验:)
 
----
-
-# 🛠 使用文档
-
-[点击跳转到使用文档](https://g1879.gitee.io/drissionpage)
-
 --- 
 
 # 🔖 版本历史
 
-[点击查看版本历史](https://g1879.gitee.io/drissionpagedocs/history/3.x/)
+[点击查看版本历史](https://g1879.gitee.io/drissionpagedocs/history/introduction/)
 
 --- 
 
diff --git a/setup.py b/setup.py
index 3b50914..dcaef44 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh:
 
 setup(
     name="DrissionPage",
-    version="3.2.34",
+    version="3.2.35",
     author="g1879",
     author_email="g1879@qq.com",
     description="Python based web automation tool. It can control the browser and send and receive data packets.",