@@ -440,7 +440,7 @@ async def _capture_clean_screenshot(self) -> str:
440
440
raise
441
441
442
442
async def _wait_for_stable_network (self ):
443
- """Wait for page stability - simplified for CDP-only branch ."""
443
+ """Wait for page stability with enhanced network idle detection and load state monitoring ."""
444
444
start_time = time .time ()
445
445
446
446
# Apply minimum wait time first (let page settle)
@@ -449,15 +449,60 @@ async def _wait_for_stable_network(self):
449
449
self .logger .debug (f'⏳ Minimum wait: { min_wait } s' )
450
450
await asyncio .sleep (min_wait )
451
451
452
- # Apply network idle wait time (for dynamic content like iframes)
452
+ # Enhanced network idle wait with load state monitoring
453
453
network_idle_wait = self .browser_session .browser_profile .wait_for_network_idle_page_load_time
454
454
if network_idle_wait > 0 :
455
- self .logger .debug (f'⏳ Network idle wait: { network_idle_wait } s' )
456
- await asyncio .sleep (network_idle_wait )
455
+ self .logger .debug (f'⏳ Enhanced network idle wait: { network_idle_wait } s' )
456
+
457
+ # Try to wait for document ready state and network idle
458
+ try :
459
+ await self ._wait_for_document_ready_and_network_idle (network_idle_wait )
460
+ except Exception as e :
461
+ self .logger .debug (f'Advanced wait failed, falling back to simple wait: { e } ' )
462
+ await asyncio .sleep (network_idle_wait )
457
463
458
464
elapsed = time .time () - start_time
459
465
self .logger .debug (f'✅ Page stability wait completed in { elapsed :.2f} s' )
460
466
467
+ async def _wait_for_document_ready_and_network_idle (self , max_wait : float ):
468
+ """Wait for document ready state and network idle with timeout."""
469
+ if not self .browser_session .agent_focus :
470
+ await asyncio .sleep (max_wait ) # Fallback to simple wait
471
+ return
472
+
473
+ try :
474
+ cdp_session = await self .browser_session .get_or_create_cdp_session (
475
+ target_id = self .browser_session .agent_focus .target_id , focus = True
476
+ )
477
+
478
+ # Enable runtime and page events
479
+ await cdp_session .cdp_client .send .Runtime .enable (session_id = cdp_session .session_id )
480
+ await cdp_session .cdp_client .send .Page .enable (session_id = cdp_session .session_id )
481
+
482
+ # Check document ready state
483
+ ready_state_check = await cdp_session .cdp_client .send .Runtime .evaluate (
484
+ params = {
485
+ 'expression' : 'document.readyState' ,
486
+ 'returnByValue' : True
487
+ },
488
+ session_id = cdp_session .session_id
489
+ )
490
+
491
+ document_ready = ready_state_check .get ('result' , {}).get ('value' ) == 'complete'
492
+
493
+ if document_ready :
494
+ self .logger .debug ('📄 Document already complete' )
495
+ # Still wait a bit for any remaining network requests
496
+ await asyncio .sleep (min (0.5 , max_wait ))
497
+ else :
498
+ self .logger .debug ('📄 Document not complete, waiting for ready state' )
499
+ # Wait for document to be ready or timeout
500
+ await asyncio .sleep (max_wait )
501
+
502
+ except Exception as e :
503
+ self .logger .debug (f'Document ready check failed: { e } ' )
504
+ await asyncio .sleep (max_wait ) # Fallback to simple wait
505
+
461
506
async def _get_page_info (self ) -> 'PageInfo' :
462
507
"""Get comprehensive page information using a single CDP call.
463
508
0 commit comments