120 lines
8.8 KiB
Markdown
120 lines
8.8 KiB
Markdown
---
|
||
id: T-632
|
||
title: ①采集短标题就绪识别与页面错误诊断修复
|
||
phase: 2
|
||
deps: [T-404b, T-630]
|
||
status: TODO
|
||
created: 2026-07-14
|
||
---
|
||
|
||
## 问题 / 背景
|
||
|
||
最新代码采集商品 `48363984966` 时,账号 Chrome/CDP 连通正常,程序打开的商品详情 tab 也已加载成功,但任务在约 63 秒后失败:
|
||
|
||
```text
|
||
step=wait_ready result=failed
|
||
detail=等待蝦皮商品编辑器就绪超时:此物流選項不支援較長備貨商品
|
||
```
|
||
|
||
运行事件只进入 `open_product -> wait_ready`,尚未执行 `read_title`、`read_cover` 或 `download_cover`。用户导出的商品图片区域 HTML 与实时只读 CDP 探查确认:
|
||
|
||
- 主图区域存在 `data-product-edit-field-unique-id="images"`,其中有 5 个可拖拽 `.shopee-image-manager__itembox`;5 张图片均已取得 `susercontent` CDN 地址。
|
||
- 该业务字段范围内存在 1 个主图上传 input;当前 `read_cover_src()` 也能正常取得第一张封面 URL。因此图片未加载和封面下载不是本次失败原因。
|
||
- 页面商品名称输入框位于 `data-product-edit-field-unique-id="name"` 下,真实 `value/modelvalue` 长度为 20。
|
||
- `app/editor.py` 当前 `TITLE_XPATH` 使用 `string-length(@modelvalue)>24` 猜测标题输入框;该商品命中数为 0,导致 `JS_READY` 即使图片和上传入口均存在也持续返回 `false`。
|
||
- 用 `data-product-edit-field-unique-id="name"` 作为标题业务字段定位后,实时页面准确命中 1 个标题输入框,标题/5张图片/上传入口三项就绪判断立即为 `true`。
|
||
|
||
错误末尾的“此物流選項不支援較長備貨商品”不是页面未加载原因。`_open_product_ready_error()` 当前在没有商品失效 toast 时,会把缓存中的最后一条任意 toast 直接拼到就绪超时后面;物流、备货或表单校验提示因此可能被误报为采集失败根因。
|
||
|
||
## 方案
|
||
|
||
### 1. 标题输入框改用业务字段定位
|
||
|
||
- 标题主定位改为 `data-product-edit-field-unique-id="name"` 范围内的文本输入框,例如:
|
||
|
||
```xpath
|
||
//*[@data-product-edit-field-unique-id='name']
|
||
//input[contains(concat(' ', normalize-space(@class), ' '), ' eds-input__input ')]
|
||
```
|
||
|
||
- 不再用标题字符数判断输入框身份;1~24 字、空值编辑态和长标题都必须识别到同一个商品名称字段。
|
||
- 不使用“页面第一个 `.eds-input__input`”或中文 `商品名稱` label 作为唯一定位,避免规格、价格、库存输入框误命中和站点语言变化。
|
||
- 为兼容尚未带 `data-product-edit-field-unique-id` 的旧页面,在主定位不存在时才回退当前已验证的旧 XPath;主定位命中时不得再通过长度启发式改选其他输入框。
|
||
- 抽取单一标题定位事实,让 `JS_READY`、`JS_TITLE_STATE`、`read_title()` 和 `change_title()` 共用;禁止采集、就绪判断和③更新各维护一份不同选择器。
|
||
- 若主定位命中多个可见标题输入框,返回明确诊断并停止,不猜测写入其中任意一个。
|
||
|
||
### 2. 主图区域限定到 `images` 业务字段
|
||
|
||
- 商品主图优先限定在 `data-product-edit-field-unique-id="images"` 业务字段内,再读取:
|
||
- `.shopee-image-manager`;
|
||
- 可拖拽且 `data-draggable="true"` 的主图 itembox;
|
||
- `.shopee-image-manager__upload input[type=file]`。
|
||
- 实时页面全局共有多个文件 input,但 `images` 业务字段内只有 1 个主图上传入口;就绪判断、读取封面、图片矩形、上传状态和点击上传块必须指向同一个主图 manager,不能由全局 `querySelector()` 分别命中不同图片组件。
|
||
- 对缺少业务字段属性的旧页面保留现有 itembox/upload 选择器回退;回退只能在业务字段根不存在时启用。
|
||
- 本节只收敛选择范围,不改变③更新封面的删除第一张、上传、等待 CDN、拖到第一位和点击更新流程。
|
||
|
||
### 3. 就绪判断返回可诊断快照
|
||
|
||
- 将当前只返回布尔值的 `JS_READY` 扩展为共享的就绪状态快照,至少包含:
|
||
- 商品名称主定位/回退定位命中数;
|
||
- 主图业务字段是否存在;
|
||
- 已加载主图数量及 CDN/blob 概况;
|
||
- 主图上传 input 是否存在;
|
||
- 当前 URL。
|
||
- `_wait_ready()` 仍按现有最多 60 秒预算轮询,不增加固定 sleep、不切换 Chrome 前台;成功条件仍为标题字段、至少一张商品主图和主图上传入口同时存在。
|
||
- 超时时按最后快照给出具体中文原因,例如:
|
||
|
||
```text
|
||
商品编辑器未就绪:未识别商品名称输入框;商品图片5张;主图上传入口正常
|
||
```
|
||
|
||
- 诊断快照写入现有 `run_log_events` 和本地脱敏日志,不保存标题全文、Cookie、token、上传文件内容或页面整份 HTML。
|
||
|
||
### 4. 区分页面错误与无关 toast
|
||
|
||
- 保持 T-404b 既有规则:明确商品失效、商品不存在、无权限或店铺不匹配类 toast,即使已经自动隐藏,也可作为 `open_product()` 的主要失败原因并驱动①列表显示“商品失效”。
|
||
- 非商品失效类 toast 不得无条件覆盖就绪快照。物流、较长备货、库存、价格、标题校验、图片重复等编辑表单提示不能被描述为“商品页加载失败”。
|
||
- 未分类 toast 只有在当前仍可见且与本次导航/页面打开直接相关时,才可作为附加“页面提示”显示;已经隐藏的普通 toast 只保留在脱敏诊断 payload,不拼成用户可见的主要错误原因。
|
||
- 若同时存在明确商品失效 toast 和选择器缺失,商品失效优先;否则优先显示缺失的就绪组件,并把普通 toast 标为可能无关的诊断信息。
|
||
|
||
### 5. 测试与真实页面验证
|
||
|
||
- 更新 editor 单元测试,覆盖:
|
||
- 20 字及 1~24 字短标题通过业务字段主定位并判定页面就绪;
|
||
- 长标题仍命中同一业务字段;
|
||
- 旧 DOM 缺少业务字段时旧 XPath 回退仍可用;
|
||
- 页面有大量规格/价格/库存 `.eds-input__input` 时不误选;
|
||
- 主定位命中多个候选时明确失败,不猜测;
|
||
- `read_title()` 与 `change_title()` 使用同一标题节点,并继续校验 `value == modelvalue == 新标题`;
|
||
- 主图业务字段内图片、上传 input 和上传状态来自同一个 manager;旧 DOM 回退不回归;
|
||
- 图片与上传入口正常、仅标题旧启发式不命中的页面,会报告“未识别商品名称输入框”;
|
||
- 隐藏的“此物流選項不支援較長備貨商品”不再成为加载失败主因;明确商品失效 toast 仍按 T-404b 上浮。
|
||
- 使用商品 `48363984966` 做只读 CDP 验证:新就绪快照须为标题1个、主图5张、主图上传入口1个;`read_title()` 非空、`read_cover_src()` 为 `susercontent`,①采集可进入 `read_title/read_cover/download_cover/db_write` 并成功关闭本轮自动创建 tab。
|
||
- 标题写入路径只在仓库指定测试商品或 mock 中验证,不在该运营商品上点击「更新」提交;测试商品失效导致实跑不可用时如实记录限制。
|
||
- 选择器变化后同步 `docs/04-architecture.md` 第七节与 `docs/api.md`,不得继续把标题长度启发式记作当前唯一已验证事实。
|
||
|
||
## 验收要点
|
||
|
||
- 标题不足25个字符的有效商品不再卡在 `wait_ready`;页面图片已加载时能正常采集标题和第一张封面。
|
||
- 标题识别基于 `name` 业务字段,不会误选规格、价格、库存、物流或货号输入框;旧页面仍有受控回退。
|
||
- 商品名称、主图 itembox 和上传入口分别来自明确业务字段,且所有读写/就绪脚本复用同一定位事实。
|
||
- 就绪超时能明确指出标题、主图或上传入口哪一项缺失,不再只显示泛化超时。
|
||
- 物流/备货等无关且已隐藏 toast 不再伪装成商品页面加载失败;商品失效/无权限 toast 捕获不回归。
|
||
- 不改变①后台采集、不切前台、只关闭程序自动创建 tab的策略;不改变③封面上传、拖拽、确认和线上提交边界。
|
||
- 自动验证:
|
||
- `py -3.10 -m unittest tests.test_editor_login`
|
||
- `py -3.10 -m unittest tests.test_gui`
|
||
- `py -3.10 -m unittest discover -s tests`
|
||
- `python -m ruff check app tests main.py`
|
||
- `py -3.10 -m compileall app main.py`
|
||
- `git diff --check`
|
||
|
||
## 边界(不改什么)
|
||
|
||
- 不通过降低为 `document.readyState`、只检查 URL 或取消关键字段检查来掩盖问题。
|
||
- 不通过固定等待更久、把60秒改得更大或切换 Chrome 前台解决选择器错误。
|
||
- 不修改登录检测、账号 Chrome 启动、只读 tab 生命周期或①采集并发策略。
|
||
- 不修改③删除第一张封面、上传、拖拽第一位、更新确认框和成功后关闭 tab 的业务顺序,不点击线上「更新」做本任务验收。
|
||
- 不修改 SQLite/Excel schema、AI/cmhub、提示词或 GUI 布局。
|
||
- 不提交用户导出的 `48363984966.html`、运营 Excel、`data/` 日志、账号登录态或其他业务数据。
|