feat: keep login selector fallbacks close to auth flow (#855)

This commit is contained in:
Jens
2026-03-02 13:01:05 +01:00
committed by GitHub
parent c4a2d1c4f5
commit fa9df6fca4
3 changed files with 82 additions and 18 deletions

View File

@@ -7,7 +7,7 @@ import urllib.parse as urllib_parse
from datetime import datetime
from gettext import gettext as _
from pathlib import Path
from typing import Any, Final, cast
from typing import Any, Final, Sequence, cast
import certifi, colorama, nodriver # isort: skip
from nodriver.core.connection import ProtocolException
@@ -34,10 +34,19 @@ LOG.setLevel(loggers.INFO)
PUBLISH_MAX_RETRIES:Final[int] = 3
_NUMERIC_IDS_RE:Final[re.Pattern[str]] = re.compile(r"^\d+(,\d+)*$")
_LOGIN_DETECTION_SELECTORS:Final[list[tuple["By", str]]] = [
(By.CLASS_NAME, "mr-medium"),
(By.ID, "user-email"),
]
_LOGIN_DETECTION_SELECTOR_LABELS:Final[tuple[str, ...]] = ("user_info_primary", "user_info_secondary")
colorama.just_fix_windows_console()
def _format_login_detection_selectors(selectors:Sequence[tuple["By", str]]) -> str:
return ", ".join(f"{selector_type.name}={selector_value}" for selector_type, selector_value in selectors)
class AdUpdateStrategy(enum.Enum):
REPLACE = enum.auto()
MODIFY = enum.auto()
@@ -1245,38 +1254,39 @@ class KleinanzeigenBot(WebScrapingMixin): # noqa: PLR0904
login_check_timeout,
effective_timeout,
)
login_selectors = [
(By.CLASS_NAME, "mr-medium"),
(By.ID, "user-email"),
]
primary_selector_index = 0
tried_login_selectors = _format_login_detection_selectors(_LOGIN_DETECTION_SELECTORS)
try:
user_info, matched_selector = await self.web_text_first_available(
login_selectors,
_LOGIN_DETECTION_SELECTORS,
timeout = login_check_timeout,
key = "login_detection",
description = "login_detection(selector_group)",
)
if username in user_info.lower():
if matched_selector == primary_selector_index:
LOG.debug("Login detected via .mr-medium element")
else:
LOG.debug("Login detected via #user-email element")
matched_selector_label = (
_LOGIN_DETECTION_SELECTOR_LABELS[matched_selector]
if 0 <= matched_selector < len(_LOGIN_DETECTION_SELECTOR_LABELS)
else f"selector_index_{matched_selector}"
)
LOG.debug("Login detected via login detection selector '%s'", matched_selector_label)
return True
except TimeoutError:
LOG.debug("Timeout waiting for login detection selector group after %.1fs", effective_timeout)
if not include_probe:
LOG.debug("No login detected - neither .mr-medium nor #user-email found with username")
LOG.debug("No login detected via configured login detection selectors (%s)", tried_login_selectors)
return False
state = await self._auth_probe_login_state()
if state == LoginState.LOGGED_IN:
return True
LOG.debug("No login detected - DOM elements not found and server probe returned %s", state.name)
LOG.debug(
"No login detected - DOM login detection selectors (%s) did not confirm login and server probe returned %s",
tried_login_selectors,
state.name,
)
return False
async def _fetch_published_ads(self) -> list[dict[str, Any]]:

View File

@@ -97,11 +97,8 @@ kleinanzeigen_bot/__init__.py:
is_logged_in:
"Starting login detection (timeout: %.1fs base, %.1fs effective with multiplier/backoff)": "Starte Login-Erkennung (Timeout: %.1fs Basis, %.1fs effektiv mit Multiplikator/Backoff)"
"Login detected via .mr-medium element": "Login erkannt über .mr-medium Element"
"Login detected via #user-email element": "Login erkannt über #user-email Element"
"Login detected via login detection selector '%s'": "Login erkannt über Login-Erkennungs-Selektor '%s'"
"Timeout waiting for login detection selector group after %.1fs": "Timeout beim Warten auf die Login-Erkennungs-Selektorgruppe nach %.1fs"
"No login detected - neither .mr-medium nor #user-email found with username": "Kein Login erkannt - weder .mr-medium noch #user-email mit Benutzername gefunden"
"No login detected - DOM elements not found and server probe returned %s": "Kein Login erkannt - DOM-Elemente nicht gefunden und Server-Probe ergab %s"
handle_after_login_logic:
"# Device verification message detected. Please follow the instruction displayed in the Browser.": "# Nachricht zur Geräteverifizierung erkannt. Bitte den Anweisungen im Browser folgen."