mirror of
https://gitee.com/g1879/DrissionPage.git
synced 2024-12-10 04:00:23 +08:00
元素失效抛出异常提示;ChromiumElement增加get_src()
This commit is contained in:
parent
410839b23f
commit
a480edc325
@ -65,7 +65,7 @@ class ChromiumElement(DrissionElement):
|
|||||||
def tag(self) -> str:
|
def tag(self) -> str:
|
||||||
"""返回元素tag"""
|
"""返回元素tag"""
|
||||||
if self._tag is None:
|
if self._tag is None:
|
||||||
self._tag = self.page.driver.DOM.describeNode(nodeId=self._node_id)['node']['localName'].lower()
|
self._tag = self.page.run_cdp('DOM.describeNode', nodeId=self._node_id)['node']['localName'].lower()
|
||||||
return self._tag
|
return self._tag
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -73,11 +73,11 @@ class ChromiumElement(DrissionElement):
|
|||||||
"""返回元素outerHTML文本"""
|
"""返回元素outerHTML文本"""
|
||||||
tag = self.tag
|
tag = self.tag
|
||||||
if tag in ('iframe', 'frame'):
|
if tag in ('iframe', 'frame'):
|
||||||
out_html = self.page.driver.DOM.getOuterHTML(nodeId=self._node_id)['outerHTML']
|
out_html = self.page.run_cdp('DOM.getOuterHTML', nodeId=self._node_id)['outerHTML']
|
||||||
in_html = self.inner_html
|
in_html = self.inner_html
|
||||||
sign = search(rf'<{tag}.*?>', out_html).group(0)
|
sign = search(rf'<{tag}.*?>', out_html).group(0)
|
||||||
return f'{sign}{in_html}</{tag}>'
|
return f'{sign}{in_html}</{tag}>'
|
||||||
return self.page.driver.DOM.getOuterHTML(nodeId=self._node_id)['outerHTML']
|
return self.page.run_cdp('DOM.getOuterHTML', nodeId=self._node_id)['outerHTML']
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def inner_html(self) -> str:
|
def inner_html(self) -> str:
|
||||||
@ -90,7 +90,7 @@ class ChromiumElement(DrissionElement):
|
|||||||
@property
|
@property
|
||||||
def attrs(self) -> dict:
|
def attrs(self) -> dict:
|
||||||
"""返回元素所有attribute属性"""
|
"""返回元素所有attribute属性"""
|
||||||
attrs = self.page.driver.DOM.getAttributes(nodeId=self._node_id)['attributes']
|
attrs = self.page.run_cdp('DOM.getAttributes', nodeId=self._node_id)['attributes']
|
||||||
attrs_len = len(attrs)
|
attrs_len = len(attrs)
|
||||||
return {attrs[i]: attrs[i + 1] for i in range(0, attrs_len, 2)}
|
return {attrs[i]: attrs[i + 1] for i in range(0, attrs_len, 2)}
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ class ChromiumElement(DrissionElement):
|
|||||||
def size(self) -> dict:
|
def size(self) -> dict:
|
||||||
"""返回元素宽和高"""
|
"""返回元素宽和高"""
|
||||||
try:
|
try:
|
||||||
model = self.page.driver.DOM.getBoxModel(nodeId=self._node_id)['model']
|
model = self.page.run_cdp('DOM.getBoxModel', nodeId=self._node_id)['model']
|
||||||
return {'height': model['height'], 'width': model['width']}
|
return {'height': model['height'], 'width': model['width']}
|
||||||
except Exception:
|
except Exception:
|
||||||
return {'height': 0, 'width': 0}
|
return {'height': 0, 'width': 0}
|
||||||
@ -377,7 +377,7 @@ class ChromiumElement(DrissionElement):
|
|||||||
:param prop: 属性名
|
:param prop: 属性名
|
||||||
:return: 属性值文本
|
:return: 属性值文本
|
||||||
"""
|
"""
|
||||||
p = self.page.driver.Runtime.getProperties(objectId=self._obj_id)['result']
|
p = self.page.run_cdp('Runtime.getProperties', objectId=self._obj_id)['result']
|
||||||
for i in p:
|
for i in p:
|
||||||
if i['name'] == prop:
|
if i['name'] == prop:
|
||||||
if 'value' not in i or 'value' not in i['value']:
|
if 'value' not in i or 'value' not in i['value']:
|
||||||
@ -482,15 +482,12 @@ class ChromiumElement(DrissionElement):
|
|||||||
js = f'return window.getComputedStyle(this{pseudo_ele}).getPropertyValue("{style}");'
|
js = f'return window.getComputedStyle(this{pseudo_ele}).getPropertyValue("{style}");'
|
||||||
return self.run_script(js)
|
return self.run_script(js)
|
||||||
|
|
||||||
def save(self, path: [str, bool] = None, rename: str = None) -> Union[bytes, str, bool]:
|
def get_src(self) -> Union[bytes, str, None]:
|
||||||
"""保存图片或其它有src属性的元素的资源 \n
|
"""返回元素src资源,base64的会转为bytes返回,其它返回str"""
|
||||||
:param path: 文件保存路径,为None时保存到当前文件夹,为False时不保存
|
|
||||||
:param rename: 文件名称,为None时从资源url获取
|
|
||||||
:return: 资源内容文本
|
|
||||||
"""
|
|
||||||
src = self.attr('src')
|
src = self.attr('src')
|
||||||
if not src:
|
if not src:
|
||||||
return False
|
return None
|
||||||
|
|
||||||
if self.tag == 'img': # 等待图片加载完成
|
if self.tag == 'img': # 等待图片加载完成
|
||||||
js = ('return this.complete && typeof this.naturalWidth != "undefined" '
|
js = ('return this.complete && typeof this.naturalWidth != "undefined" '
|
||||||
'&& this.naturalWidth > 0 && typeof this.naturalHeight != "undefined" '
|
'&& this.naturalWidth > 0 && typeof this.naturalHeight != "undefined" '
|
||||||
@ -499,33 +496,41 @@ class ChromiumElement(DrissionElement):
|
|||||||
while not self.run_script(js) and perf_counter() < end_time:
|
while not self.run_script(js) and perf_counter() < end_time:
|
||||||
sleep(.1)
|
sleep(.1)
|
||||||
|
|
||||||
path = path or '.'
|
node = self.page.run_cdp('DOM.describeNode', nodeId=self._node_id)['node']
|
||||||
|
|
||||||
node = self.page.driver.DOM.describeNode(nodeId=self._node_id)['node']
|
|
||||||
frame = node.get('frameId', None)
|
frame = node.get('frameId', None)
|
||||||
frame = frame or self.page.tab_id
|
frame = frame or self.page.tab_id
|
||||||
result = self.page.driver.Page.getResourceContent(frameId=frame, url=src)
|
result = self.page.driver.Page.getResourceContent(frameId=frame, url=src)
|
||||||
if result['base64Encoded']:
|
if result['base64Encoded']:
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
data = b64decode(result['content'])
|
data = b64decode(result['content'])
|
||||||
write_type = 'wb'
|
|
||||||
else:
|
else:
|
||||||
data = result['content']
|
data = result['content']
|
||||||
write_type = 'w'
|
|
||||||
|
|
||||||
if path:
|
|
||||||
rename = rename or basename(src)
|
|
||||||
Path(path).mkdir(parents=True, exist_ok=True)
|
|
||||||
with open(f'{path}{sep}{rename}', write_type) as f:
|
|
||||||
f.write(data)
|
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def save(self, path: [str, bool] = None, rename: str = None) -> None:
|
||||||
|
"""保存图片或其它有src属性的元素的资源 \n
|
||||||
|
:param path: 文件保存路径,为None时保存到当前文件夹,为False时不保存
|
||||||
|
:param rename: 文件名称,为None时从资源url获取
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
src = self.attr('src')
|
||||||
|
if not src:
|
||||||
|
raise TypeError('该元素无可保存的内容。')
|
||||||
|
|
||||||
|
data = self.get_src()
|
||||||
|
path = path or '.'
|
||||||
|
rename = rename or basename(src)
|
||||||
|
write_type = 'wb' if isinstance(data, bytes) else 'w'
|
||||||
|
|
||||||
|
Path(path).mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(f'{path}{sep}{rename}', write_type) as f:
|
||||||
|
f.write(data)
|
||||||
|
|
||||||
def get_screenshot(self, path: [str, Path] = None,
|
def get_screenshot(self, path: [str, Path] = None,
|
||||||
as_bytes: [bool, str] = None) -> Union[str, bytes]:
|
as_bytes: [bool, str] = None) -> Union[str, bytes]:
|
||||||
"""对当前元素截图 \n
|
"""对当前元素截图 \n
|
||||||
:param path: 完整路径,后缀可选'jpg','jpeg','png','webp'
|
:param path: 完整路径,后缀可选 'jpg','jpeg','png','webp'
|
||||||
:param as_bytes: 是否已字节形式返回图片,可选'jpg','jpeg','png','webp',生效时path参数无效
|
:param as_bytes: 是否已字节形式返回图片,可选 'jpg','jpeg','png','webp',生效时path参数无效
|
||||||
:return: 图片完整路径或字节文本
|
:return: 图片完整路径或字节文本
|
||||||
"""
|
"""
|
||||||
if self.tag == 'img': # 等待图片加载完成
|
if self.tag == 'img': # 等待图片加载完成
|
||||||
@ -554,7 +559,7 @@ class ChromiumElement(DrissionElement):
|
|||||||
return self._set_file_input(vals)
|
return self._set_file_input(vals)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.page.driver.DOM.focus(nodeId=self._node_id)
|
self.page.run_cdp('DOM.focus', nodeId=self._node_id)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.click(by_js=True)
|
self.click(by_js=True)
|
||||||
|
|
||||||
@ -572,10 +577,10 @@ class ChromiumElement(DrissionElement):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if vals.endswith('\n'):
|
if vals.endswith('\n'):
|
||||||
self.page.run_cdp('Input.insertText', text=vals[:-1])
|
self.page.driver.Input.insertText(text=vals[:-1])
|
||||||
_send_key(self, modifier, '\n')
|
_send_key(self, modifier, '\n')
|
||||||
else:
|
else:
|
||||||
self.page.run_cdp('Input.insertText', text=vals)
|
self.page.driver.Input.insertText(text=vals)
|
||||||
|
|
||||||
def _set_file_input(self, files: Union[str, list, tuple]) -> None:
|
def _set_file_input(self, files: Union[str, list, tuple]) -> None:
|
||||||
"""设置上传控件值
|
"""设置上传控件值
|
||||||
@ -584,7 +589,7 @@ class ChromiumElement(DrissionElement):
|
|||||||
"""
|
"""
|
||||||
if isinstance(files, str):
|
if isinstance(files, str):
|
||||||
files = files.split('\n')
|
files = files.split('\n')
|
||||||
self.page.driver.DOM.setFileInputFiles(files=files, nodeId=self._node_id)
|
self.page.run_cdp('DOM.setFileInputFiles', files=files, nodeId=self._node_id)
|
||||||
|
|
||||||
def clear(self, by_js: bool = False) -> None:
|
def clear(self, by_js: bool = False) -> None:
|
||||||
"""清空元素文本 \n
|
"""清空元素文本 \n
|
||||||
@ -759,14 +764,14 @@ class ChromiumElement(DrissionElement):
|
|||||||
:param node_id: cdp中的node id
|
:param node_id: cdp中的node id
|
||||||
:return: js中的object id
|
:return: js中的object id
|
||||||
"""
|
"""
|
||||||
return self.page.driver.DOM.resolveNode(nodeId=node_id)['object']['objectId']
|
return self.page.run_cdp('DOM.resolveNode', nodeId=node_id)['object']['objectId']
|
||||||
|
|
||||||
def _get_node_id(self, obj_id) -> str:
|
def _get_node_id(self, obj_id) -> str:
|
||||||
"""根据传入object id获取cdp中的node id \n
|
"""根据传入object id获取cdp中的node id \n
|
||||||
:param obj_id: js中的object id
|
:param obj_id: js中的object id
|
||||||
:return: cdp中的node id
|
:return: cdp中的node id
|
||||||
"""
|
"""
|
||||||
return self.page.driver.DOM.requestNode(objectId=obj_id)['nodeId']
|
return self.page.run_cdp('DOM.requestNode', objectId=obj_id)['nodeId']
|
||||||
|
|
||||||
def _get_ele_path(self, mode) -> str:
|
def _get_ele_path(self, mode) -> str:
|
||||||
"""返获取css路径或xpath路径"""
|
"""返获取css路径或xpath路径"""
|
||||||
@ -860,7 +865,7 @@ class ChromiumShadowRootElement(BaseElement):
|
|||||||
def is_alive(self) -> bool:
|
def is_alive(self) -> bool:
|
||||||
"""返回元素是否仍在DOM中"""
|
"""返回元素是否仍在DOM中"""
|
||||||
try:
|
try:
|
||||||
self.page.driver.DOM.describeNode(nodeId=self._node_id)
|
self.page.run_cdp('DOM.describeNode', nodeId=self._node_id)
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
@ -1057,20 +1062,20 @@ class ChromiumShadowRootElement(BaseElement):
|
|||||||
|
|
||||||
css_paths = [i.css_path[47:] for i in eles]
|
css_paths = [i.css_path[47:] for i in eles]
|
||||||
if single:
|
if single:
|
||||||
node_id = self.page.driver.DOM.querySelector(nodeId=self._node_id, selector=css_paths[0])['nodeId']
|
node_id = self.page.run_cdp('DOM.querySelector', nodeId=self._node_id, selector=css_paths[0])['nodeId']
|
||||||
return ChromiumElement(self.page, node_id) if node_id else None
|
return ChromiumElement(self.page, node_id) if node_id else None
|
||||||
|
|
||||||
else:
|
else:
|
||||||
results = []
|
results = []
|
||||||
for i in css_paths:
|
for i in css_paths:
|
||||||
node_id = self.page.driver.DOM.querySelector(nodeId=self._node_id, selector=i)['nodeId']
|
node_id = self.page.run_cdp('DOM.querySelector', nodeId=self._node_id, selector=i)['nodeId']
|
||||||
if node_id:
|
if node_id:
|
||||||
results.append(ChromiumElement(self.page, node_id))
|
results.append(ChromiumElement(self.page, node_id))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def _get_node_id(self, obj_id) -> str:
|
def _get_node_id(self, obj_id) -> str:
|
||||||
"""返回元素node id"""
|
"""返回元素node id"""
|
||||||
return self.page.driver.DOM.requestNode(objectId=obj_id)['nodeId']
|
return self.page.run_cdp('DOM.requestNode', objectId=obj_id)['nodeId']
|
||||||
|
|
||||||
|
|
||||||
class ChromiumBase(BasePage):
|
class ChromiumBase(BasePage):
|
||||||
@ -1492,7 +1497,12 @@ class ChromiumBase(BasePage):
|
|||||||
:param cmd_args: 参数
|
:param cmd_args: 参数
|
||||||
:return: 执行的结果
|
:return: 执行的结果
|
||||||
"""
|
"""
|
||||||
return self._driver.call_method(cmd, **cmd_args)
|
try:
|
||||||
|
return self._driver.call_method(cmd, **cmd_args)
|
||||||
|
except Exception as e:
|
||||||
|
if 'Could not find node with given id' in str(e):
|
||||||
|
raise RuntimeError('该元素已不在当前页面中。')
|
||||||
|
raise
|
||||||
|
|
||||||
def set_user_agent(self, ua: str) -> None:
|
def set_user_agent(self, ua: str) -> None:
|
||||||
"""为当前tab设置user agent,只在当前tab有效 \n
|
"""为当前tab设置user agent,只在当前tab有效 \n
|
||||||
@ -1623,7 +1633,7 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
def html(self) -> str:
|
def html(self) -> str:
|
||||||
"""返回元素outerHTML文本"""
|
"""返回元素outerHTML文本"""
|
||||||
tag = self.tag
|
tag = self.tag
|
||||||
out_html = self.page.driver.DOM.getOuterHTML(nodeId=self._inner_ele.node_id)['outerHTML']
|
out_html = self.page.run_cdp('DOM.getOuterHTML', nodeId=self._inner_ele.node_id)['outerHTML']
|
||||||
in_html = super().html
|
in_html = super().html
|
||||||
sign = search(rf'<{tag}.*?>', out_html).group(0)
|
sign = search(rf'<{tag}.*?>', out_html).group(0)
|
||||||
return f'{sign}{in_html}</{tag}>'
|
return f'{sign}{in_html}</{tag}>'
|
||||||
@ -2067,15 +2077,15 @@ def _send_enter(ele: ChromiumElement) -> None:
|
|||||||
data = {'type': 'keyDown', 'modifiers': 0, 'windowsVirtualKeyCode': 13, 'code': 'Enter', 'key': 'Enter',
|
data = {'type': 'keyDown', 'modifiers': 0, 'windowsVirtualKeyCode': 13, 'code': 'Enter', 'key': 'Enter',
|
||||||
'text': '\r', 'autoRepeat': False, 'unmodifiedText': '\r', 'location': 0, 'isKeypad': False}
|
'text': '\r', 'autoRepeat': False, 'unmodifiedText': '\r', 'location': 0, 'isKeypad': False}
|
||||||
|
|
||||||
ele.page.run_cdp('Input.dispatchKeyEvent', **data)
|
ele.page.driver.Input.dispatchKeyEvent(**data)
|
||||||
data['type'] = 'keyUp'
|
data['type'] = 'keyUp'
|
||||||
ele.page.run_cdp('Input.dispatchKeyEvent', **data)
|
ele.page.driver.Input.dispatchKeyEvent(**data)
|
||||||
|
|
||||||
|
|
||||||
def _send_key(ele: ChromiumElement, modifier: int, key: str) -> None:
|
def _send_key(ele: ChromiumElement, modifier: int, key: str) -> None:
|
||||||
"""发送一个字,在键盘中的字符触发按键,其它直接发送文本"""
|
"""发送一个字,在键盘中的字符触发按键,其它直接发送文本"""
|
||||||
if key not in _keyDefinitions:
|
if key not in _keyDefinitions:
|
||||||
ele.page.run_cdp('Input.insertText', text=key)
|
ele.page.driver.Input.insertText(text=key)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
description = _keyDescriptionForString(modifier, key)
|
description = _keyDescriptionForString(modifier, key)
|
||||||
@ -2091,9 +2101,9 @@ def _send_key(ele: ChromiumElement, modifier: int, key: str) -> None:
|
|||||||
'location': description['location'],
|
'location': description['location'],
|
||||||
'isKeypad': description['location'] == 3}
|
'isKeypad': description['location'] == 3}
|
||||||
|
|
||||||
ele.page.run_cdp('Input.dispatchKeyEvent', **data)
|
ele.page.driver.Input.dispatchKeyEvent(**data)
|
||||||
data['type'] = 'keyUp'
|
data['type'] = 'keyUp'
|
||||||
ele.page.run_cdp('Input.dispatchKeyEvent', **data)
|
ele.page.driver.Input.dispatchKeyEvent(**data)
|
||||||
|
|
||||||
|
|
||||||
def _offset_scroll(ele: ChromiumElement, offset_x: int, offset_y: int) -> tuple:
|
def _offset_scroll(ele: ChromiumElement, offset_x: int, offset_y: int) -> tuple:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user