fix(tencent): 修正登录完成判定顺序——移除 qrconnect iframe 前置误判,改为发表视频按钮/平台页优先;扫码与过期检测穿透 iframe,修复扫码后无反馈、登录成功后二维码不销毁

This commit is contained in:
Qiufeng
2026-08-21 18:45:15 +08:00
parent b96de7a2d2
commit a7348495c9
+42 -32
View File
@@ -298,20 +298,13 @@ async def _has_tencent_login_cookie(context) -> bool:
async def _is_tencent_login_completed(page: Page, context=None) -> bool: async def _is_tencent_login_completed(page: Page, context=None) -> bool:
current_url = page.url or "" current_url = page.url or ""
# 1) 仍在登录页 => 未完成(即使 sessionid 已种下,登录流程尚未走完:可能在选号/跳转中) is_platform = (
if "login.html" in current_url: current_url.startswith(TENCENT_HOME_URL)
return False or current_url.startswith(TENCENT_UPLOAD_URL)
or current_url.startswith(TENCENT_MANAGE_URL)
)
# 2) 页面仍有 qrconnect 扫码 iframe => 未完成登录(登录态不完整会残留扫码框) # 1) 平台首页出现「发表视频」按钮 => 登录完整(最可靠,优先)
try:
for fr in page.frames:
if "open.weixin.qq.com/connect/qrconnect" in (fr.url or ""):
return False
except Exception:
pass
# 3) 平台首页出现「发表视频」按钮 => 登录完整(最可靠标志)
# (不完整登录时页面会延迟弹扫码框、且无发表入口)
try: try:
publish_entry = page.locator("button.weui-desktop-btn", has_text="发表视频").first publish_entry = page.locator("button.weui-desktop-btn", has_text="发表视频").first
if await publish_entry.count() and await publish_entry.is_visible(): if await publish_entry.count() and await publish_entry.is_visible():
@@ -319,29 +312,24 @@ async def _is_tencent_login_completed(page: Page, context=None) -> bool:
except Exception: except Exception:
pass pass
# 4) localStorage 已有视频号身份(finder_username 非空)=> 登录完整 # 2) 已跳到平台页且无 qrconnect 扫码 iframe => 登录完成
# 注意:登录中的二维码本就嵌在 qrconnect iframe 里,不能把「iframe 存在」当作未登录;
# 只有「平台页 + 扫码 iframe 仍在」才视为登录态不完整(页面弹了扫码框)
if is_platform:
try: try:
finder_username = await page.evaluate("localStorage.getItem('finder_username')") has_qr_iframe = any("open.weixin.qq.com/connect/qrconnect" in (fr.url or "") for fr in page.frames)
if finder_username:
return True
except Exception: except Exception:
pass has_qr_iframe = False
if not has_qr_iframe:
# 5) 已跳到平台页(首页/发布页/列表页)且无可见二维码容器 => 成功 return True
if current_url.startswith(TENCENT_HOME_URL) or current_url.startswith(TENCENT_UPLOAD_URL) or current_url.startswith(TENCENT_MANAGE_URL): # 平台页但扫码 iframe 仍在 => 登录态不完整,视为未完成
for marker in [
page.locator("div.login-qrcode-wrap").first,
page.locator("div.qrcode-wrap").first,
page.locator('span:has-text("微信扫码登录 视频号助手")').first,
]:
try:
if await marker.count() and await marker.is_visible():
return False return False
except Exception:
continue
return True
# 6) cookie 兜底(已离开登录页且无扫码框) # 3) 仍在登录页 => 未完成
if "login.html" in current_url:
return False
# 4) cookie 兜底(sessionid 已种下,可能正处于跳转中间态)
if context is not None and await _has_tencent_login_cookie(context): if context is not None and await _has_tencent_login_cookie(context):
return True return True
@@ -355,6 +343,7 @@ async def _is_tencent_qrcode_expired(page: Page) -> bool:
'p.refresh-tip:has-text("二维码已过期,点击刷新")', 'p.refresh-tip:has-text("二维码已过期,点击刷新")',
'p.refresh-tip:has-text("网络不可用,点击刷新")', 'p.refresh-tip:has-text("网络不可用,点击刷新")',
] ]
# 1) 主页面
for selector in tip_selectors: for selector in tip_selectors:
tip = page.locator(selector).first tip = page.locator(selector).first
try: try:
@@ -362,6 +351,16 @@ async def _is_tencent_qrcode_expired(page: Page) -> bool:
return True return True
except Exception: except Exception:
continue continue
# 2) qrconnect iframe 内部(过期/刷新提示显示在 iframe 里)
for fr in page.frames:
if "open.weixin.qq.com/connect/qrconnect" not in (fr.url or ""):
continue
try:
txt = await fr.evaluate("() => document.body ? document.body.innerText : ''")
if any(k in txt for k in ["二维码已过期", "已失效", "点击刷新", "重新扫码"]):
return True
except Exception:
continue
return False return False
@@ -370,6 +369,7 @@ async def _is_tencent_qrcode_scanned(page: Page) -> bool:
'div.qr-tip div:has-text("已扫码")', 'div.qr-tip div:has-text("已扫码")',
'div.qr-tip div:has-text("需在手机上进行确认")', 'div.qr-tip div:has-text("需在手机上进行确认")',
] ]
# 1) 主页面
for selector in scanned_tips: for selector in scanned_tips:
tip = page.locator(selector).first tip = page.locator(selector).first
try: try:
@@ -377,6 +377,16 @@ async def _is_tencent_qrcode_scanned(page: Page) -> bool:
return True return True
except Exception: except Exception:
continue continue
# 2) qrconnect iframe 内部(扫码状态显示在 iframe 里)
for fr in page.frames:
if "open.weixin.qq.com/connect/qrconnect" not in (fr.url or ""):
continue
try:
txt = await fr.evaluate("() => document.body ? document.body.innerText : ''")
if any(k in txt for k in ["已扫码", "扫码成功", "确认登录", "请在手机上确认"]):
return True
except Exception:
continue
return False return False