capture_bypwd_v2.py 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. """Capture byPwd response via page.expect_response (works while page is still open).
  2. Returns the actual response body so we can see if we got a real JWT.
  3. """
  4. import asyncio
  5. import json
  6. import sys
  7. from pathlib import Path
  8. _HERE = Path(__file__).resolve().parent
  9. sys.path.insert(0, str(_HERE.parent / "src"))
  10. from cq2_sdk.env_loader import load_env
  11. load_env(_HERE.parent / ".env")
  12. from cq2_sdk.store import UserStore, connection
  13. from cq2_sdk.debug_log import DebugLogger
  14. EDGE = r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
  15. URL = "https://pc.hzwlan.com/login/account"
  16. async def main():
  17. log = DebugLogger(extra={"task": "capture_bypwd_v2"})
  18. from playwright.async_api import async_playwright
  19. async with async_playwright() as p:
  20. browser = await p.chromium.launch(executable_path=EDGE, headless=True)
  21. ctx = await browser.new_context(viewport={"width": 1366, "height": 768})
  22. page = await ctx.new_page()
  23. await page.goto(URL, wait_until="networkidle", timeout=30000)
  24. await page.evaluate(
  25. "([u, p]) => {"
  26. " const setVal = (sel, v) => {"
  27. " const el = document.querySelector(sel);"
  28. " Object.getOwnPropertyDescriptor("
  29. " window.HTMLInputElement.prototype, 'value').set.call(el, v);"
  30. " el.dispatchEvent(new Event('input', {bubbles: true}));"
  31. " };"
  32. " setVal('input#username', u);"
  33. " setVal('input#password', p);"
  34. " const btn = document.querySelector("
  35. " 'button.login-form_box__submit_button');"
  36. " if (btn) { btn.disabled = false; btn.classList.remove('disabled'); }"
  37. "}",
  38. ["longwu988", "Longwu1988"],
  39. )
  40. await page.wait_for_timeout(300)
  41. # expect_response captures while page is alive; the response handle
  42. # is awaitable after the context exits.
  43. async with page.expect_response("**/auth/v3/login/safe/byPwd") as resp_info:
  44. await page.locator(
  45. "button.login-form_box__submit_button"
  46. ).first.click(force=True)
  47. # Don't wait_timeout here - we want to catch the response when it arrives
  48. response = await resp_info.value
  49. status = response.status
  50. body = await response.text()
  51. await browser.close()
  52. print(f"=== byPwd response ===")
  53. print(f"status: {status}")
  54. print(f"body ({len(body)} chars): {body[:1500]}")
  55. if not body:
  56. print("no body")
  57. return
  58. try:
  59. data = json.loads(body)
  60. print(f"\nparsed keys: {list(data.keys())}")
  61. token = data.get("data", {}).get("token", "")
  62. if token:
  63. print(f"\n*** TOKEN FOUND ({len(token)} chars) ***")
  64. print(f" preview: {token[:50]}...")
  65. with connection() as conn:
  66. u = UserStore(conn).get_by_username("longwu988")
  67. if u:
  68. UserStore(conn).update_token(user_id=u.id, token=token)
  69. print(f" saved to MySQL users.id={u.id}")
  70. else:
  71. print(" user longwu988 not in MySQL; run scaffold first")
  72. else:
  73. print(f"\nno token in response: code={data.get('code')}, msg={data.get('msg')}")
  74. except Exception as e:
  75. print(f"\nJSON parse error: {e}")
  76. asyncio.run(main())