解决新加载的iframe点击问题;对无位置和大小信息的元素进行处理

This commit is contained in:
g1879 2023-02-17 19:52:37 +08:00
parent e8b22de2e3
commit 5dce3077ed
4 changed files with 40 additions and 32 deletions

View File

@ -15,7 +15,8 @@ from .chromium_driver import ChromiumDriver
from .chromium_element import ChromiumWaiter, ChromiumScroll, ChromiumElement, run_js, make_chromium_ele, \
ChromiumElementWaiter
from .common.constants import HANDLE_ALERT_METHOD, ERROR, NoneElement
from .common.errors import ContextLossError, ElementLossError, AlertExistsError, CallMethodError, TabClosedError
from .common.errors import ContextLossError, ElementLossError, AlertExistsError, CallMethodError, TabClosedError, \
NoRectError
from .common.locator import get_loc
from .common.tools import get_usable_path
from .common.web import offset_scroll, cookies_to_tuple
@ -346,6 +347,8 @@ class ChromiumBase(BasePage):
raise TabClosedError
elif r[ERROR] == 'alert exists':
pass
elif r[ERROR] in ('Node does not have a layout object', 'Could not compute box model.'):
raise NoRectError
elif r['type'] == 'call_method_error':
raise CallMethodError(f'\n错误:{r["error"]}\nmethod{r["method"]}\nargs{r["args"]}')
else:
@ -924,7 +927,7 @@ class ChromiumPageScroll(ChromiumScroll):
"""
ele = self._driver.ele(loc_or_ele)
try:
self._driver.run_cdp('DOM.scrollIntoViewIfNeeded', nodeId=ele.node_id)
self._driver.run_cdp('DOM.scrollIntoViewIfNeeded', nodeId=ele.ids.node_id)
except Exception:
ele.run_js("this.scrollIntoView();")

View File

@ -11,7 +11,7 @@ from warnings import warn
from .base import DrissionElement, BaseElement
from .common.constants import FRAME_ELEMENT, NoneElement
from .common.errors import ContextLossError, ElementLossError, JavaScriptError
from .common.errors import ContextLossError, ElementLossError, JavaScriptError, NoRectError
from .common.locator import get_loc
from .common.web import make_absolute_link, get_ele_txt, format_html, is_js_func, location_in_viewport, offset_scroll
from .keys import _keys_to_typing, _keyDescriptionForString, _keyDefinitions
@ -1515,37 +1515,37 @@ class Locations(object):
def location(self):
"""返回元素左上角的绝对坐标"""
cl = self.viewport_location
return self._get_page_coord(cl[0], cl[1]) if cl else (0, 0)
return self._get_page_coord(cl[0], cl[1])
@property
def midpoint(self):
"""返回元素中间点的绝对坐标"""
cl = self.viewport_midpoint
return self._get_page_coord(cl[0], cl[1]) if cl else (0, 0)
return self._get_page_coord(cl[0], cl[1])
@property
def click_point(self):
"""返回元素接受点击的点的绝对坐标"""
cl = self.viewport_click_point
return self._get_page_coord(cl[0], cl[1]) if cl else (0, 0)
return self._get_page_coord(cl[0], cl[1])
@property
def viewport_location(self):
"""返回元素左上角在视口中的坐标"""
m = self._get_viewport_rect('border')
return (int(m[0]), int(m[1])) if m else (0, 0)
return int(m[0]), int(m[1])
@property
def viewport_midpoint(self):
"""返回元素中间点在视口中的坐标"""
m = self._get_viewport_rect('border')
return (int(m[0] + (m[2] - m[0]) // 2), int(m[3] + (m[5] - m[3]) // 2)) if m else (0, 0)
return int(m[0] + (m[2] - m[0]) // 2), int(m[3] + (m[5] - m[3]) // 2)
@property
def viewport_click_point(self):
"""返回元素接受点击的点视口坐标"""
m = self._get_viewport_rect('padding')
return (int(self.viewport_midpoint[0]), int(m[1]) + 1) if m else (0, 0)
return int(self.viewport_midpoint[0]), int(m[1]) + 1
@property
def screen_location(self):
@ -1573,10 +1573,7 @@ class Locations(object):
:param quad: 方框类型margin border padding
:return: 四个角坐标大小为0时返回None
"""
try:
return self._ele.page.run_cdp('DOM.getBoxModel', nodeId=self._ele.ids.node_id)['model'][quad]
except Exception:
return None
return self._ele.page.run_cdp('DOM.getBoxModel', nodeId=self._ele.ids.node_id)['model'][quad]
def _get_page_coord(self, x, y):
"""根据绝对坐标获取窗口坐标"""
@ -1628,25 +1625,29 @@ class Click(object):
return True
if not by_js:
self._ele.page.scroll.to_see(self._ele)
if self._ele.states.is_in_viewport:
client_x, client_y = self._ele.locations.viewport_click_point
if client_x:
loc_x, loc_y = self._ele.locations.click_point
try:
self._ele.page.scroll.to_see(self._ele)
if self._ele.states.is_in_viewport:
client_x, client_y = self._ele.locations.viewport_click_point
if client_x:
loc_x, loc_y = self._ele.locations.click_point
click = do_it(client_x, client_y, loc_x, loc_y)
if click:
self._ele.page.wait.load_start(wait_loading)
return True
timeout = timeout if timeout is not None else self._ele.page.timeout
end_time = perf_counter() + timeout
while click is False and perf_counter() < end_time:
click = do_it(client_x, client_y, loc_x, loc_y)
if click:
self._ele.page.wait.load_start(wait_loading)
return True
if click is not None:
self._ele.page.wait.load_start(wait_loading)
return True
timeout = timeout if timeout is not None else self._ele.page.timeout
end_time = perf_counter() + timeout
while click is False and perf_counter() < end_time:
click = do_it(client_x, client_y, loc_x, loc_y)
if click is not None:
self._ele.page.wait.load_start(wait_loading)
return True
except NoRectError:
by_js = True
if by_js is not False:
self._ele.run_js('this.click();')

View File

@ -84,7 +84,7 @@ class ChromiumFrame(ChromiumBase):
self._reload()
try:
self.run_cdp('DOM.describeNode', nodeId=self.ids.node_id)
self.page.run_cdp('DOM.describeNode', nodeId=self.ids.node_id)
except Exception:
self._reload()
# sleep(2)
@ -291,7 +291,7 @@ class ChromiumFrame(ChromiumBase):
:return: 运行的结果
"""
self._check_ok()
return self.doc_ele.run_js(script, as_expr=as_expr, *args)
return self.doc_ele.run_js(script, *args, as_expr=as_expr)
def parent(self, level_or_loc=1):
"""返回上面某一级父元素,可指定层数或用查询语法定位
@ -531,7 +531,7 @@ class ChromiumFrameScroll(ChromiumPageScroll):
"""
ele = loc_or_ele if isinstance(loc_or_ele, ChromiumElement) else self._driver.ele(loc_or_ele)
try:
self._driver.page.run_cdp('DOM.scrollIntoViewIfNeeded', nodeId=ele.node_id)
self._driver.page.run_cdp('DOM.scrollIntoViewIfNeeded', nodeId=ele.ids.node_id)
except Exception:
ele.run_js("this.scrollIntoView();")

View File

@ -38,3 +38,7 @@ class NotElementFoundError(BaseError):
class JavaScriptError(BaseError):
_info = 'JavaScript运行错误。'
class NoRectError(BaseError):
_info = '该元素没有位置及大小。'