mirror of
https://github.com/ThePhaseless/Byparr.git
synced 2026-09-24 14:20:08 +01:00
Fix Playwright page crash error with retry mechanism
- Add import for PlaywrightError from playwright.async_api - Implement retry logic (max 2 attempts) for page crashes - When page crashes, close the crashed page and create a new one from context - Use current_page variable to track the active page instance - Initialize page_request and status to prevent undefined variable errors - Add proper error logging for page crash scenarios This fix resolves the "Page.goto: Page crashed" error by gracefully handling page crashes and retrying the operation with a fresh page.
This commit is contained in:
+62
-33
@@ -6,6 +6,7 @@ from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi.responses import RedirectResponse
|
||||
from playwright.async_api import Error as PlaywrightError
|
||||
from playwright_captcha import CaptchaType
|
||||
|
||||
from src.consts import CHALLENGE_TITLES
|
||||
@@ -57,50 +58,78 @@ async def read_item(request: LinkRequest, dep: CamoufoxDep) -> LinkResponse:
|
||||
timer = TimeoutTimer(duration=request.max_timeout)
|
||||
|
||||
request.url = request.url.replace('"', "").strip()
|
||||
try:
|
||||
page_request = await dep.page.goto(
|
||||
request.url, timeout=timer.remaining() * 1000
|
||||
)
|
||||
status = page_request.status if page_request else HTTPStatus.OK
|
||||
await dep.page.wait_for_load_state(
|
||||
state="domcontentloaded", timeout=timer.remaining() * 1000
|
||||
)
|
||||
await dep.page.wait_for_load_state(
|
||||
"networkidle", timeout=timer.remaining() * 1000
|
||||
)
|
||||
|
||||
if await dep.page.title() in CHALLENGE_TITLES:
|
||||
logger.info("Challenge detected, attempting to solve...")
|
||||
# Solve the captcha
|
||||
await wait_for(
|
||||
dep.solver.solve_captcha( # pyright: ignore[reportUnknownMemberType,reportUnknownArgumentType]
|
||||
captcha_container=dep.page,
|
||||
captcha_type=CaptchaType.CLOUDFLARE_INTERSTITIAL,
|
||||
wait_checkbox_attempts=1,
|
||||
wait_checkbox_delay=0.5,
|
||||
),
|
||||
timeout=timer.remaining(),
|
||||
# Track retry attempts for page crashes
|
||||
max_retries = 2
|
||||
current_page = dep.page
|
||||
page_request = None
|
||||
status = HTTPStatus.OK
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
page_request = await current_page.goto(
|
||||
request.url, timeout=timer.remaining() * 1000
|
||||
)
|
||||
status = HTTPStatus.OK
|
||||
logger.debug("Challenge solved successfully.")
|
||||
except TimeoutError as e:
|
||||
logger.error("Timed out while solving the challenge")
|
||||
raise HTTPException(
|
||||
status_code=408,
|
||||
detail="Timed out while solving the challenge",
|
||||
) from e
|
||||
status = page_request.status if page_request else HTTPStatus.OK
|
||||
await current_page.wait_for_load_state(
|
||||
state="domcontentloaded", timeout=timer.remaining() * 1000
|
||||
)
|
||||
await current_page.wait_for_load_state(
|
||||
"networkidle", timeout=timer.remaining() * 1000
|
||||
)
|
||||
|
||||
if await current_page.title() in CHALLENGE_TITLES:
|
||||
logger.info("Challenge detected, attempting to solve...")
|
||||
# Solve the captcha
|
||||
await wait_for(
|
||||
dep.solver.solve_captcha( # pyright: ignore[reportUnknownMemberType,reportUnknownArgumentType]
|
||||
captcha_container=current_page,
|
||||
captcha_type=CaptchaType.CLOUDFLARE_INTERSTITIAL,
|
||||
wait_checkbox_attempts=1,
|
||||
wait_checkbox_delay=0.5,
|
||||
),
|
||||
timeout=timer.remaining(),
|
||||
)
|
||||
status = HTTPStatus.OK
|
||||
logger.debug("Challenge solved successfully.")
|
||||
break # Success, exit retry loop
|
||||
except PlaywrightError as e:
|
||||
if "Page crashed" in str(e) and attempt < max_retries - 1:
|
||||
logger.warning(f"Page crashed on attempt {attempt + 1}, recreating page and retrying...")
|
||||
try:
|
||||
# Close the crashed page
|
||||
await current_page.close()
|
||||
except Exception as close_error:
|
||||
logger.debug(f"Error closing crashed page: {close_error}")
|
||||
|
||||
# Create a new page from the existing context
|
||||
current_page = await dep.context.new_page()
|
||||
continue # Retry with the new page
|
||||
else:
|
||||
# Either not a page crash or out of retries
|
||||
logger.error(f"Playwright error: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Browser error: {str(e)}",
|
||||
) from e
|
||||
except TimeoutError as e:
|
||||
logger.error("Timed out while solving the challenge")
|
||||
raise HTTPException(
|
||||
status_code=408,
|
||||
detail="Timed out while solving the challenge",
|
||||
) from e
|
||||
|
||||
cookies = await dep.context.cookies()
|
||||
|
||||
return LinkResponse(
|
||||
message="Success",
|
||||
solution=Solution(
|
||||
user_agent=await dep.page.evaluate("navigator.userAgent"),
|
||||
url=dep.page.url,
|
||||
user_agent=await current_page.evaluate("navigator.userAgent"),
|
||||
url=current_page.url,
|
||||
status=status,
|
||||
cookies=cookies,
|
||||
headers=page_request.headers if page_request else {},
|
||||
response=await dep.page.content(),
|
||||
response=await current_page.content(),
|
||||
),
|
||||
start_timestamp=start_time,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user