fix: авто-перезапуск браузера при закрытом контексте (BrowserContext.new_page: has been closed)

This commit is contained in:
apuc committed 2026-09-16 13:20:19 +03:00
1 parent 4dcaffd4c4
commit e4cd06a23d
1 file changed
+51 -11
+51 -11
View File
@@ -42,6 +42,7 @@ SUBMIT_BUTTONS = [
# Доступны ТОЛЬКО из браузерного потока.
_browsers = {}
_pages = {}
_playwrights = {}
# ---------- Браузерный поток ----------
@@ -111,9 +112,8 @@ def get_proxy_config():
# ---------- Внутренние функции (только из браузерного потока) ----------
def _launch_context(account_dir):
def _launch_context_with(p, account_dir):
"""Запускает браузер с профилем аккаунта и подставляет cookies сессии."""
p = sync_playwright().start()
kwargs = dict(
user_data_dir=os.path.join(account_dir, "profile"),
headless=is_headless(),
@@ -127,6 +127,15 @@ def _launch_context(account_dir):
return context
def _context_alive(ctx):
"""Проверяет, жив ли контекст (лёгкая операция, не создаёт страниц)."""
try:
ctx.pages
return True
except Exception:
return False
def _inject_session_cookies(context, account_dir):
"""Подставляет cookies из session.txt — вход на hh.ru без ручного логина."""
path = os.path.join(account_dir, "session.txt")
@@ -149,10 +158,33 @@ def _inject_session_cookies(context, account_dir):
def _get_context(account_dir, user, account):
"""Возвращает живой контекст; если браузер умер — перезапускает."""
key = (user, account)
if key not in _browsers:
_browsers[key] = _launch_context(account_dir)
return _browsers[key]
ctx = _browsers.get(key)
if ctx is None or not _context_alive(ctx):
if ctx is not None:
print(f" ⚠ Браузер {key} закрыт — перезапускаю")
_close_context(key)
p = sync_playwright().start()
try:
ctx = _launch_context_with(p, account_dir)
except Exception:
p.stop()
raise
_browsers[key] = ctx
_playwrights[key] = p
return ctx
def _new_page(account_dir, user, account):
"""Создаёт страницу; если контекст умер между проверкой и созданием —
перезапускает браузер и пробует ещё раз."""
try:
return _get_context(account_dir, user, account).new_page()
except Exception:
print(f" ⚠ Не удалось создать страницу для {(user, account)} — перезапускаю браузер")
_close_context((user, account))
return _get_context(account_dir, user, account).new_page()
def _save_screenshot(page, screenshot_dir, vid):
@@ -181,8 +213,7 @@ def open_response_page(account_dir, user, account, vacancy, message,
except Exception:
pass
context = _get_context(account_dir, user, account)
page = context.new_page()
page = _new_page(account_dir, user, account)
_pages[key] = page
page.goto(vacancy["url"], timeout=45000)
page.wait_for_timeout(2500)
@@ -276,15 +307,14 @@ def confirm_send(user, account, vid):
def open_login_page(account_dir, user, account):
"""Открывает hh.ru в браузере (для ручного входа, локальный режим с экраном)."""
key = (user, account)
context = _get_context(account_dir, user, account)
page = context.new_page()
page = _new_page(account_dir, user, account)
_pages[key] = page
page.goto("https://hh.ru", timeout=45000)
return True, "Страница hh.ru открыта"
def close_context(user, account):
key = (user, account)
def _close_context(key):
"""Закрывает контекст и останавливает playwright-инстанс (из браузерного потока)."""
if key in _browsers:
try:
_browsers[key].close()
@@ -292,6 +322,16 @@ def close_context(user, account):
pass
_browsers.pop(key, None)
_pages.pop(key, None)
p = _playwrights.pop(key, None)
if p:
try:
p.stop()
except Exception:
pass
def close_context(user, account):
_close_context((user, account))
# ---------- Публичные обёртки (можно вызывать из любого потока) ----------