fix wait for animation end (#3201)
This commit is contained in:
@@ -2642,6 +2642,28 @@ async function getIncrementElements(wait_until_finished = true) {
|
||||
return [Array.from(idToElement.values()), cleanedTreeList];
|
||||
}
|
||||
|
||||
function isAnimationFinished() {
|
||||
const animations = document.getAnimations({ subtree: true });
|
||||
const unfinishedAnimations = animations.filter(
|
||||
(a) => a.playState !== "finished",
|
||||
);
|
||||
if (!unfinishedAnimations || unfinishedAnimations.length == 0) {
|
||||
return true;
|
||||
}
|
||||
const unfinishedAnimationsWithoutBlocked = unfinishedAnimations.filter(
|
||||
(a) => {
|
||||
const element = a.effect?.target;
|
||||
if (!element) {
|
||||
_jsConsoleLog("Unfinished animation without element:", a);
|
||||
return false;
|
||||
}
|
||||
const result = getBlockElementUniqueID(element);
|
||||
return !result[1];
|
||||
},
|
||||
);
|
||||
return unfinishedAnimationsWithoutBlocked.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
// How to run the code:
|
||||
|
||||
@@ -557,7 +557,8 @@ async def scrape_web_unsafe(
|
||||
|
||||
try:
|
||||
await page.wait_for_load_state("load", timeout=3000)
|
||||
await SkyvernFrame.wait_for_animation_end(page)
|
||||
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)
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ async def _scrolling_screenshots_helper(
|
||||
|
||||
if mode == ScreenshotMode.DETAILED:
|
||||
# wait until animation ends, which is triggered by scrolling
|
||||
await SkyvernFrame.wait_for_animation_end(skyvern_page.frame)
|
||||
await skyvern_page.safe_wait_for_animation_end()
|
||||
else:
|
||||
if draw_boxes:
|
||||
await skyvern_page.build_elements_and_draw_bounding_boxes(frame=frame, frame_index=frame_index)
|
||||
@@ -214,21 +214,6 @@ def _merge_images_by_position(images: list[Image.Image], positions: list[int]) -
|
||||
|
||||
|
||||
class SkyvernFrame:
|
||||
@staticmethod
|
||||
async def wait_for_animation_end(page: Page, timeout: float = 3000) -> None:
|
||||
try:
|
||||
await page.wait_for_function(
|
||||
"""
|
||||
() => {
|
||||
const animations = document.getAnimations();
|
||||
return animations.every(a => a.playState === 'finished');
|
||||
}
|
||||
""",
|
||||
timeout=timeout,
|
||||
)
|
||||
except Exception:
|
||||
LOG.warning("Failed to wait for animation end, but continue", exc_info=True)
|
||||
|
||||
@staticmethod
|
||||
async def evaluate(
|
||||
frame: Page | Frame,
|
||||
@@ -514,3 +499,23 @@ class SkyvernFrame:
|
||||
return await self.evaluate(
|
||||
frame=self.frame, expression=js_script, timeout_ms=timeout_ms, arg=[wait_until_finished]
|
||||
)
|
||||
|
||||
async def safe_wait_for_animation_end(self, 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)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user