腾讯/金山文档「导出为」菜单选择器过期排查 #148
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
背景
#49 扫码登录运维验收时发现: 登录态已真实生效(cookies 落盘 + .bak 备份 + 进入文档页面交互阶段), 但同步导出步骤在两家文档都失败:
shared_doc_sync_service.py:229):Page.hover: Timeout 30000ms exceeded - waiting for locator("text=导出为")shared_doc_sync_service.py:283):RuntimeError: 菜单中未找到'导出为'入口(金山前端可能变动)关键判据: 两家都未触发 L96
FileNotFoundError("未找到登录态")—— 说明登录态真实生效, 失败发生在文档菜单交互层(已进入文档页面后才失败)。影响范围
backend/app/services/shared_doc_sync_service.py_export_tencent函数(hover "导出为" → 点"本地Excel表格 (.xlsx)")_export_kdocs函数(JS 精确定位"导出为"叶子节点 → 点"导出为 Excel(.xlsx)")根因判断(待实测确认)
三种可能性, 需实测排查:
text=导出为简单文本匹配, 金山用 JSinnerText.trim() === '导出为' && children.length===0—— 若前端把"导出为"包了一层 icon 或改成按钮, 两套选择器都失效处理动作 / 设计要求
tencent_doc.json/kdocs.json登录态, 起有头浏览器打开两家文档page.hover("text=导出为")的 locatorpage.wait_for_selector(..., state="visible", timeout=10000)显式等待BROWSER_STATE_DIR/.export_debug_*.png便于后续排查sync_one_source对两家文档, 验证能成功导出 .xlsx 并入库tests/test_shared_doc_sync_export.py用 monkeypatch 打桩浏览器层, 覆盖新选择器验收标准 / 关闭条件
sync_one_source对两家文档都 status=success/partial(不再 hover 超时/菜单未找到)关联
backend/app/services/shared_doc_sync_service.py:197-290/app/data/browser_states/tencent_doc.json+kdocs.json(2026-09-18 11:19 用户扫码生成)scripts/tencent_doc_login.py(.dockerignore排除, 需 docker cp 进容器)关闭凭证核验 (2026-09-18)
根因结论
本次「导出为」菜单选择器过期排查的实际根因比预期更深一层:
text=导出为30s 超时 / 金山 JS 定位叶子节点失败。Playwright sync API 直接跑在 FastAPI 线程池 →
asyncio.get_running_loop()报错/会话互斥;且扫码后金山停在
account.wps.cn/v1/chooseaccount选账号中间页, 选账号按钮无头浏览器里点不到 → 登录态永远拿不到 → 导出必然失败(即 #49 里的「登录态生效但导出失败」其实是
访客态被误判为登录态)。
goto doc_url重新加载页面, 冲掉扫码后刚写好的
__WPSENV__.user.id/ skey → 真实登录态被误判为访客。(无需再改菜单选择器 — 原
_TENCENT_MENU_XY坐标与金山.app-header-more-btn均有效)。docker logs csctalon-backend): 金山扫码后verify(当前页) url=account.wps.cn/v1/chooseaccount; 修复后verify(当前页) url=www.kdocs.cn/l/cbzihtt6obyf is_guest=False uid=8231334; 腾讯verify(当前页) url=docs.qq.com is_guest=False+ cookies 含 uid/TOKshared_doc_sync_service.pyL256-258 腾讯 ribbon-toolbar 说明 +_TENCENT_MENU_XY坐标保留加守卫; L334 金山改page.locator(".app-header-more-btn").first.click()(commit 含 #148); 容器内 grep 证实app-header-more-btn=TruePOST /api/v1/sync/shared-docs/sync-now: 金山(source_id=2)status=partial total=4545 inserted=1; 腾讯(source_id=1)status=success投诉 2698 行/卡商 768 行, 均不再 hover 超时/菜单未找到shared_doc_sync_service.py全函数wait_for_selector+ 失败截图_save_debug_screenshot→BROWSER_STATE_DIR/.export_debug_*.png(容器内可见 .export_debug_tencent_guest_.png / .export_debug_kdocs_guest_.png); 测试test_screenshot_saved_on_failure覆盖tests/test_shared_doc_login.py+tests/test_shared_doc_sync_export.py:54 passed(pytest);ruff check全过app-header-more-btn=True _check_tencent_guest=True 金山中间页DOM dump=True _SessionWorker=True; 登录态文件tencent_doc.json(21 cookies, uid/TOK) +kdocs.json(39 cookies, wps_sid) 时间戳 2026-09-18 08:04/08:06; 部署版本git-20260918160235附加修复(页面内扫码登录打通, 工单原始诉求 #45/#49 的延续)
shared_doc_login_service.py重构为_SessionWorker专属线程模型, 根治 Playwright syncAPI 在 FastAPI 线程池的 asyncio 冲突(commit
a642e2b后多笔含 #148)18097a9)storage_state读取完全一致(tencent_doc.json / kdocs.json)结论
两家文档从扫码登录到端到端同步入库全链路已在生产验证通过, 工单逐条核验完成, 申请关闭。