- BT a mutat login-ul (09.2026): go.bancatransilvania.ro face 302 spre marketing; formularul e pe goapp.bancatransilvania.ro, acelasi tab, fara popup. - Daca formularul nu apare: eroare explicita cu URL/titlu + screenshot/HTML. - scripts/check_login_page.py: verifica pagina de login fara credentiale. - Download: asteapta documentul nou din "Recente"; export gol -> [SKIP], nu timeout. - Screenshot la eroare facut inainte de oprirea Playwright. - opencode.json: agentii opencode nu pot citi .env. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DxPhZABSUf1RJXRWtwecqC
183 lines
5.7 KiB
Python
183 lines
5.7 KiB
Python
"""
|
|
Verifica daca pagina de login BT e inca la fel (campuri user/parola/submit).
|
|
|
|
Fara credentiale, fara .env: doar deschide pagina de login ca scraper-ul,
|
|
o observa si iese cu cod 0 daca formularul e intact, altfel 1 + motivul.
|
|
Nu completeaza campuri si nu submite nimic.
|
|
|
|
Chromium e lansat identic cu btgo_scraper.py (noul mod headless
|
|
--headless=new + UA de Chrome normal), altfel WAF-ul Akamai al BT raspunde
|
|
cu Access Denied. Nu folosim networkidle (nu se atinge niciodata pe site-ul
|
|
BT) -> domcontentloaded + asteptari pe selector.
|
|
|
|
Nota: lansarea browserului e duplicata din btgo_scraper.run() pentru ca
|
|
acolo e inline si btgo_scraper importa config (care citeste .env). Daca
|
|
lansarea va fi extrasa intr-un helper fara config, scriptul il poate importa.
|
|
"""
|
|
|
|
import sys
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeout
|
|
|
|
# Aceleasi intrari ca in btgo_scraper.login() (ordinea conteaza).
|
|
LOGIN_ENTRY_URLS = [
|
|
"https://goapp.bancatransilvania.ro/",
|
|
"https://go.bancatransilvania.ro/",
|
|
]
|
|
|
|
USER_SELECTORS = ["input#user", "input[placeholder='ID logare']"]
|
|
PASSWORD_SELECTORS = ["input#password", "input[type='password']"]
|
|
SUBMIT_SELECTORS = [
|
|
"input[type='submit']",
|
|
"button[type='submit']",
|
|
"input[value*='Autentific']",
|
|
]
|
|
|
|
DATA_DIR = Path("data")
|
|
|
|
|
|
def launch(p):
|
|
"""Lanseaza Chromium exact ca btgo_scraper.run() (WAF-safe)."""
|
|
browser = p.chromium.launch(
|
|
headless=False,
|
|
slow_mo=0,
|
|
args=[
|
|
"--window-size=1366,768",
|
|
"--disable-gpu",
|
|
"--disable-dev-shm-usage",
|
|
"--disable-extensions",
|
|
"--disable-background-networking",
|
|
"--disable-renderer-backgrounding",
|
|
"--disable-features=Translate",
|
|
"--headless=new",
|
|
],
|
|
)
|
|
context = browser.new_context(
|
|
viewport={"width": 1366, "height": 768},
|
|
user_agent=(
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
|
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
|
"Chrome/130.0.0.0 Safari/537.36"
|
|
),
|
|
)
|
|
return browser, context
|
|
|
|
|
|
def first_visible(page, selectors, timeout=1000):
|
|
"""Primul selector din lista care are un element vizibil, sau None."""
|
|
for sel in selectors:
|
|
try:
|
|
el = page.locator(sel).first
|
|
if el.count() and el.is_visible(timeout=timeout):
|
|
return sel
|
|
except Exception:
|
|
continue
|
|
return None
|
|
|
|
|
|
def dump_diag(page):
|
|
"""Salveaza HTML + screenshot pentru diagnostic. Returneaza caile scrise."""
|
|
written = []
|
|
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
try:
|
|
DATA_DIR.mkdir(exist_ok=True)
|
|
except Exception:
|
|
return written
|
|
try:
|
|
html_path = DATA_DIR / f"check_login_page_{ts}.html"
|
|
html_path.write_text(page.content(), encoding="utf-8")
|
|
written.append(html_path)
|
|
except Exception:
|
|
pass
|
|
try:
|
|
shot_path = DATA_DIR / f"check_login_page_{ts}.png"
|
|
page.screenshot(path=str(shot_path))
|
|
written.append(shot_path)
|
|
except Exception:
|
|
pass
|
|
return written
|
|
|
|
|
|
def check_page(page, url):
|
|
"""Navigheaza la `url` si inspecteaza formularul. Returneaza un dict."""
|
|
info = {
|
|
"ok": False,
|
|
"url": url,
|
|
"final_url": None,
|
|
"title": None,
|
|
"user": None,
|
|
"password": None,
|
|
"submit": None,
|
|
"error": None,
|
|
}
|
|
print(f"[check] {url}")
|
|
|
|
try:
|
|
page.goto(url, wait_until="domcontentloaded", timeout=30000)
|
|
except Exception as e:
|
|
info["error"] = f"goto a esuat: {e}"
|
|
print(f" [WARN] {info['error']}")
|
|
return info
|
|
|
|
try:
|
|
page.wait_for_selector(
|
|
", ".join(USER_SELECTORS), timeout=60000, state="visible"
|
|
)
|
|
except PlaywrightTimeout:
|
|
info["final_url"] = page.url
|
|
info["title"] = page.title()
|
|
info["error"] = "formularul de login (input#user) nu a aparut"
|
|
print(f" [WARN] {info['error']} (URL final: {info['final_url']})")
|
|
return info
|
|
|
|
info["final_url"] = page.url
|
|
info["title"] = page.title()
|
|
info["user"] = first_visible(page, USER_SELECTORS)
|
|
info["password"] = first_visible(page, PASSWORD_SELECTORS)
|
|
info["submit"] = first_visible(page, SUBMIT_SELECTORS)
|
|
info["ok"] = bool(info["user"] and info["password"] and info["submit"])
|
|
|
|
print(f" URL final: {info['final_url']}")
|
|
print(f" titlu: {info['title']!r}")
|
|
print(f" user: {info['user']!r}")
|
|
print(f" parola: {info['password']!r}")
|
|
print(f" submit: {info['submit']!r}")
|
|
return info
|
|
|
|
|
|
def main():
|
|
with sync_playwright() as p:
|
|
browser, context = launch(p)
|
|
try:
|
|
page = context.new_page()
|
|
last = None
|
|
for url in LOGIN_ENTRY_URLS:
|
|
info = check_page(page, url)
|
|
if info["ok"]:
|
|
print("[OK] Pagina de login e intacta "
|
|
"(campuri user/parola/submit gasite).")
|
|
return 0
|
|
last = info
|
|
|
|
written = dump_diag(page)
|
|
missing = [k for k in ("user", "password", "submit")
|
|
if not last.get(k)]
|
|
print("[FAIL] Pagina de login BT s-a schimbat.")
|
|
print(f" URL final: {last.get('final_url')}, "
|
|
f"titlu: {last.get('title')!r}")
|
|
if last.get("error"):
|
|
print(f" Motiv: {last['error']}")
|
|
if missing:
|
|
print(f" Campuri lipsa: {', '.join(missing)}")
|
|
for path in written:
|
|
print(f" Dovezi: {path}")
|
|
return 1
|
|
finally:
|
|
browser.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|