[Python] Selenium cannot log in to ZTE ZXHN H298A modem admin panel despite correct credentials

Discussão em 'Python' iniciado por Stack, Agosto 13, 2025.

  1. Stack

    Stack Membro Participativo

    I am trying to automate the login and PPP credential update process for a ZTE ZXHN H298A modem (firmware TTN.26_240416) using Selenium and Python.

    The exact manual steps are:

    • Open the modem’s web interface at http://192.168.5.1.
    • Enter username/password (admin / admin) and log in.
    • Click the WAN tab at the top of the interface.
    • Select WAN Connections from the left-hand menu.
    • In the center panel, expand the INTERNET entry.
    • Update PPP Username and PPP Password fields.
    • Click Apply.

    My goal is to perform these steps programmatically and reliably with Selenium, without manual interaction.

    I am running the script like this:

    py "Modem Refurbishment App/scripts/zte_ppp_selenium.py" \
    --ip 192.168.5.1 \
    --user admin \
    --pass admin \
    --headful \
    --prelogin-delay-sec 10


    Problem:

    Even though I provide the correct credentials, Selenium fails to complete the login step. The modem’s admin panel remains at the login page.

    I have checked:

    • Credentials are correct (I can log in manually).
    • The login form fields are being filled by Selenium.
    • The modem’s UI uses dynamic content loading (AJAX) after login.
    • The script tries both JS-based and click-based form submission

    Additional requirement:

    When running in headful mode, I pause after Selenium fills in the username and password so I can see the login screen with the credentials filled in inside the browser.

    In addition to this, I also want to be able to see the interface after a successful login, including the admin menu and subsequent navigation steps inside the browser while the script continues executing.

    Questions:

    • Are there any known quirks or anti-automation measures in ZTE modem firmware that would block Selenium login?
    • Is there a reliable way in Selenium to handle this kind of dynamic login (possibly involving hidden tokens or delayed AJAX form handling)?
    • Could the modem require additional request headers or cookies that Selenium is not sending by default?

    Environment:

    • Python 3.x
    • Selenium 4.x
    • Chrome + matching ChromeDriver
    • ZTE ZXHN H298A modem, firmware TTN.26_240416

    Here is a more simple sample script:

    import time
    import os
    import tempfile
    import logging
    import argparse
    from datetime import datetime
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.by import By
    from selenium.webdriver.common.keys import Keys

    ROUTER_URL = "http://192.168.5.1/"
    USERNAME = "admin"
    PASSWORD = "admin"
    LOGIN_TIMEOUT_SEC = 15

    def setup_driver(headless=True):
    options = Options()
    if headless:
    options.add_argument("--headless=new")
    options.add_argument("--disable-gpu")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-dev-shm-usage")
    driver = webdriver.Chrome(options=options) # Selenium Manager auto-downloads driver
    return driver

    def login(driver, base_url: str, username: str, password: str, pause_before_submit: float = 0.0):
    driver.get(base_url)
    time.sleep(1)
    user_el = driver.find_element(By.ID, "Frm_Username")
    pass_el = driver.find_element(By.ID, "Frm_Password")
    try:
    user_el.clear()
    pass_el.clear()
    except Exception:
    pass
    user_el.send_keys(username.strip())
    pass_el.send_keys(password.strip())
    if pause_before_submit > 0:
    logging.info("Pausing %.1fs before submit so you can visually confirm fields...", pause_before_submit)
    time.sleep(pause_before_submit)
    driver.find_element(By.ID, "LoginId").click()
    time.sleep(2)

    def verify_login(driver) -> bool:
    # Poll for either explicit error or solid success indicators
    end = time.time() + LOGIN_TIMEOUT_SEC
    had_sid = False
    error_visible = False
    login_form_visible = True
    has_admin_indicators = False

    while time.time() < end:
    # Cookies
    had_sid = any(
    (c.get("name", "").upper() == "SID" and c.get("value")) for c in driver.get_cookies()
    )

    # Page content checks
    src = driver.page_source
    low = src.lower()

    # Login form presence
    try:
    elem = driver.find_element(By.ID, "Frm_Username")
    login_form_visible = elem.is_displayed()
    except Exception:
    login_form_visible = False

    # Error banner must be visible to count (initial banner may be present in DOM by default)
    try:
    err_el = driver.find_element(
    By.XPATH,
    "//*[contains(text(),'Kullanıcı') and contains(text(),'şifre') and (contains(text(),'hatalı') or contains(text(),'yanlış'))]",
    )
    error_visible = err_el.is_displayed()
    except Exception:
    error_visible = False

    # Admin indicators
    has_admin_indicators = any(
    k in low for k in [
    "çıkış",
    "logout",
    "mainnavigator",
    "menu",
    "systeminfo",
    "wanstatedev",
    ]
    )

    # Success: SID + no visible login form OR strong admin indicators
    if had_sid and (not login_form_visible or has_admin_indicators):
    break

    time.sleep(0.5)

    # Save diagnostics to a stable path near this script
    ts = datetime.now().strftime("%Y%m%d_%H%M%S")
    script_dir = os.path.dirname(os.path.abspath(__file__))
    out_dir = os.path.join(script_dir, "selenium_debug")
    os.makedirs(out_dir, exist_ok=True)
    screenshot_path = os.path.join(out_dir, f"login_result_{ts}.png")
    html_path = os.path.join(out_dir, f"login_result_{ts}.html")

    screenshot_ok = False
    html_ok = False
    try:
    driver.save_screenshot(screenshot_path)
    screenshot_ok = os.path.exists(screenshot_path)
    except Exception as e:
    logging.error("Failed to save screenshot: %s", e)
    try:
    with open(html_path, "w", encoding="utf-8") as f:
    f.write(driver.page_source)
    html_ok = os.path.exists(html_path)
    except Exception as e:
    logging.error("Failed to save HTML: %s", e)

    if screenshot_ok:
    logging.info("Saved screenshot: %s", screenshot_path)
    else:
    logging.warning("Screenshot not saved: %s", screenshot_path)
    if html_ok:
    logging.info("Saved HTML: %s", html_path)
    else:
    logging.warning("HTML not saved: %s", html_path)

    success = had_sid and (not login_form_visible or has_admin_indicators)
    if success:
    logging.info(
    "Login SUCCESS | SID=%s | AdminIndicators=%s | LoginFormVisible=%s",
    had_sid,
    has_admin_indicators,
    login_form_visible,
    )
    else:
    if error_visible and login_form_visible:
    logging.warning("Login FAILED due to on-page error | SID=%s", had_sid)
    else:
    logging.warning("Login NOT confirmed | SID=%s (no error banner)", had_sid)
    logging.warning(
    "Login NOT confirmed | SID=%s | AdminIndicators=%s | LoginFormVisible=%s",
    had_sid,
    has_admin_indicators,
    login_form_visible,
    )
    return success

    if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO, format="%(asctime)s | %(levelname)s | %(message)s")

    parser = argparse.ArgumentParser(description="ZTE router login verifier (selenium)")
    parser.add_argument("--headful", action="store_true", help="Show browser window (disable headless mode)")
    parser.add_argument("--router-url", default=ROUTER_URL, help="Router base URL")
    parser.add_argument("--user", default=USERNAME, help="Admin username")
    parser.add_argument("--passw", default=PASSWORD, help="Admin password")
    parser.add_argument("--pause-before-submit", type=float, default=0.0, help="Pause (seconds) after typing credentials, before clicking login")
    args, _ = parser.parse_known_args()

    driver = setup_driver(headless=(not args.headful))
    try:
    login(driver, args.router_url, args.user, args.passw, pause_before_submit=args.pause_before_submit)
    success = verify_login(driver)
    if not success:
    raise SystemExit(2)
    finally:
    driver.quit()


    I see that the correct username and password have been entered as admin in the browser, but the browser doesn't go past the login page. The script logs say the login was successful, but I can't find the PPP username and password information in the relevant menus. Therefore, I can't be sure that I'm actually logged in. I can manually login with the same credentials.

    Continue reading...

Compartilhe esta Página