[Python] I'm having this error: Event loop is closed! Is Playwright already stopped. How can i...

Discussão em 'Python' iniciado por Stack, Março 2, 2025.

  1. Stack

    Stack Membro Participativo

    I am working with Playwright in Python and facing an issue with the retry logic when an action fails.

    The idea is that if the action fails on one attempt, the code should retry up to a maximum of 8 times. For each new attempt, the proxy should be renewed, changing the IP address used.

    from src.services.LoggingService import LoggingService
    from playwright.sync_api import sync_playwright, TimeoutError
    from decouple import config

    class UserService:

    @staticmethod
    def update(username, password, playerName, playerPassword):
    attempt = 0
    max_attempts = 8
    while attempt < max_attempts:
    browser = None
    try:
    with sync_playwright() as p:
    if config("PROXY_ENABLED") == "true":
    browser = p.chromium.launch(
    headless=True,
    args=["--no-sandbox", "--disable-blink-features=AutomationControlled"],
    proxy={"server": config("PROXY_URL")}
    )
    LoggingService.info(f"Proxy enabled: {config('PROXY_URL')}", "UserService")
    else:
    LoggingService.info("Proxy disabled", "UserService")
    browser = p.chromium.launch(headless=True)

    page = browser.new_page()
    page.goto(config("GA_LOGIN_URL"), timeout=60000)
    page.fill('input.input_sizable_low.input_type_text.input_validState_1', username)
    page.fill('input.input_sizable_low.input_type_password.input_with-eye.input_validState_1', password)
    page.click('button.button_sizable_default.button_colors_default')
    page.wait_for_selector('input.input_sizable_default.input_type_text.input_validState_1', timeout=60000)
    page.fill('input.input_sizable_default.input_type_text.input_validState_1', playerName)
    page.locator(f"text={playerName}").click(timeout=30000)
    page.locator(".dropdown__action").first.click(timeout=30000)
    page.get_by_role("link", name="Cambiar contraseña").click(timeout=30000)
    page.get_by_role("textbox", name="Nueva contraseña", exact=True).fill(playerPassword)
    page.get_by_role("textbox", name="Confirmar nueva contraseña").fill(playerPassword)
    page.get_by_role("button", name="Cambiar").click(timeout=30000)
    page.wait_for_timeout(1000)
    browser.close()

    LoggingService.info(f"Usuario {playerName} actualizado con éxito luego de {attempt + 1} intentos", "UserService")
    return True
    except Exception as e:
    LoggingService.error(f"Error en intento {attempt + 1}: {str(e)}", "UserService")
    attempt += 1
    if attempt == max_attempts:
    LoggingService.error(f"No se pudo realizar el ingreso para {playerName} tras {max_attempts} intentos", "UserService")
    return False

    return False

    @staticmethod
    def create(username, password, playerName, playerPassword):
    attempt = 0
    max_attempts = 8
    while attempt < max_attempts:
    browser = None
    try:
    with sync_playwright() as p:
    if config("PROXY_ENABLED") == "true":
    browser = p.chromium.launch(
    headless=True,
    args=["--no-sandbox", "--disable-blink-features=AutomationControlled"],
    proxy={"server": config("PROXY_URL")}
    )
    LoggingService.info(f"Proxy enabled: {config('PROXY_URL')}", "UserService")
    else:
    LoggingService.info("Proxy disabled", "UserService")
    browser = p.chromium.launch(headless=True)

    page = browser.new_page()
    page.goto(config("GA_LOGIN_URL"), timeout=60000)
    page.fill('input.input_sizable_low.input_type_text.input_validState_1', username)
    page.fill('input.input_sizable_low.input_type_password.input_with-eye.input_validState_1', password)
    page.click('button.button_sizable_default.button_colors_default')
    page.get_by_role("link", name="Nuevo jugador").click(timeout=30000)
    page.get_by_role("textbox", name="Nombre de usuario").fill(playerName)
    page.get_by_role("textbox", name="Contraseña", exact=True).fill(playerPassword)
    page.get_by_role("textbox", name="Confirmar contraseña").fill(playerPassword)
    page.get_by_role("button", name="Crear jugador").click(timeout=30000)
    page.locator("#modal-root").get_by_role("button", name="Crear jugador").click(timeout=30000)
    page.wait_for_timeout(500)
    browser.close()

    LoggingService.info(f"Usuario {playerName} creado con éxito luego de {attempt + 1} intentos", "UserService")
    return True
    except Exception as e:
    LoggingService.info(f"Error en intento {attempt + 1}: {str(e)}", "UserService")
    attempt += 1
    if attempt == max_attempts:
    LoggingService.info(f"No se pudo realizar el ingreso para {playerName} tras {max_attempts} intentos", "UserService")
    return False

    return False

    @staticmethod
    def cashin(username: str, password: str, playerName: str, playerAmount: str):
    attempt = 0
    max_attempts = 8
    while attempt < max_attempts:
    browser = None
    try:
    with sync_playwright() as p:
    if config("PROXY_ENABLED") == "true":
    browser = p.chromium.launch(
    headless=True,
    args=["--no-sandbox", "--disable-blink-features=AutomationControlled"],
    proxy={"server": config("PROXY_URL")}
    )
    LoggingService.info(f"Proxy enabled: {config('PROXY_URL')}", "UserService")
    else:
    LoggingService.info("Proxy disabled", "UserService")
    browser = p.chromium.launch(headless=True)

    page = browser.new_page()
    page.goto(config("GA_LOGIN_URL"), timeout=60000)
    page.fill('input.input_sizable_low.input_type_text.input_validState_1', username)
    page.fill('input.input_sizable_low.input_type_password.input_with-eye.input_validState_1', password)
    page.click('button.button_sizable_default.button_colors_default')
    page.wait_for_selector('input.input_sizable_default.input_type_text.input_validState_1', timeout=60000)
    page.fill('input.input_sizable_default.input_type_text.input_validState_1', playerName)
    page.locator(f"text={playerName}").click(timeout=30000)
    page.locator("div:has-text('Depositar')").first.click(timeout=30000)
    page.get_by_role("link", name="Depositar").first.click(timeout=30000)
    page.get_by_role("textbox", name="Monto").wait_for(timeout=30000)
    page.get_by_role("textbox", name="Monto").fill(str(playerAmount))
    page.get_by_role("button", name="Depósito").click(timeout=30000)
    page.wait_for_timeout(1000)
    browser.close()

    LoggingService.info(f"Ingreso de {playerAmount} en la cuenta @{playerName} luego de {attempt + 1} intentos", "UserService")
    return True
    except Exception as e:
    LoggingService.error(f"Error en intento {attempt + 1}: {str(e)}", "UserService")
    attempt += 1
    if attempt == max_attempts:
    LoggingService.error(f"No se pudo realizar el ingreso para {playerName} tras {max_attempts} intentos", "UserService")
    return False

    return False

    @staticmethod
    def cashout(username, password, playerName, playerAmount):
    attempt = 0
    max_attempts = 8
    while attempt < max_attempts:
    browser = None
    try:
    with sync_playwright() as p:
    if config("PROXY_ENABLED") == "true":
    browser = p.chromium.launch(
    headless=True,
    args=["--no-sandbox", "--disable-blink-features=AutomationControlled"],
    proxy={"server": config("PROXY_URL")}
    )
    LoggingService.info(f"Proxy enabled: {config('PROXY_URL')}", "UserService")
    else:
    LoggingService.info("Proxy disabled", "UserService")
    browser = p.chromium.launch(headless=True)

    page = browser.new_page()
    page.goto(config("GA_LOGIN_URL"), timeout=60000)
    page.fill('input.input_sizable_low.input_type_text.input_validState_1', username)
    page.fill('input.input_sizable_low.input_type_password.input_with-eye.input_validState_1', password)
    page.click('button.button_sizable_default.button_colors_default')
    page.wait_for_selector('input.input_sizable_default.input_type_text.input_validState_1', timeout=60000)
    page.fill('input.input_sizable_default.input_type_text.input_validState_1', playerName)
    page.locator(f"text={playerName}").click(timeout=30000)
    page.get_by_role("link", name="Retiro", exact=True).first.click(timeout=30000)
    page.get_by_role("textbox", name="Monto").fill(str(playerAmount))
    page.get_by_role("button", name="Retiro").click(timeout=30000)
    page.wait_for_timeout(1000)
    browser.close()

    LoggingService.info(f"Retiro de {playerAmount} en la cuenta @{playerName} luego de {attempt + 1} intentos", "UserService")
    return True
    except Exception as e:
    LoggingService.error(f"Error en intento {attempt + 1}: {str(e)}", "UserService")
    attempt += 1
    if attempt == max_attempts:
    LoggingService.error(f"No se pudo realizar el ingreso para {playerName} tras {max_attempts} intentos", "UserService")
    return False

    return False


    However, the code is not working as expected. I am encountering the following error:

    line 104, in _sync
    raise Error("Event loop is closed! Is Playwright already stopped?")
    playwright._impl._errors.Error: Event loop is closed! Is Playwright already stopped?


    I don’t understand why this error occurs since I am using sync_playwright() inside each attempt and properly closing the browser at the end of the process.

    The main issue is that although I expect Playwright to start and close correctly on each attempt, it seems that at some point, the event loop is already closed and cannot be restarted. This prevents the reconnection attempts from working as intended.

    Here is the complete code for reference:

    Why is the event loop closing unexpectedly? What would be the best way to handle retries in Playwright to ensure that the proxy is properly renewed on each attempt without causing this error?

    I would appreciate any suggestions or solutions.

    Continue reading...

Compartilhe esta Página