From 44cbe8e2aa8bce60117d6927d40f3e6654926256 Mon Sep 17 00:00:00 2001 From: butubb <1422726308@qq.com> Date: Fri, 9 Oct 2026 13:49:11 +0800 Subject: [PATCH] =?UTF-8?q?fix(monitor):=20=E5=B7=B2=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=97=B6=E7=82=B9=E3=80=8C=E5=90=8C=E6=AD=A5=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=80=81=E4=B8=BA=20Cookie=E3=80=8D=E8=A6=81=E5=B9=B2=E7=AD=89?= =?UTF-8?q?=2030=20=E7=A7=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 顺序反了:原先先开页面、读二维码,读完才发现「已经登录、没有二维码」。而读二维码内部 会 wait_for_selector 等满 30 秒才放弃 —— 用户点一下按钮要干等半分钟,还白开一个标签页。 实测日志里就是 `Page.wait_for_selector: Timeout 30000ms exceeded`。 改成先问登录状态(那是一次接口调用,很快),已登录就直接返回,根本不碰页面。 新增测试守住这个顺序:已登录时 context.new_page 不得被调用。 --- api/monitor/qrlogin.py | 30 ++++++++++++++++++------------ tests/test_qrlogin.py | 15 +++++++++++++++ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/api/monitor/qrlogin.py b/api/monitor/qrlogin.py index 81ca128..b214792 100644 --- a/api/monitor/qrlogin.py +++ b/api/monitor/qrlogin.py @@ -331,6 +331,23 @@ async def start(platform: str = PLATFORM_XHS) -> Dict[str, Any]: async with _lock: await _discard_current_locked() + # **先问状态,再决定要不要开页面。** 顺序反过来是有代价的:读二维码内部会 + # wait_for_selector 等满 30 秒才放弃,而已经登录时页面上根本没有二维码 —— + # 用户点一下按钮要干等半分钟,还白开一个标签页。 + state = await check_login_state(force=True) + if state.get("logged_in"): + # 已经是登录状态时站点不显示二维码 —— 这本身就是成功,不是失败。 + # 顺带把 cookie 取出来,让调用方可以存进库。 + session = QrLoginSession(platform, None) + session.cookie = await _current_cookie() + session.status = STATUS_SUCCESS + session.logged_in = True + session.nickname = state.get("nickname") + who = f"({session.nickname})" if session.nickname else "" + session.message = f"浏览器已经是登录状态{who},无需扫码" + _current = session + return session.snapshot() + page = await _ensure_page(platform) try: await page.goto( @@ -342,18 +359,7 @@ async def start(platform: str = PLATFORM_XHS) -> Dict[str, Any]: session = QrLoginSession(platform, page) session.image = image - - state = await check_login_state() - if state.get("logged_in"): - # 已经是登录状态时站点不显示二维码——这本身就是成功,不是失败。 - # 顺带把 cookie 取出来,让调用方可以存进库。 - session.cookie = await _current_cookie() - session.status = STATUS_SUCCESS - session.logged_in = True - session.nickname = state.get("nickname") - who = f"({session.nickname})" if session.nickname else "" - session.message = f"浏览器已经是登录状态{who},无需扫码" - elif not image: + if not image: session.status = STATUS_ERROR session.message = "页面上没找到二维码,请确认站点结构没有变化" diff --git a/tests/test_qrlogin.py b/tests/test_qrlogin.py index 0f6c463..5f977a5 100644 --- a/tests/test_qrlogin.py +++ b/tests/test_qrlogin.py @@ -140,6 +140,21 @@ async def test_an_already_signed_in_profile_needs_no_scan(monkeypatch): assert snapshot["nickname"] == "老王" +@pytest.mark.asyncio +async def test_an_already_signed_in_profile_never_opens_a_page(monkeypatch): + """已登录时**根本不该去开页面**。 + + 读二维码内部会 wait_for_selector 等满 30 秒才放弃,而已经登录时页面上没有二维码 —— + 顺序反了的话,用户点一下按钮要干等半分钟,还白开一个标签页。 + """ + manager, _pw, _browser, context, _page, _qr = _fake_stack() + _patch(monkeypatch, manager, resolver=lambda _c: {"user_id": "u1", "nickname": "小明"}) + + await qrlogin.start(qrlogin.PLATFORM_XHS) + + context.new_page.assert_not_called() + + @pytest.mark.asyncio async def test_no_qr_and_not_signed_in_is_an_error(monkeypatch): manager, *_rest = _fake_stack()