mirror of
https://gitee.com/g1879/DrissionPage.git
synced 2024-12-10 04:00:23 +08:00
对iframe逻辑进行完全重构
This commit is contained in:
parent
a6037e960e
commit
146e527494
@ -97,6 +97,7 @@ class ChromiumDriver(object):
|
|||||||
def _recv_loop(self):
|
def _recv_loop(self):
|
||||||
"""接收浏览器信息的守护线程方法"""
|
"""接收浏览器信息的守护线程方法"""
|
||||||
while not self._stopped.is_set():
|
while not self._stopped.is_set():
|
||||||
|
print('收')
|
||||||
try:
|
try:
|
||||||
# self._ws.settimeout(1)
|
# self._ws.settimeout(1)
|
||||||
msg_json = self._ws.recv()
|
msg_json = self._ws.recv()
|
||||||
@ -110,7 +111,7 @@ class ChromiumDriver(object):
|
|||||||
if self._debug:
|
if self._debug:
|
||||||
if self._debug is True or 'id' in msg or (isinstance(self._debug, str)
|
if self._debug is True or 'id' in msg or (isinstance(self._debug, str)
|
||||||
and msg.get('method', '').startswith(self._debug)):
|
and msg.get('method', '').startswith(self._debug)):
|
||||||
print(f'<收 {msg_json}')
|
print(f'<收 {self.id} {msg_json}')
|
||||||
elif isinstance(self._debug, (list, tuple, set)):
|
elif isinstance(self._debug, (list, tuple, set)):
|
||||||
for m in self._debug:
|
for m in self._debug:
|
||||||
if msg.get('method', '').startswith(m):
|
if msg.get('method', '').startswith(m):
|
||||||
@ -139,11 +140,11 @@ class ChromiumDriver(object):
|
|||||||
|
|
||||||
function = self.event_handlers.get(event['method'])
|
function = self.event_handlers.get(event['method'])
|
||||||
if function:
|
if function:
|
||||||
# if self._debug:
|
if self._debug:
|
||||||
# print(f'开始执行 {function.__name__}')
|
print(f'开始执行 {function.__name__}')
|
||||||
function(**event['params'])
|
function(**event['params'])
|
||||||
# if self._debug:
|
if self._debug:
|
||||||
# print(f'执行 {function.__name__}完毕')
|
print(f'执行 {function.__name__}完毕')
|
||||||
|
|
||||||
self.event_queue.task_done()
|
self.event_queue.task_done()
|
||||||
|
|
||||||
@ -186,6 +187,20 @@ class ChromiumDriver(object):
|
|||||||
if self._ws:
|
if self._ws:
|
||||||
self._ws.close()
|
self._ws.close()
|
||||||
self._ws = None
|
self._ws = None
|
||||||
|
|
||||||
|
while not self.event_queue.empty():
|
||||||
|
event = self.event_queue.get_nowait()
|
||||||
|
function = self.event_handlers.get(event['method'])
|
||||||
|
if function:
|
||||||
|
if self._debug:
|
||||||
|
print(f'开始执行 {function.__name__}')
|
||||||
|
try:
|
||||||
|
function(**event['params'])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if self._debug:
|
||||||
|
print(f'执行 {function.__name__}完毕')
|
||||||
|
|
||||||
self.event_handlers.clear()
|
self.event_handlers.clear()
|
||||||
self.method_results.clear()
|
self.method_results.clear()
|
||||||
self.event_queue.queue.clear()
|
self.event_queue.queue.clear()
|
||||||
|
@ -46,6 +46,8 @@ class ChromiumBase(BasePage):
|
|||||||
self._listener = None
|
self._listener = None
|
||||||
self._has_alert = False
|
self._has_alert = False
|
||||||
self._ready_state = None
|
self._ready_state = None
|
||||||
|
if self._debug:
|
||||||
|
print('在__init__变成None')
|
||||||
self._doc_got = False # 用于在LoadEventFired和FrameStoppedLoading间标记是否已获取doc
|
self._doc_got = False # 用于在LoadEventFired和FrameStoppedLoading间标记是否已获取doc
|
||||||
|
|
||||||
self._download_path = str(Path('.').absolute())
|
self._download_path = str(Path('.').absolute())
|
||||||
@ -88,6 +90,8 @@ class ChromiumBase(BasePage):
|
|||||||
if self.ready_state == 'complete' and self._ready_state is None:
|
if self.ready_state == 'complete' and self._ready_state is None:
|
||||||
self._get_document()
|
self._get_document()
|
||||||
self._ready_state = 'complete'
|
self._ready_state = 'complete'
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}在connect_browser变成complete')
|
||||||
|
|
||||||
def _driver_init(self, tab_id):
|
def _driver_init(self, tab_id):
|
||||||
"""新建页面、页面刷新、切换标签页后要进行的cdp参数初始化
|
"""新建页面、页面刷新、切换标签页后要进行的cdp参数初始化
|
||||||
@ -107,7 +111,8 @@ class ChromiumBase(BasePage):
|
|||||||
r = self.run_cdp('Page.getFrameTree')
|
r = self.run_cdp('Page.getFrameTree')
|
||||||
for i in findall(r"'id': '(.*?)'", str(r)):
|
for i in findall(r"'id': '(.*?)'", str(r)):
|
||||||
self.browser._frames[i] = self.tab_id
|
self.browser._frames[i] = self.tab_id
|
||||||
self._frame_id = r['frameTree']['frame']['id']
|
if not hasattr(self, '_frame_id'):
|
||||||
|
self._frame_id = r['frameTree']['frame']['id']
|
||||||
|
|
||||||
self._driver.set_listener('Page.frameStartedLoading', self._onFrameStartedLoading)
|
self._driver.set_listener('Page.frameStartedLoading', self._onFrameStartedLoading)
|
||||||
self._driver.set_listener('Page.frameNavigated', self._onFrameNavigated)
|
self._driver.set_listener('Page.frameNavigated', self._onFrameNavigated)
|
||||||
@ -149,6 +154,10 @@ class ChromiumBase(BasePage):
|
|||||||
"""页面开始加载时执行"""
|
"""页面开始加载时执行"""
|
||||||
self.browser._frames[kwargs['frameId']] = self.tab_id
|
self.browser._frames[kwargs['frameId']] = self.tab_id
|
||||||
if kwargs['frameId'] == self._frame_id:
|
if kwargs['frameId'] == self._frame_id:
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}触发FrameStartedLoading')
|
||||||
|
print('在FrameStartedLoading变成loading')
|
||||||
|
|
||||||
self._doc_got = False
|
self._doc_got = False
|
||||||
self._ready_state = 'loading'
|
self._ready_state = 'loading'
|
||||||
self._is_loading = True
|
self._is_loading = True
|
||||||
@ -156,43 +165,64 @@ class ChromiumBase(BasePage):
|
|||||||
t = Thread(target=self._wait_to_stop)
|
t = Thread(target=self._wait_to_stop)
|
||||||
t.daemon = True
|
t.daemon = True
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
if self._debug:
|
if self._debug:
|
||||||
print(f'frameStartedLoading {kwargs}')
|
print(f'{self._frame_id}执行FrameStartedLoading完毕')
|
||||||
|
|
||||||
def _onFrameNavigated(self, **kwargs):
|
def _onFrameNavigated(self, **kwargs):
|
||||||
"""页面跳转时执行"""
|
"""页面跳转时执行"""
|
||||||
if kwargs['frame']['id'] == self._frame_id:
|
if kwargs['frame']['id'] == self._frame_id:
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}触发FrameNavigated')
|
||||||
|
print('在FrameNavigated变成loading')
|
||||||
|
|
||||||
self._doc_got = False
|
self._doc_got = False
|
||||||
self._ready_state = 'loading'
|
self._ready_state = 'loading'
|
||||||
self._is_loading = True
|
self._is_loading = True
|
||||||
|
|
||||||
if self._debug:
|
if self._debug:
|
||||||
print(f'FrameNavigated {kwargs}')
|
print(f'>>> FrameNavigated {kwargs}')
|
||||||
|
|
||||||
def _onDomContentEventFired(self, **kwargs):
|
def _onDomContentEventFired(self, **kwargs):
|
||||||
"""在页面刷新、变化后重新读取页面内容"""
|
"""在页面刷新、变化后重新读取页面内容"""
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}触发DomContentEventFired')
|
||||||
|
print('在DomContentEventFired变成interactive')
|
||||||
|
|
||||||
self._ready_state = 'interactive'
|
self._ready_state = 'interactive'
|
||||||
if self.page_load_strategy == 'eager':
|
if self.page_load_strategy == 'eager':
|
||||||
self.run_cdp('Page.stopLoading')
|
self.run_cdp('Page.stopLoading')
|
||||||
|
|
||||||
if self._debug:
|
if self._debug:
|
||||||
print(f'DomContentEventFired {kwargs}')
|
print(f'{self._frame_id}执行DomContentEventFired完毕')
|
||||||
|
|
||||||
def _onLoadEventFired(self, **kwargs):
|
def _onLoadEventFired(self, **kwargs):
|
||||||
"""在页面刷新、变化后重新读取页面内容"""
|
"""在页面刷新、变化后重新读取页面内容"""
|
||||||
self._ready_state = 'complete'
|
|
||||||
if self._debug:
|
if self._debug:
|
||||||
print(f'LoadEventFired {kwargs}')
|
print(f'{self._frame_id}触发LoadEventFired')
|
||||||
|
print('在LoadEventFired变成complete')
|
||||||
|
|
||||||
|
self._ready_state = 'complete'
|
||||||
self._get_document()
|
self._get_document()
|
||||||
self._doc_got = True
|
self._doc_got = True
|
||||||
|
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}执行LoadEventFired完毕')
|
||||||
|
|
||||||
def _onFrameStoppedLoading(self, **kwargs):
|
def _onFrameStoppedLoading(self, **kwargs):
|
||||||
"""页面加载完成后执行"""
|
"""页面加载完成后执行"""
|
||||||
self.browser._frames[kwargs['frameId']] = self.tab_id
|
self.browser._frames[kwargs['frameId']] = self.tab_id
|
||||||
if kwargs['frameId'] == self._frame_id and self._doc_got is False:
|
if kwargs['frameId'] == self._frame_id and self._doc_got is False:
|
||||||
self._ready_state = 'complete'
|
|
||||||
if self._debug:
|
if self._debug:
|
||||||
print(f'FrameStoppedLoading {kwargs}')
|
print(f'{self._frame_id}触发FrameStoppedLoading')
|
||||||
|
print('在FrameStoppedLoading变成complete')
|
||||||
|
|
||||||
|
self._ready_state = 'complete'
|
||||||
self._get_document()
|
self._get_document()
|
||||||
|
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}执行FrameStoppedLoading完毕')
|
||||||
|
|
||||||
def _onFileChooserOpened(self, **kwargs):
|
def _onFileChooserOpened(self, **kwargs):
|
||||||
"""文件选择框打开时执行"""
|
"""文件选择框打开时执行"""
|
||||||
if self._upload_list:
|
if self._upload_list:
|
||||||
@ -836,7 +866,10 @@ class ChromiumBase(BasePage):
|
|||||||
|
|
||||||
sleep(.1)
|
sleep(.1)
|
||||||
|
|
||||||
self.stop_loading()
|
try:
|
||||||
|
self.stop_loading()
|
||||||
|
except CDPError:
|
||||||
|
pass
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _d_connect(self, to_url, times=0, interval=1, show_errmsg=False, timeout=None):
|
def _d_connect(self, to_url, times=0, interval=1, show_errmsg=False, timeout=None):
|
||||||
@ -854,7 +887,7 @@ class ChromiumBase(BasePage):
|
|||||||
err = None
|
err = None
|
||||||
end_time = perf_counter() + timeout
|
end_time = perf_counter() + timeout
|
||||||
try:
|
try:
|
||||||
result = self.run_cdp('Page.navigate', url=to_url, _timeout=timeout)
|
result = self.run_cdp('Page.navigate', frameId=self._frame_id, url=to_url, _timeout=timeout)
|
||||||
if 'errorText' in result:
|
if 'errorText' in result:
|
||||||
err = ConnectionError(result['errorText'])
|
err = ConnectionError(result['errorText'])
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
@ -877,7 +910,6 @@ class ChromiumBase(BasePage):
|
|||||||
sleep(interval)
|
sleep(interval)
|
||||||
if self._debug or show_errmsg:
|
if self._debug or show_errmsg:
|
||||||
print(f'重试{t + 1} {to_url}')
|
print(f'重试{t + 1} {to_url}')
|
||||||
self.stop_loading()
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not err:
|
if not err:
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
"""
|
"""
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from re import search, findall
|
from re import search, findall
|
||||||
from threading import Thread
|
|
||||||
from time import sleep, perf_counter
|
from time import sleep, perf_counter
|
||||||
|
|
||||||
from .._elements.chromium_element import ChromiumElement
|
from .._elements.chromium_element import ChromiumElement
|
||||||
@ -35,21 +34,22 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
|
|
||||||
self.address = page.address
|
self.address = page.address
|
||||||
node = page.run_cdp('DOM.describeNode', backendNodeId=ele.ids.backend_id)['node']
|
node = page.run_cdp('DOM.describeNode', backendNodeId=ele.ids.backend_id)['node']
|
||||||
self.frame_id = node['frameId']
|
|
||||||
self._tab_id = page.tab_id
|
self._tab_id = page.tab_id
|
||||||
self._backend_id = ele.ids.backend_id
|
self._backend_id = ele.ids.backend_id
|
||||||
self._frame_ele = ele
|
self._frame_ele = ele
|
||||||
self._states = None
|
self._states = None
|
||||||
self._ids = FrameIds(self)
|
self._ids = FrameIds(self)
|
||||||
|
self._is_init_get_doc = True
|
||||||
|
|
||||||
|
self._frame_id = node['frameId']
|
||||||
if self._is_inner_frame():
|
if self._is_inner_frame():
|
||||||
self._is_diff_domain = False
|
self._is_diff_domain = False
|
||||||
self.doc_ele = ChromiumElement(self._target_page, backend_id=node['contentDocument']['backendNodeId'])
|
self.doc_ele = ChromiumElement(self._target_page, backend_id=node['contentDocument']['backendNodeId'])
|
||||||
super().__init__(page.address, page.tab_id, page.timeout)
|
super().__init__(page.address, page.tab_id, page.timeout)
|
||||||
self._frame_id = self.frame_id
|
|
||||||
else:
|
else:
|
||||||
self._is_diff_domain = True
|
self._is_diff_domain = True
|
||||||
super().__init__(page.address, self.frame_id, page.timeout)
|
delattr(self, '_frame_id')
|
||||||
|
super().__init__(page.address, node['frameId'], page.timeout)
|
||||||
obj_id = super().run_js('document;', as_expr=True)['objectId']
|
obj_id = super().run_js('document;', as_expr=True)['objectId']
|
||||||
self.doc_ele = ChromiumElement(self, obj_id=obj_id)
|
self.doc_ele = ChromiumElement(self, obj_id=obj_id)
|
||||||
|
|
||||||
@ -57,10 +57,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
while perf_counter() < end_time and self.url == 'about:blank':
|
while perf_counter() < end_time and self.url == 'about:blank':
|
||||||
sleep(.1)
|
sleep(.1)
|
||||||
|
|
||||||
t = Thread(target=self._check_alive)
|
|
||||||
t.daemon = True
|
|
||||||
t.start()
|
|
||||||
|
|
||||||
def __call__(self, loc_or_str, timeout=None):
|
def __call__(self, loc_or_str, timeout=None):
|
||||||
"""在内部查找元素
|
"""在内部查找元素
|
||||||
例:ele2 = ele1('@id=ele_id')
|
例:ele2 = ele1('@id=ele_id')
|
||||||
@ -77,11 +73,12 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
|
|
||||||
def _d_set_runtime_settings(self):
|
def _d_set_runtime_settings(self):
|
||||||
"""重写设置浏览器运行参数方法"""
|
"""重写设置浏览器运行参数方法"""
|
||||||
self._timeouts = copy(self._target_page.timeouts)
|
if not hasattr(self, '_timeouts'):
|
||||||
self.retry_times = self._target_page.retry_times
|
self._timeouts = copy(self._target_page.timeouts)
|
||||||
self.retry_interval = self._target_page.retry_interval
|
self.retry_times = self._target_page.retry_times
|
||||||
self._page_load_strategy = self._target_page.page_load_strategy
|
self.retry_interval = self._target_page.retry_interval
|
||||||
self._download_path = self._target_page.download_path
|
self._page_load_strategy = self._target_page.page_load_strategy if not self._is_diff_domain else 'normal'
|
||||||
|
self._download_path = self._target_page.download_path
|
||||||
|
|
||||||
def _driver_init(self, tab_id, is_init=True):
|
def _driver_init(self, tab_id, is_init=True):
|
||||||
"""避免出现服务器500错误
|
"""避免出现服务器500错误
|
||||||
@ -93,65 +90,90 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
except:
|
except:
|
||||||
self.browser.driver.get(f'http://{self.address}/json')
|
self.browser.driver.get(f'http://{self.address}/json')
|
||||||
super()._driver_init(tab_id)
|
super()._driver_init(tab_id)
|
||||||
self.driver.set_listener('Inspector.detached', self._onInspectorDetached)
|
self._driver.set_listener('Inspector.detached', self._onInspectorDetached)
|
||||||
|
|
||||||
def _reload(self):
|
def _reload(self):
|
||||||
"""重新获取document"""
|
"""重新获取document"""
|
||||||
|
self._is_loading = True
|
||||||
debug = self._debug
|
debug = self._debug
|
||||||
d_debug = self.driver._debug
|
d_debug = self.driver._debug
|
||||||
old_driver = self.driver
|
self._is_init_get_doc = False
|
||||||
|
self._doc_got = False
|
||||||
if debug:
|
if debug:
|
||||||
print('重新获取document')
|
print(f'{self._frame_id} reload 开始')
|
||||||
|
|
||||||
self._frame_ele = ChromiumElement(self._target_page, backend_id=self._backend_id)
|
try:
|
||||||
node = self._target_page.run_cdp('DOM.describeNode', backendNodeId=self._frame_ele.ids.backend_id)['node']
|
self._frame_ele = ChromiumElement(self._target_page, backend_id=self._backend_id)
|
||||||
|
except ElementLossError:
|
||||||
|
return
|
||||||
|
node = self._target_page.run_cdp('DOM.describeNode',
|
||||||
|
backendNodeId=self._frame_ele.ids.backend_id)['node']
|
||||||
|
|
||||||
end_time = perf_counter() + self.timeout
|
self._driver.stop()
|
||||||
while perf_counter() < end_time:
|
|
||||||
try:
|
if self._is_inner_frame():
|
||||||
if self._is_inner_frame():
|
self._is_diff_domain = False
|
||||||
self._is_diff_domain = False
|
self.doc_ele = ChromiumElement(self._target_page,
|
||||||
self.doc_ele = ChromiumElement(self._target_page,
|
backend_id=node['contentDocument']['backendNodeId'])
|
||||||
backend_id=node['contentDocument']['backendNodeId'])
|
self._frame_id = node['frameId']
|
||||||
super().__init__(self.address, self._target_page.tab_id, self._target_page.timeout)
|
super().__init__(self.address, self._target_page.tab_id, self._target_page.timeout)
|
||||||
self._frame_id = self.frame_id
|
self._debug = debug
|
||||||
self._debug = debug
|
self.driver._debug = d_debug
|
||||||
self.driver._debug = d_debug
|
|
||||||
else:
|
else:
|
||||||
self._is_diff_domain = True
|
self._is_diff_domain = True
|
||||||
self._driver.stop()
|
super().__init__(self.address, node['frameId'], self._target_page.timeout)
|
||||||
super().__init__(self.address, self.frame_id, self._target_page.timeout)
|
end_time = perf_counter() + self.timeouts.page_load
|
||||||
|
while perf_counter() < end_time:
|
||||||
|
try:
|
||||||
obj_id = super().run_js('document;', as_expr=True)['objectId']
|
obj_id = super().run_js('document;', as_expr=True)['objectId']
|
||||||
self.doc_ele = ChromiumElement(self, obj_id=obj_id)
|
self.doc_ele = ChromiumElement(self, obj_id=obj_id)
|
||||||
self._debug = debug
|
break
|
||||||
self.driver._debug = d_debug
|
except Exception as e:
|
||||||
|
sleep(.1)
|
||||||
|
if self._debug:
|
||||||
|
print(f'获取doc失败,重试 {e}')
|
||||||
|
else:
|
||||||
|
raise GetDocumentError
|
||||||
|
self._debug = debug
|
||||||
|
self.driver._debug = d_debug
|
||||||
|
|
||||||
|
self._is_loading = False
|
||||||
|
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id} reload 完毕')
|
||||||
|
|
||||||
|
def _get_document(self):
|
||||||
|
if self._is_reading:
|
||||||
|
return
|
||||||
|
self._is_reading = True
|
||||||
|
end_time = perf_counter() + 10
|
||||||
|
while perf_counter() < end_time:
|
||||||
|
try:
|
||||||
|
b_id = self.run_cdp('DOM.getDocument')['root']['backendNodeId']
|
||||||
|
self._root_id = self.run_cdp('DOM.resolveNode', backendNodeId=b_id)['object']['objectId']
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
pass
|
continue
|
||||||
|
|
||||||
sleep(.1)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise GetDocumentError
|
raise GetDocumentError
|
||||||
|
|
||||||
old_driver.stop()
|
r = self.run_cdp('Page.getFrameTree')
|
||||||
self.wait.load_complete()
|
for i in findall(r"'id': '(.*?)'", str(r)):
|
||||||
|
self.browser._frames[i] = self.tab_id
|
||||||
|
|
||||||
def _check_ok(self):
|
if self._is_init_get_doc: # 阻止reload时标识
|
||||||
"""用于应付同域异域之间跳转导致元素丢失问题"""
|
self._is_loading = False
|
||||||
if self._driver._stopped.is_set():
|
self._is_reading = False
|
||||||
self._reload()
|
|
||||||
|
|
||||||
try:
|
|
||||||
self._target_page.run_cdp('DOM.describeNode', nodeId=self.ids.node_id)
|
|
||||||
except ElementLossError:
|
|
||||||
self._reload()
|
|
||||||
# sleep(2)
|
|
||||||
|
|
||||||
def _get_new_document(self):
|
def _get_new_document(self):
|
||||||
"""刷新cdp使用的document数据"""
|
"""刷新cdp使用的document数据"""
|
||||||
if self._is_reading:
|
if self._is_reading:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if self._debug:
|
||||||
|
print('>>> get new doc')
|
||||||
|
|
||||||
self._is_reading = True
|
self._is_reading = True
|
||||||
end_time = perf_counter() + 10
|
end_time = perf_counter() + 10
|
||||||
while perf_counter() < end_time:
|
while perf_counter() < end_time:
|
||||||
@ -179,19 +201,66 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
self._is_loading = False
|
self._is_loading = False
|
||||||
self._is_reading = False
|
self._is_reading = False
|
||||||
|
|
||||||
|
if self._debug:
|
||||||
|
print('>>> new doc got')
|
||||||
|
|
||||||
|
def _onLoadEventFired(self, **kwargs):
|
||||||
|
"""在页面刷新、变化后重新读取页面内容"""
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}触发在frame的LoadEventFired')
|
||||||
|
print('在frame的LoadEventFired变成complete')
|
||||||
|
|
||||||
|
self._ready_state = 'complete'
|
||||||
|
self._get_new_document()
|
||||||
|
self._doc_got = True
|
||||||
|
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}执行frame的LoadEventFired完毕')
|
||||||
|
|
||||||
def _onFrameStoppedLoading(self, **kwargs):
|
def _onFrameStoppedLoading(self, **kwargs):
|
||||||
"""页面加载完成后触发"""
|
"""页面加载完成后触发"""
|
||||||
self.browser._frames[kwargs['frameId']] = self.tab_id
|
self.browser._frames[kwargs['frameId']] = self.tab_id
|
||||||
if kwargs['frameId'] == self.frame_id:
|
if kwargs['frameId'] == self._frame_id and self._doc_got is False:
|
||||||
self._ready_state = 'complete'
|
|
||||||
if self._debug:
|
if self._debug:
|
||||||
print(f'FrameStoppedLoading {kwargs}')
|
print(f'{self._frame_id}触发frame的FrameStoppedLoading')
|
||||||
|
print('在frame的FrameStoppedLoading变成complete')
|
||||||
|
|
||||||
|
self._ready_state = 'complete'
|
||||||
self._get_new_document()
|
self._get_new_document()
|
||||||
|
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}执行frame的FrameStoppedLoading完毕')
|
||||||
|
|
||||||
def _onInspectorDetached(self, **kwargs):
|
def _onInspectorDetached(self, **kwargs):
|
||||||
self._is_loading = True
|
"""异域转同域或退出"""
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}触发InspectorDetached')
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._frame_ele.attrs
|
||||||
|
except ElementLossError:
|
||||||
|
self._driver.stop()
|
||||||
self._reload()
|
self._reload()
|
||||||
|
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}执行InspectorDetached完毕')
|
||||||
|
|
||||||
|
def _onFrameDetached(self, **kwargs):
|
||||||
|
"""同域变异域"""
|
||||||
|
self.browser._frames.pop(kwargs['frameId'], None)
|
||||||
|
if kwargs['frameId'] == self._frame_id:
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}触发FrameDetached')
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._frame_ele.attrs
|
||||||
|
except ElementLossError:
|
||||||
|
self._driver.stop()
|
||||||
|
self._reload()
|
||||||
|
|
||||||
|
if self._debug:
|
||||||
|
print(f'{self._frame_id}执行FrameDetached完毕')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def page(self):
|
def page(self):
|
||||||
return self._page
|
return self._page
|
||||||
@ -208,19 +277,16 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
@property
|
@property
|
||||||
def tag(self):
|
def tag(self):
|
||||||
"""返回元素tag"""
|
"""返回元素tag"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.tag
|
return self.frame_ele.tag
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def url(self):
|
def url(self):
|
||||||
"""返回frame当前访问的url"""
|
"""返回frame当前访问的url"""
|
||||||
self._check_ok()
|
|
||||||
return self.doc_ele.run_js('return this.location.href;')
|
return self.doc_ele.run_js('return this.location.href;')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def html(self):
|
def html(self):
|
||||||
"""返回元素outerHTML文本"""
|
"""返回元素outerHTML文本"""
|
||||||
self._check_ok()
|
|
||||||
tag = self.tag
|
tag = self.tag
|
||||||
out_html = self._target_page.run_cdp('DOM.getOuterHTML', backendNodeId=self.frame_ele.ids.backend_id)[
|
out_html = self._target_page.run_cdp('DOM.getOuterHTML', backendNodeId=self.frame_ele.ids.backend_id)[
|
||||||
'outerHTML']
|
'outerHTML']
|
||||||
@ -230,32 +296,27 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
@property
|
@property
|
||||||
def inner_html(self):
|
def inner_html(self):
|
||||||
"""返回元素innerHTML文本"""
|
"""返回元素innerHTML文本"""
|
||||||
self._check_ok()
|
|
||||||
return self.doc_ele.run_js('return this.documentElement.outerHTML;')
|
return self.doc_ele.run_js('return this.documentElement.outerHTML;')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
"""返回页面title"""
|
"""返回页面title"""
|
||||||
self._check_ok()
|
|
||||||
r = self._ele('t:title', raise_err=False)
|
r = self._ele('t:title', raise_err=False)
|
||||||
return r.text if r else None
|
return r.text if r else None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cookies(self):
|
def cookies(self):
|
||||||
"""以dict格式返回cookies"""
|
"""以dict格式返回cookies"""
|
||||||
self._check_ok()
|
|
||||||
return super().cookies if self._is_diff_domain else self.doc_ele.run_js('return this.cookie;')
|
return super().cookies if self._is_diff_domain else self.doc_ele.run_js('return this.cookie;')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def attrs(self):
|
def attrs(self):
|
||||||
"""返回frame元素所有attribute属性"""
|
"""返回frame元素所有attribute属性"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.attrs
|
return self.frame_ele.attrs
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def frame_size(self):
|
def frame_size(self):
|
||||||
"""返回frame内页面尺寸,格式:(长, 高)"""
|
"""返回frame内页面尺寸,格式:(长, 高)"""
|
||||||
self._check_ok()
|
|
||||||
w = self.doc_ele.run_js('return this.body.scrollWidth')
|
w = self.doc_ele.run_js('return this.body.scrollWidth')
|
||||||
h = self.doc_ele.run_js('return this.body.scrollHeight')
|
h = self.doc_ele.run_js('return this.body.scrollHeight')
|
||||||
return w, h
|
return w, h
|
||||||
@ -263,19 +324,16 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
@property
|
@property
|
||||||
def size(self):
|
def size(self):
|
||||||
"""返回frame元素大小"""
|
"""返回frame元素大小"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.size
|
return self.frame_ele.size
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def active_ele(self):
|
def active_ele(self):
|
||||||
"""返回当前焦点所在元素"""
|
"""返回当前焦点所在元素"""
|
||||||
self._check_ok()
|
|
||||||
return self.doc_ele.run_js('return this.activeElement;')
|
return self.doc_ele.run_js('return this.activeElement;')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def location(self):
|
def location(self):
|
||||||
"""返回frame元素左上角的绝对坐标"""
|
"""返回frame元素左上角的绝对坐标"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.location
|
return self.frame_ele.location
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -286,13 +344,11 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
@property
|
@property
|
||||||
def xpath(self):
|
def xpath(self):
|
||||||
"""返回frame的xpath绝对路径"""
|
"""返回frame的xpath绝对路径"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.xpath
|
return self.frame_ele.xpath
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def css_path(self):
|
def css_path(self):
|
||||||
"""返回frame的css selector绝对路径"""
|
"""返回frame的css selector绝对路径"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.css_path
|
return self.frame_ele.css_path
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -319,8 +375,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
|
|
||||||
sleep(.1)
|
sleep(.1)
|
||||||
|
|
||||||
# raise RuntimeError('获取document失败。')
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_alive(self):
|
def is_alive(self):
|
||||||
"""返回是否仍可用"""
|
"""返回是否仍可用"""
|
||||||
@ -361,7 +415,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
"""刷新frame页面"""
|
"""刷新frame页面"""
|
||||||
self._check_ok()
|
|
||||||
self.doc_ele.run_js('this.location.reload();')
|
self.doc_ele.run_js('this.location.reload();')
|
||||||
|
|
||||||
def attr(self, attr):
|
def attr(self, attr):
|
||||||
@ -369,7 +422,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param attr: 属性名
|
:param attr: 属性名
|
||||||
:return: 属性值文本,没有该属性返回None
|
:return: 属性值文本,没有该属性返回None
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.attr(attr)
|
return self.frame_ele.attr(attr)
|
||||||
|
|
||||||
def remove_attr(self, attr):
|
def remove_attr(self, attr):
|
||||||
@ -377,7 +429,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param attr: 属性名
|
:param attr: 属性名
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
self.frame_ele.remove_attr(attr)
|
self.frame_ele.remove_attr(attr)
|
||||||
|
|
||||||
def run_js(self, script, *args, as_expr=False):
|
def run_js(self, script, *args, as_expr=False):
|
||||||
@ -387,7 +438,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param as_expr: 是否作为表达式运行,为True时args无效
|
:param as_expr: 是否作为表达式运行,为True时args无效
|
||||||
:return: 运行的结果
|
:return: 运行的结果
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
if script.startswith('this.scrollIntoView'):
|
if script.startswith('this.scrollIntoView'):
|
||||||
return self.frame_ele.run_js(script, *args, as_expr=as_expr)
|
return self.frame_ele.run_js(script, *args, as_expr=as_expr)
|
||||||
else:
|
else:
|
||||||
@ -399,7 +449,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param index: 当level_or_loc传入定位符,使用此参数选择第几个结果
|
:param index: 当level_or_loc传入定位符,使用此参数选择第几个结果
|
||||||
:return: 上级元素对象
|
:return: 上级元素对象
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.parent(level_or_loc, index)
|
return self.frame_ele.parent(level_or_loc, index)
|
||||||
|
|
||||||
def prev(self, filter_loc='', index=1, timeout=0, ele_only=True):
|
def prev(self, filter_loc='', index=1, timeout=0, ele_only=True):
|
||||||
@ -410,7 +459,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||||
:return: 同级元素或节点
|
:return: 同级元素或节点
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.prev(filter_loc, index, timeout, ele_only=ele_only)
|
return self.frame_ele.prev(filter_loc, index, timeout, ele_only=ele_only)
|
||||||
|
|
||||||
def next(self, filter_loc='', index=1, timeout=0, ele_only=True):
|
def next(self, filter_loc='', index=1, timeout=0, ele_only=True):
|
||||||
@ -421,7 +469,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||||
:return: 同级元素或节点
|
:return: 同级元素或节点
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.next(filter_loc, index, timeout, ele_only=ele_only)
|
return self.frame_ele.next(filter_loc, index, timeout, ele_only=ele_only)
|
||||||
|
|
||||||
def before(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
def before(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||||
@ -433,7 +480,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||||
:return: 本元素前面的某个元素或节点
|
:return: 本元素前面的某个元素或节点
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.before(filter_loc, index, timeout, ele_only=ele_only)
|
return self.frame_ele.before(filter_loc, index, timeout, ele_only=ele_only)
|
||||||
|
|
||||||
def after(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
def after(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||||
@ -445,7 +491,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||||
:return: 本元素后面的某个元素或节点
|
:return: 本元素后面的某个元素或节点
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.after(filter_loc, index, timeout, ele_only=ele_only)
|
return self.frame_ele.after(filter_loc, index, timeout, ele_only=ele_only)
|
||||||
|
|
||||||
def prevs(self, filter_loc='', timeout=0, ele_only=True):
|
def prevs(self, filter_loc='', timeout=0, ele_only=True):
|
||||||
@ -455,7 +500,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||||
:return: 同级元素或节点文本组成的列表
|
:return: 同级元素或节点文本组成的列表
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.prevs(filter_loc, timeout, ele_only=ele_only)
|
return self.frame_ele.prevs(filter_loc, timeout, ele_only=ele_only)
|
||||||
|
|
||||||
def nexts(self, filter_loc='', timeout=0, ele_only=True):
|
def nexts(self, filter_loc='', timeout=0, ele_only=True):
|
||||||
@ -465,7 +509,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||||
:return: 同级元素或节点文本组成的列表
|
:return: 同级元素或节点文本组成的列表
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.nexts(filter_loc, timeout, ele_only=ele_only)
|
return self.frame_ele.nexts(filter_loc, timeout, ele_only=ele_only)
|
||||||
|
|
||||||
def befores(self, filter_loc='', timeout=None, ele_only=True):
|
def befores(self, filter_loc='', timeout=None, ele_only=True):
|
||||||
@ -476,7 +519,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||||
:return: 本元素前面的元素或节点组成的列表
|
:return: 本元素前面的元素或节点组成的列表
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.befores(filter_loc, timeout, ele_only=ele_only)
|
return self.frame_ele.befores(filter_loc, timeout, ele_only=ele_only)
|
||||||
|
|
||||||
def afters(self, filter_loc='', timeout=None, ele_only=True):
|
def afters(self, filter_loc='', timeout=None, ele_only=True):
|
||||||
@ -487,7 +529,6 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||||
:return: 本元素前面的元素或节点组成的列表
|
:return: 本元素前面的元素或节点组成的列表
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
return self.frame_ele.afters(filter_loc, timeout, ele_only=ele_only)
|
return self.frame_ele.afters(filter_loc, timeout, ele_only=ele_only)
|
||||||
|
|
||||||
def get_screenshot(self, path=None, name=None, as_bytes=None, as_base64=None):
|
def get_screenshot(self, path=None, name=None, as_bytes=None, as_base64=None):
|
||||||
@ -586,75 +627,14 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
:param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置
|
:param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置
|
||||||
:return: ChromiumElement对象
|
:return: ChromiumElement对象
|
||||||
"""
|
"""
|
||||||
self._check_ok()
|
|
||||||
if isinstance(loc_or_ele, ChromiumElement):
|
if isinstance(loc_or_ele, ChromiumElement):
|
||||||
return loc_or_ele
|
return loc_or_ele
|
||||||
|
|
||||||
self.wait.load_complete()
|
self.wait.load_complete()
|
||||||
|
|
||||||
return self.doc_ele._ele(loc_or_ele, timeout, raise_err=raise_err) \
|
return self.doc_ele._ele(loc_or_ele, timeout,
|
||||||
if single else self.doc_ele.eles(loc_or_ele, timeout)
|
raise_err=raise_err) if single else self.doc_ele.eles(loc_or_ele, timeout)
|
||||||
|
|
||||||
def _d_connect(self, to_url, times=0, interval=1, show_errmsg=False, timeout=None):
|
|
||||||
"""尝试连接,重试若干次
|
|
||||||
:param to_url: 要访问的url
|
|
||||||
:param times: 重试次数
|
|
||||||
:param interval: 重试间隔(秒)
|
|
||||||
:param show_errmsg: 是否抛出异常
|
|
||||||
:param timeout: 连接超时时间
|
|
||||||
:return: 是否成功,返回None表示不确定
|
|
||||||
"""
|
|
||||||
self._check_ok()
|
|
||||||
err = None
|
|
||||||
timeout = timeout if timeout is not None else self.timeouts.page_load
|
|
||||||
|
|
||||||
for t in range(times + 1):
|
|
||||||
err = None
|
|
||||||
end_time = perf_counter() + timeout
|
|
||||||
try:
|
|
||||||
result = self.run_cdp('Page.navigate', url=to_url, _timeout=timeout)
|
|
||||||
if 'errorText' in result:
|
|
||||||
err = ConnectionError(result['errorText'])
|
|
||||||
except TimeoutError:
|
|
||||||
err = TimeoutError('页面连接超时。')
|
|
||||||
|
|
||||||
if err:
|
|
||||||
sleep(interval)
|
|
||||||
if self._debug or show_errmsg:
|
|
||||||
print(f'重试{t + 1} {to_url}')
|
|
||||||
self.stop_loading()
|
|
||||||
continue
|
|
||||||
|
|
||||||
if self.page_load_strategy == 'none':
|
|
||||||
return True
|
|
||||||
|
|
||||||
yu = end_time - perf_counter()
|
|
||||||
ok = self._wait_loaded(1 if yu <= 0 else yu)
|
|
||||||
if not ok:
|
|
||||||
err = TimeoutError('页面连接超时。')
|
|
||||||
sleep(interval)
|
|
||||||
if self._debug or show_errmsg:
|
|
||||||
print(f'重试{t + 1} {to_url}')
|
|
||||||
self.stop_loading()
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not err:
|
|
||||||
break
|
|
||||||
|
|
||||||
if err:
|
|
||||||
if show_errmsg:
|
|
||||||
raise err if err is not None else ConnectionError('连接异常。')
|
|
||||||
return False
|
|
||||||
|
|
||||||
self._check_ok()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _is_inner_frame(self):
|
def _is_inner_frame(self):
|
||||||
"""返回当前frame是否同域"""
|
"""返回当前frame是否同域"""
|
||||||
return self.frame_id in str(self._target_page.run_cdp('Page.getFrameTree')['frameTree'])
|
return self._frame_id in str(self._target_page.run_cdp('Page.getFrameTree')['frameTree'])
|
||||||
|
|
||||||
def _check_alive(self):
|
|
||||||
"""检测iframe是否有效线程方法"""
|
|
||||||
while self.is_alive:
|
|
||||||
sleep(1)
|
|
||||||
self.driver.stop()
|
|
||||||
|
@ -21,12 +21,11 @@ from .._units.waiter import FrameWaiter
|
|||||||
|
|
||||||
class ChromiumFrame(ChromiumBase):
|
class ChromiumFrame(ChromiumBase):
|
||||||
|
|
||||||
def __init__(self, page: ChromiumBase, ele: ChromiumElement):
|
def __init__(self, page: Union[ChromiumPage, WebPage, ChromiumTab, ChromiumFrame], ele: ChromiumElement):
|
||||||
self._page: ChromiumPage = ...
|
self._page: ChromiumPage = ...
|
||||||
self._target_page: ChromiumBase = ...
|
self._target_page: ChromiumBase = ...
|
||||||
self.tab: ChromiumTab = ...
|
self.tab: ChromiumTab = ...
|
||||||
self._tab_id: str = ...
|
self._tab_id: str = ...
|
||||||
self.frame_id: str = ...
|
|
||||||
self._frame_ele: ChromiumElement = ...
|
self._frame_ele: ChromiumElement = ...
|
||||||
self._backend_id: str = ...
|
self._backend_id: str = ...
|
||||||
self._doc_ele: ChromiumElement = ...
|
self._doc_ele: ChromiumElement = ...
|
||||||
@ -49,7 +48,7 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
|
|
||||||
def _reload(self) -> None: ...
|
def _reload(self) -> None: ...
|
||||||
|
|
||||||
def _check_ok(self) -> None: ...
|
def _get_document(self) -> None: ...
|
||||||
|
|
||||||
def _get_new_document(self) -> None: ...
|
def _get_new_document(self) -> None: ...
|
||||||
|
|
||||||
@ -193,11 +192,4 @@ class ChromiumFrame(ChromiumBase):
|
|||||||
timeout: float = None, single: bool = True, relative: bool = False, raise_err: bool = None) \
|
timeout: float = None, single: bool = True, relative: bool = False, raise_err: bool = None) \
|
||||||
-> Union[ChromiumElement, ChromiumFrame, None, List[Union[ChromiumElement, ChromiumFrame]]]: ...
|
-> Union[ChromiumElement, ChromiumFrame, None, List[Union[ChromiumElement, ChromiumFrame]]]: ...
|
||||||
|
|
||||||
def _d_connect(self,
|
|
||||||
to_url: str,
|
|
||||||
times: int = 0,
|
|
||||||
interval: float = 1,
|
|
||||||
show_errmsg: bool = False,
|
|
||||||
timeout: float = None) -> Union[bool, None]: ...
|
|
||||||
|
|
||||||
def _is_inner_frame(self) -> bool: ...
|
def _is_inner_frame(self) -> bool: ...
|
||||||
|
2
setup.py
2
setup.py
@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="DrissionPage",
|
name="DrissionPage",
|
||||||
version="4.0.0b5",
|
version="4.0.0b6",
|
||||||
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.",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user