helper function for wait animation (#3240)

This commit is contained in:
LawyZheng
2025-08-20 14:28:01 +08:00
committed by GitHub
parent 79d9486f92
commit 55bc6bd367
3 changed files with 32 additions and 137 deletions

View File

@@ -974,18 +974,7 @@ async def handle_input_text_action(
action=action,
)
try:
await skyvern_frame.get_frame().wait_for_load_state("load", timeout=3000)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.info(
"Timeout to wait for the frame to load, ignore the timeout and continue to execute the action",
task_id=task.task_id,
step_id=step.step_id,
element_id=skyvern_element.get_id(),
action=action,
)
await skyvern_frame.safe_wait_for_animation_end()
incremental_element = await incremental_scraped.get_incremental_element_tree(
clean_and_remove_element_tree_factory(
task=task, step=step, check_filter_funcs=[check_existed_but_not_option_element_in_dom_factory(dom)]
@@ -1126,18 +1115,7 @@ async def handle_input_text_action(
return [ActionFailure(InvalidElementForTextInput(element_id=action.element_id, tag_name=tag_name))]
# wait for blocking element to show up
try:
await skyvern_frame.get_frame().wait_for_load_state("load", timeout=3000)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.info(
"Timeout to wait for the frame to load, ignore the timeout and continue to execute the action",
task_id=task.task_id,
step_id=step.step_id,
element_id=skyvern_element.get_id(),
action=action,
)
await skyvern_frame.safe_wait_for_animation_end()
try:
blocking_element, exist = await skyvern_element.find_blocking_element(
dom=dom, incremental_page=incremental_scraped
@@ -1538,15 +1516,7 @@ async def handle_select_option_action(
await skyvern_element.click(page=page, dom=dom, timeout=timeout)
# wait for options to load
await asyncio.sleep(0.5)
try:
await skyvern_frame.get_frame().wait_for_event("load", timeout=3000)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.info(
"Failed to wait for the frame to load, ignore the timeout and continue to get incremental element tree",
exc_info=True,
)
await skyvern_frame.safe_wait_for_animation_end(before_wait_sec=0.5)
incremental_element = await incremental_scraped.get_incremental_element_tree(
clean_and_remove_element_tree_factory(
@@ -1564,15 +1534,7 @@ async def handle_select_option_action(
await skyvern_element.scroll_into_view()
await skyvern_element.press_key("ArrowDown")
# wait for options to load
await asyncio.sleep(0.5)
try:
await skyvern_frame.get_frame().wait_for_event("load", timeout=3000)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.info(
"Failed to wait for the frame to load, ignore the timeout and continue to get incremental element tree",
exc_info=True,
)
await skyvern_frame.safe_wait_for_animation_end(before_wait_sec=0.5)
incremental_element = await incremental_scraped.get_incremental_element_tree(
clean_and_remove_element_tree_factory(
task=task, step=step, check_filter_funcs=[check_existed_but_not_option_element_in_dom_factory(dom)]
@@ -1669,15 +1631,7 @@ async def handle_select_option_action(
await skyvern_element.scroll_into_view()
await skyvern_element.press_key("ArrowDown")
try:
await asyncio.sleep(0.5)
await skyvern_frame.get_frame().wait_for_event("load", timeout=3000)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.info(
"Failed to wait for the frame to load, ignore the exception and continue",
exc_info=True,
)
await skyvern_frame.safe_wait_for_animation_end(before_wait_sec=0.5)
is_open = True
result = await select_from_dropdown_by_value(
@@ -2200,15 +2154,7 @@ async def choose_auto_completion_dropdown(
try:
await skyvern_element.press_fill(text)
# wait for new elemnts to load
try:
await asyncio.sleep(0.5)
await skyvern_frame.get_frame().wait_for_load_state("load", timeout=3000)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.warning(
"Failed to wait for load state or animation end after input the value, will continue to get incremental element tree",
exc_info=True,
)
await skyvern_frame.safe_wait_for_animation_end(before_wait_sec=0.5)
incremental_element = await incremental_scraped.get_incremental_element_tree(
clean_and_remove_element_tree_factory(
task=task, step=step, check_filter_funcs=[check_existed_but_not_option_element_in_dom_factory(dom)]
@@ -2608,15 +2554,7 @@ async def sequentially_select_from_dropdown(
select_history.append(single_select_result)
values.append(single_select_result.value)
# wait 1s until DOM finished updating
try:
await asyncio.sleep(0.5)
await skyvern_frame.get_frame().wait_for_event("load", timeout=3000)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.info(
"Failed to wait for the animation to end, ignore the exception and continue",
exc_info=True,
)
await skyvern_frame.safe_wait_for_animation_end(before_wait_sec=0.5)
if await single_select_result.is_done():
return single_select_result
@@ -2637,15 +2575,7 @@ async def sequentially_select_from_dropdown(
step_id=step.step_id,
)
# wait to load new options
try:
await asyncio.sleep(0.5)
await skyvern_frame.get_frame().wait_for_event("load", timeout=3000)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.info(
"Failed to wait for the animation to end, ignore the exception and continue",
exc_info=True,
)
await skyvern_frame.safe_wait_for_animation_end(before_wait_sec=0.5)
check_filter_funcs.append(
check_disappeared_element_id_in_incremental_factory(incremental_scraped=incremental_scraped)
@@ -3356,29 +3286,13 @@ async def scroll_down_to_load_all_options(
else:
await skyvern_frame.scroll_to_element_bottom(dropdown_menu_element_handle, page_by_page)
# wait until animation ends, otherwise the scroll operation could be overwritten
try:
await asyncio.sleep(0.5)
await skyvern_frame.get_frame().wait_for_event("load", timeout=3000)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.info(
"Failed to wait for the animation to end, ignore the exception and continue",
exc_info=True,
)
await skyvern_frame.safe_wait_for_animation_end(before_wait_sec=0.5)
# scroll a little back and scroll down to trigger the loading
await page.mouse.wheel(0, -1e-5)
await page.mouse.wheel(0, 1e-5)
# wait for while to load new options
try:
await asyncio.sleep(0.5)
await skyvern_frame.get_frame().wait_for_event("load", timeout=3000)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.info(
"Failed to wait for the animation to end, ignore the exception and continue",
exc_info=True,
)
await skyvern_frame.safe_wait_for_animation_end(before_wait_sec=0.5)
current_num = await incremental_scraped.get_incremental_elements_num()
LOG.info(
@@ -3403,15 +3317,7 @@ async def scroll_down_to_load_all_options(
await page.mouse.wheel(0, -scroll_pace)
else:
await skyvern_frame.scroll_to_element_top(dropdown_menu_element_handle)
try:
await asyncio.sleep(0.5)
await skyvern_frame.get_frame().wait_for_event("load", timeout=3000)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.info(
"Failed to wait for the animation to end, ignore the exception and continue",
exc_info=True,
)
await skyvern_frame.safe_wait_for_animation_end(before_wait_sec=0.5)
async def normal_select(

View File

@@ -555,12 +555,8 @@ async def scrape_web_unsafe(
if url == "about:blank" and not support_empty_page:
raise ScrapingFailedBlankPage()
try:
await page.wait_for_load_state("load", timeout=3000)
skyvern_frame = await SkyvernFrame.create_instance(page)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.warning("Failed to wait for load state, will continue scraping", exc_info=True)
skyvern_frame = await SkyvernFrame.create_instance(page)
await skyvern_frame.safe_wait_for_animation_end()
if wait_seconds > 0:
LOG.info(f"Waiting for {wait_seconds} seconds before scraping the website.", wait_seconds=wait_seconds)
@@ -689,15 +685,7 @@ async def add_frame_interactable_elements(
return elements, element_tree
skyvern_frame = await SkyvernFrame.create_instance(frame)
try:
await skyvern_frame.get_frame().wait_for_load_state("load", timeout=3000)
await skyvern_frame.safe_wait_for_animation_end()
except Exception:
LOG.warning(
"Failed to wait for load state or animation end for the frame, will continue scraping",
frame_id=unique_id,
exc_info=True,
)
await skyvern_frame.safe_wait_for_animation_end()
frame_elements, frame_element_tree = await skyvern_frame.build_tree_from_body(
frame_name=unique_id, frame_index=frame_index

View File

@@ -517,22 +517,23 @@ class SkyvernFrame:
frame=self.frame, expression=js_script, timeout_ms=timeout_ms, arg=[starter, frame, full_tree]
)
async def safe_wait_for_animation_end(self, timeout_ms: float = 3000) -> None:
async def safe_wait_for_animation_end(self, before_wait_sec: float = 0, timeout_ms: float = 3000) -> None:
try:
async with asyncio.timeout(timeout_ms / 1000):
while True:
try:
is_finished = await self.evaluate(
frame=self.frame,
expression="() => isAnimationFinished()",
timeout_ms=timeout_ms,
)
if is_finished:
return
await asyncio.sleep(0.1)
except Exception:
LOG.warning("Failed to wait for animation end, but ignore it", exc_info=True)
return
except asyncio.TimeoutError:
LOG.debug("Timeout while waiting for animation end, but ignore it", exc_info=True)
await asyncio.sleep(before_wait_sec)
await self.frame.wait_for_load_state("load", timeout=timeout_ms)
await self.wait_for_animation_end(timeout_ms=timeout_ms)
except Exception:
LOG.info("Failed to wait for animation end, but ignore it", exc_info=True)
return
async def wait_for_animation_end(self, timeout_ms: float = 3000) -> None:
async with asyncio.timeout(timeout_ms / 1000):
while True:
is_finished = await self.evaluate(
frame=self.frame,
expression="() => isAnimationFinished()",
timeout_ms=timeout_ms,
)
if is_finished:
return
await asyncio.sleep(0.1)