插件路径自动变成绝对路径;抓包加上判断frame;元素坐标改为float;修复配置文件损坏时出现的问题

This commit is contained in:
g1879 2023-11-14 11:41:33 +08:00
parent a5e86167e2
commit 47557844e0
14 changed files with 68 additions and 77 deletions

View File

@ -3,7 +3,7 @@
@Author : g1879 @Author : g1879
@Contact : g1879@qq.com @Contact : g1879@qq.com
""" """
from json import load, dump from json import load, dump, JSONDecodeError
from pathlib import Path from pathlib import Path
from subprocess import Popen, DEVNULL from subprocess import Popen, DEVNULL
from tempfile import gettempdir from tempfile import gettempdir
@ -105,7 +105,7 @@ def get_launch_args(opt):
opt._headless = headless opt._headless = headless
# ----------处理插件extensions------------- # ----------处理插件extensions-------------
ext = opt.extensions ext = [str(Path(e).absolute()) for e in opt.extensions]
if ext: if ext:
ext = ','.join(set(ext)) ext = ','.join(set(ext))
ext = f'--load-extension={ext}' ext = f'--load-extension={ext}'
@ -140,7 +140,10 @@ def set_prefs(opt):
f.write('{}') f.write('{}')
with open(prefs_file, "r", encoding='utf-8') as f: 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: for pref in prefs:
value = prefs[pref] value = prefs[pref]

View File

@ -9,9 +9,9 @@ from typing import Union
from requests import Session from requests import Session
from requests.cookies import RequestsCookieJar from requests.cookies import RequestsCookieJar
from .._base.base import BasePage, DrissionElement
from .._elements.chromium_element import ChromiumElement from .._elements.chromium_element import ChromiumElement
from .._pages.chromium_base import ChromiumBase from .._pages.chromium_base import ChromiumBase
from ..base import DrissionElement, BasePage
def get_ele_txt(e: DrissionElement) -> str: ... def get_ele_txt(e: DrissionElement) -> str: ...
@ -20,10 +20,10 @@ def get_ele_txt(e: DrissionElement) -> str: ...
def format_html(text: str) -> str: ... def format_html(text: str) -> str: ...
def location_in_viewport(page: ChromiumBase, loc_x: int, loc_y: int) -> bool: ... def location_in_viewport(page: ChromiumBase, loc_x: float, loc_y: float) -> bool: ...
def offset_scroll(ele: ChromiumElement, offset_x: int, offset_y: int) -> tuple: ... def offset_scroll(ele: ChromiumElement, offset_x: float, offset_y: float) -> tuple: ...
def make_absolute_link(link, page: BasePage = None) -> str: ... def make_absolute_link(link, page: BasePage = None) -> str: ...

View File

@ -16,7 +16,7 @@ from .._commons.tools import get_usable_path
from .._commons.web import make_absolute_link, get_ele_txt, format_html, is_js_func, offset_scroll from .._commons.web import make_absolute_link, get_ele_txt, format_html, is_js_func, offset_scroll
from .._units.clicker import Clicker from .._units.clicker import Clicker
from .._units.element_states import ElementStates, ShadowRootStates from .._units.element_states import ElementStates, ShadowRootStates
from .._units.ids import Ids, ElementIds from .._units.ids import ShadowRootIds, ElementIds
from .._units.locations import Locations from .._units.locations import Locations
from .._units.scroller import ElementScroller from .._units.scroller import ElementScroller
from .._units.select_element import SelectElement from .._units.select_element import SelectElement
@ -130,7 +130,7 @@ class ChromiumElement(DrissionElement):
def size(self): def size(self):
"""返回元素宽和高组成的元组""" """返回元素宽和高组成的元组"""
border = self.page.run_cdp('DOM.getBoxModel', backendNodeId=self._backend_id)['model']['border'] border = self.page.run_cdp('DOM.getBoxModel', backendNodeId=self._backend_id)['model']['border']
return int(border[2] - border[0]), int(border[5] - border[1]) return border[2] - border[0], border[5] - border[1]
@property @property
def set(self): def set(self):
@ -772,7 +772,7 @@ class ChromiumShadowRoot(BaseElement):
self._obj_id = obj_id self._obj_id = obj_id
self._node_id = self._get_node_id(obj_id) self._node_id = self._get_node_id(obj_id)
self._backend_id = self._get_backend_id(self._node_id) self._backend_id = self._get_backend_id(self._node_id)
self._ids = Ids(self) self._ids = ShadowRootIds(self)
self._states = None self._states = None
def __repr__(self): def __repr__(self):

View File

@ -15,7 +15,7 @@ from .._pages.chromium_page import ChromiumPage
from .._pages.web_page import WebPage from .._pages.web_page import WebPage
from .._units.clicker import Clicker from .._units.clicker import Clicker
from .._units.element_states import ShadowRootStates, ElementStates from .._units.element_states import ShadowRootStates, ElementStates
from .._units.ids import Ids, ElementIds from .._units.ids import ElementIds, ShadowRootIds
from .._units.locations import Locations from .._units.locations import Locations
from .._units.scroller import ElementScroller from .._units.scroller import ElementScroller
from .._units.select_element import SelectElement from .._units.select_element import SelectElement
@ -25,9 +25,7 @@ from .._units.waiter import ElementWaiter
class ChromiumElement(DrissionElement): class ChromiumElement(DrissionElement):
def __init__(self, def __init__(self, page: ChromiumBase, node_id: str = None, obj_id: str = None, backend_id: str = None):
page: ChromiumBase,
node_id: str = None, obj_id: str = None, backend_id: str = None):
self._tag: str = ... self._tag: str = ...
self.page: Union[ChromiumPage, WebPage] = ... self.page: Union[ChromiumPage, WebPage] = ...
self._node_id: str = ... self._node_id: str = ...
@ -46,8 +44,7 @@ class ChromiumElement(DrissionElement):
def __repr__(self) -> str: ... def __repr__(self) -> str: ...
def __call__(self, def __call__(self, loc_or_str: Union[Tuple[str, str], str],
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> Union[ChromiumElement, str, None]: ... timeout: float = None) -> Union[ChromiumElement, str, None]: ...
@property @property
@ -73,7 +70,7 @@ class ChromiumElement(DrissionElement):
def ids(self) -> ElementIds: ... def ids(self) -> ElementIds: ...
@property @property
def size(self) -> Tuple[int, int]: ... def size(self) -> Tuple[float, float]: ...
@property @property
def set(self) -> ChromiumElementSetter: ... def set(self) -> ChromiumElementSetter: ...
@ -82,7 +79,7 @@ class ChromiumElement(DrissionElement):
def states(self) -> ElementStates: ... def states(self) -> ElementStates: ...
@property @property
def location(self) -> Tuple[int, int]: ... def location(self) -> Tuple[float, float]: ...
@property @property
def locations(self) -> Locations: ... def locations(self) -> Locations: ...
@ -167,12 +164,10 @@ class ChromiumElement(DrissionElement):
def run_async_js(self, script: str, *args: Any, as_expr: bool = False) -> None: ... def run_async_js(self, script: str, *args: Any, as_expr: bool = False) -> None: ...
def ele(self, def ele(self, loc_or_str: Union[Tuple[str, str], str],
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> Union[ChromiumElement, str]: ... timeout: float = None) -> Union[ChromiumElement, str]: ...
def eles(self, def eles(self, loc_or_str: Union[Tuple[str, str], str],
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> List[Union[ChromiumElement, str]]: ... timeout: float = None) -> List[Union[ChromiumElement, str]]: ...
def s_ele(self, loc_or_str: Union[Tuple[str, str], str] = None) -> Union[SessionElement, str, NoneElement]: ... def s_ele(self, loc_or_str: Union[Tuple[str, str], str] = None) -> Union[SessionElement, str, NoneElement]: ...
@ -220,12 +215,9 @@ class ChromiumElement(DrissionElement):
class ChromiumShadowRoot(BaseElement): class ChromiumShadowRoot(BaseElement):
def __init__(self, def __init__(self, parent_ele: ChromiumElement, obj_id: str = None, backend_id: str = None):
parent_ele: ChromiumElement,
obj_id: str = None,
backend_id: str = None):
self._obj_id: str = ... self._obj_id: str = ...
self._ids: Ids = ... self._ids: ShadowRootIds = ...
self._node_id: str = ... self._node_id: str = ...
self._backend_id: str = ... self._backend_id: str = ...
self.page: ChromiumPage = ... self.page: ChromiumPage = ...
@ -234,12 +226,11 @@ class ChromiumShadowRoot(BaseElement):
def __repr__(self) -> str: ... def __repr__(self) -> str: ...
def __call__(self, def __call__(self, loc_or_str: Union[Tuple[str, str], str],
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> ChromiumElement: ... timeout: float = None) -> ChromiumElement: ...
@property @property
def ids(self) -> Ids: ... def ids(self) -> ShadowRootIds: ...
@property @property
def states(self) -> ShadowRootStates: ... def states(self) -> ShadowRootStates: ...
@ -279,12 +270,10 @@ class ChromiumShadowRoot(BaseElement):
def afters(self, filter_loc: Union[tuple, str] = '') -> List[Union[ChromiumElement, str]]: ... def afters(self, filter_loc: Union[tuple, str] = '') -> List[Union[ChromiumElement, str]]: ...
def ele(self, def ele(self, loc_or_str: Union[Tuple[str, str], str],
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> Union[ChromiumElement]: ... timeout: float = None) -> Union[ChromiumElement]: ...
def eles(self, def eles(self, loc_or_str: Union[Tuple[str, str], str],
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> List[ChromiumElement]: ... timeout: float = None) -> List[ChromiumElement]: ...
def s_ele(self, loc_or_str: Union[Tuple[str, str], str] = None) -> Union[SessionElement, str, NoneElement]: ... def s_ele(self, loc_or_str: Union[Tuple[str, str], str] = None) -> Union[SessionElement, str, NoneElement]: ...
@ -303,24 +292,16 @@ class ChromiumShadowRoot(BaseElement):
def _get_backend_id(self, node_id: str) -> str: ... def _get_backend_id(self, node_id: str) -> str: ...
def find_in_chromium_ele(ele: ChromiumElement, def find_in_chromium_ele(ele: ChromiumElement, loc: Union[str, Tuple[str, str]],
loc: Union[str, Tuple[str, str]], single: bool = True, timeout: float = None, relative: bool = True) \
single: bool = True,
timeout: float = None,
relative: bool = True) \
-> Union[ChromiumElement, str, NoneElement, List[Union[ChromiumElement, str]]]: ... -> Union[ChromiumElement, str, NoneElement, List[Union[ChromiumElement, str]]]: ...
def find_by_xpath(ele: ChromiumElement, def find_by_xpath(ele: ChromiumElement, xpath: str, single: bool, timeout: float,
xpath: str,
single: bool,
timeout: float,
relative: bool = True) -> Union[ChromiumElement, List[ChromiumElement], NoneElement]: ... relative: bool = True) -> Union[ChromiumElement, List[ChromiumElement], NoneElement]: ...
def find_by_css(ele: ChromiumElement, def find_by_css(ele: ChromiumElement, selector: str, single: bool,
selector: str,
single: bool,
timeout: float) -> Union[ChromiumElement, List[ChromiumElement], NoneElement]: ... timeout: float) -> Union[ChromiumElement, List[ChromiumElement], NoneElement]: ...

View File

@ -129,6 +129,8 @@ class ChromiumPage(ChromiumBase):
@property @property
def rect(self): def rect(self):
"""返回保存窗口方位信息的对象"""
self.wait.load_complete()
if self._rect is None: if self._rect is None:
self._rect = TabRect(self) self._rect = TabRect(self)
return self._rect return self._rect

View File

@ -73,7 +73,7 @@ class Clicker(object):
by_js = True by_js = True
elif can_click and (by_js is False or not self._ele.states.is_covered): elif can_click and (by_js is False or not self._ele.states.is_covered):
x = int(rect[1][0] - (rect[1][0] - rect[0][0]) / 2) x = rect[1][0] - (rect[1][0] - rect[0][0]) / 2
y = rect[0][0] + 3 y = rect[0][0] + 3
try: try:
r = self._ele.page.run_cdp('DOM.getNodeForLocation', x=x, y=y, includeUserAgentShadowDOM=True, r = self._ele.page.run_cdp('DOM.getNodeForLocation', x=x, y=y, includeUserAgentShadowDOM=True,

View File

@ -20,8 +20,8 @@ class Clicker(object):
def middle(self) -> None: ... def middle(self) -> None: ...
def at(self, offset_x: int = None, offset_y: int = None, button: str = 'left', count: int = 1) -> None: ... def at(self, offset_x: float = None, offset_y: float = None, button: str = 'left', count: int = 1) -> None: ...
def twice(self, by_js: bool = False) -> None: ... def twice(self, by_js: bool = False) -> None: ...
def _click(self, client_x: int, client_y: int, button: str = 'left', count: int = 1) -> None: ... def _click(self, client_x: float, client_y: float, button: str = 'left', count: int = 1) -> None: ...

View File

@ -5,7 +5,7 @@
""" """
class Ids(object): class ShadowRootIds(object):
def __init__(self, ele): def __init__(self, ele):
self._ele = ele self._ele = ele
@ -25,7 +25,7 @@ class Ids(object):
return self._ele._backend_id return self._ele._backend_id
class ElementIds(Ids): class ElementIds(ShadowRootIds):
@property @property
def doc_id(self): def doc_id(self):
"""返回所在document的object id""" """返回所在document的object id"""

View File

@ -9,7 +9,7 @@ from .._pages.chromium_frame import ChromiumFrame
from .._elements.chromium_element import ChromiumElement, ChromiumShadowRoot from .._elements.chromium_element import ChromiumElement, ChromiumShadowRoot
class Ids(object): class ShadowRootIds(object):
def __init__(self, ele: Union[ChromiumElement, ChromiumShadowRoot]): def __init__(self, ele: Union[ChromiumElement, ChromiumShadowRoot]):
self._ele: Union[ChromiumElement, ChromiumShadowRoot] = ... self._ele: Union[ChromiumElement, ChromiumShadowRoot] = ...
@ -23,7 +23,7 @@ class Ids(object):
def backend_id(self) -> str: ... def backend_id(self) -> str: ...
class ElementIds(Ids): class ElementIds(ShadowRootIds):
@property @property
def doc_id(self) -> str: ... def doc_id(self) -> str: ...

View File

@ -34,19 +34,19 @@ class Locations(object):
def viewport_location(self): def viewport_location(self):
"""返回元素左上角在视口中的坐标""" """返回元素左上角在视口中的坐标"""
m = self._get_viewport_rect('border') m = self._get_viewport_rect('border')
return int(m[0]), int(m[1]) return m[0], m[1]
@property @property
def viewport_midpoint(self): def viewport_midpoint(self):
"""返回元素中间点在视口中的坐标""" """返回元素中间点在视口中的坐标"""
m = self._get_viewport_rect('border') m = self._get_viewport_rect('border')
return int(m[0] + (m[2] - m[0]) // 2), int(m[3] + (m[5] - m[3]) // 2) return m[0] + (m[2] - m[0]) // 2, m[3] + (m[5] - m[3]) // 2
@property @property
def viewport_click_point(self): def viewport_click_point(self):
"""返回元素接受点击的点视口坐标""" """返回元素接受点击的点视口坐标"""
m = self._get_viewport_rect('padding') m = self._get_viewport_rect('padding')
return int(self.viewport_midpoint[0]), int(m[1]) + 3 return self.viewport_midpoint[0], m[1] + 3
@property @property
def screen_location(self): def screen_location(self):
@ -54,7 +54,7 @@ class Locations(object):
vx, vy = self._ele.page.rect.viewport_location vx, vy = self._ele.page.rect.viewport_location
ex, ey = self.viewport_location ex, ey = self.viewport_location
pr = self._ele.page.run_js('return window.devicePixelRatio;') pr = self._ele.page.run_js('return window.devicePixelRatio;')
return int((vx + ex) * pr), int((ey + vy) * pr) return (vx + ex) * pr, (ey + vy) * pr
@property @property
def screen_midpoint(self): def screen_midpoint(self):
@ -62,7 +62,7 @@ class Locations(object):
vx, vy = self._ele.page.rect.viewport_location vx, vy = self._ele.page.rect.viewport_location
ex, ey = self.viewport_midpoint ex, ey = self.viewport_midpoint
pr = self._ele.page.run_js('return window.devicePixelRatio;') pr = self._ele.page.run_js('return window.devicePixelRatio;')
return int((vx + ex) * pr), int((ey + vy) * pr) return (vx + ex) * pr, (ey + vy) * pr
@property @property
def screen_click_point(self): def screen_click_point(self):
@ -70,15 +70,15 @@ class Locations(object):
vx, vy = self._ele.page.rect.viewport_location vx, vy = self._ele.page.rect.viewport_location
ex, ey = self.viewport_click_point ex, ey = self.viewport_click_point
pr = self._ele.page.run_js('return window.devicePixelRatio;') pr = self._ele.page.run_js('return window.devicePixelRatio;')
return int((vx + ex) * pr), int((ey + vy) * pr) return (vx + ex) * pr, (ey + vy) * pr
@property @property
def rect(self): def rect(self):
"""返回元素四个角坐标顺序坐上、右上、右下、左下没有大小的元素抛出NoRectError""" """返回元素四个角坐标顺序坐上、右上、右下、左下没有大小的元素抛出NoRectError"""
vr = self._get_viewport_rect('border') vr = self._get_viewport_rect('border')
r = self._ele.page.run_cdp_loaded('Page.getLayoutMetrics')['visualViewport'] r = self._ele.page.run_cdp_loaded('Page.getLayoutMetrics')['visualViewport']
sx = int(r['pageX']) sx = r['pageX']
sy = int(r['pageY']) sy = r['pageY']
return [(vr[0] + sx, vr[1] + sy), (vr[2] + sx, vr[3] + sy), return [(vr[0] + sx, vr[1] + sy), (vr[2] + sx, vr[3] + sy),
(vr[4] + sx, vr[5] + sy), (vr[6] + sx, vr[7] + sy)] (vr[4] + sx, vr[5] + sy), (vr[6] + sx, vr[7] + sy)]
@ -86,7 +86,7 @@ class Locations(object):
def viewport_rect(self): def viewport_rect(self):
"""返回元素四个角视口坐标顺序坐上、右上、右下、左下没有大小的元素抛出NoRectError""" """返回元素四个角视口坐标顺序坐上、右上、右下、左下没有大小的元素抛出NoRectError"""
r = self._get_viewport_rect('border') r = self._get_viewport_rect('border')
return [(int(r[0]), int(r[1])), (int(r[2]), int(r[3])), (int(r[4]), int(r[5])), (int(r[6]), int(r[7]))] return [(r[0], r[1]), (r[2], r[3]), (r[4], r[5]), (r[6], r[7])]
def _get_viewport_rect(self, quad): def _get_viewport_rect(self, quad):
"""按照类型返回在可视窗口中的范围 """按照类型返回在可视窗口中的范围

View File

@ -13,38 +13,38 @@ class Locations(object):
self._ele: ChromiumElement = ... self._ele: ChromiumElement = ...
@property @property
def location(self) -> Tuple[int, int]: ... def location(self) -> Tuple[float, float]: ...
@property @property
def midpoint(self) -> Tuple[int, int]: ... def midpoint(self) -> Tuple[float, float]: ...
@property @property
def click_point(self) -> Tuple[int, int]: ... def click_point(self) -> Tuple[float, float]: ...
@property @property
def viewport_location(self) -> Tuple[int, int]: ... def viewport_location(self) -> Tuple[float, float]: ...
@property @property
def viewport_midpoint(self) -> Tuple[int, int]: ... def viewport_midpoint(self) -> Tuple[float, float]: ...
@property @property
def viewport_click_point(self) -> Tuple[int, int]: ... def viewport_click_point(self) -> Tuple[float, float]: ...
@property @property
def screen_location(self) -> Tuple[int, int]: ... def screen_location(self) -> Tuple[float, float]: ...
@property @property
def screen_midpoint(self) -> Tuple[int, int]: ... def screen_midpoint(self) -> Tuple[float, float]: ...
@property @property
def screen_click_point(self) -> Tuple[int, int]: ... def screen_click_point(self) -> Tuple[float, float]: ...
@property @property
def rect(self) -> List[Tuple[int, int], ...]: ... def rect(self) -> List[Tuple[float, float], ...]: ...
@property @property
def viewport_rect(self) -> List[Tuple[int, int], ...]: ... def viewport_rect(self) -> List[Tuple[float, float], ...]: ...
def _get_viewport_rect(self, quad: str) -> Union[list, None]: ... def _get_viewport_rect(self, quad: str) -> Union[list, None]: ...
def _get_page_coord(self, x: int, y: int) -> Tuple[int, int]: ... def _get_page_coord(self, x: float, y: float) -> Tuple[float, float]: ...

View File

@ -190,6 +190,8 @@ class NetworkListener(object):
def _requestWillBeSent(self, **kwargs): def _requestWillBeSent(self, **kwargs):
"""接收到请求时的回调函数""" """接收到请求时的回调函数"""
if kwargs['frameId'] != self._page._frame_id:
return
p = None p = None
if not self._targets: if not self._targets:
if not self._method or kwargs['request']['method'] in self._method: if not self._method or kwargs['request']['method'] in self._method:
@ -220,6 +222,8 @@ class NetworkListener(object):
def _response_received(self, **kwargs): def _response_received(self, **kwargs):
"""接收到返回信息时处理方法""" """接收到返回信息时处理方法"""
if kwargs['frameId'] != self._page._frame_id:
return
request = self._request_ids.get(kwargs['requestId'], None) request = self._request_ids.get(kwargs['requestId'], None)
if request: if request:
request._raw_response = kwargs['response'] request._raw_response = kwargs['response']

View File

@ -6,12 +6,13 @@
from typing import Tuple, Union from typing import Tuple, Union
from .._pages.chromium_page import ChromiumPage from .._pages.chromium_page import ChromiumPage
from .._pages.chromium_tab import ChromiumTab from .._pages.chromium_tab import ChromiumTab, WebPageTab
from .._pages.web_page import WebPage
class TabRect(object): class TabRect(object):
def __init__(self, page: Union[ChromiumPage, ChromiumTab]): def __init__(self, page: Union[ChromiumPage, ChromiumTab, WebPage, WebPageTab]):
self._page: Union[ChromiumPage, ChromiumTab] = ... self._page: Union[ChromiumPage, ChromiumTab, WebPage, WebPageTab] = ...
@property @property
def window_state(self) -> str: ... def window_state(self) -> str: ...

View File

@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh:
setup( setup(
name="DrissionPage", name="DrissionPage",
version="4.0.0b7", version="4.0.0b8",
author="g1879", author="g1879",
author_email="g1879@qq.com", author_email="g1879@qq.com",
description="Python based web automation tool. It can control the browser and send and receive data packets.", description="Python based web automation tool. It can control the browser and send and receive data packets.",