Files

10 KiB
Raw Permalink Blame History

id, title, phase, deps, status, created
id title phase deps status created
T-632 ①采集短标题就绪识别与页面错误诊断修复 2
T-404b
T-630
DONE 2026-07-14

问题 / 背景

最新代码采集商品 48363984966 时,账号 Chrome/CDP 连通正常,程序打开的商品详情 tab 也已加载成功,但任务在约 63 秒后失败:

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" 范围内的文本输入框,例如:
//*[@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 前台;成功条件仍为标题字段、至少一张商品主图和主图上传入口同时存在。
  • 超时时按最后快照给出具体中文原因,例如:
商品编辑器未就绪:未识别商品名称输入框;商品图片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/ 日志、账号登录态或其他业务数据。

执行记录

  • 2026-07-14:标题读取、就绪判断和标题写入统一改用 name 业务字段内唯一可见输入框;仅在业务字段根不存在时回退旧长度 XPath,主定位多候选时停止并给出明确诊断。
  • 2026-07-14:主图读取、矩形定位、上传状态、上传入口、删除第一张和上传事件统一限定到 images 业务字段内同一个图片管理器;保留旧 DOM 受控回退,不改变③删除、上传、拖拽和提交顺序。
  • 2026-07-14:页面就绪脚本改为结构化快照,超时会分别报告标题、主图、上传入口及当前页面;隐藏的普通物流/备货 toast 不再覆盖缺失组件,明确商品失效 toast 仍可上浮。
  • 2026-07-14:真实商品 48363984966 只读 CDP 验证通过:标题命中 1 个(长度 20)、主图 5 张且均为 susercontent、上传入口 1 个;collect() 顺利经过 open_product/wait_ready/read_title/read_cover/download_cover,临时下载封面 131477 字节。因复用用户已有 tab,按规则只断开 CDP、不关闭页面;未执行标题写入或线上更新。
  • 2026-07-14:验证通过:tests.test_editor_login 57 项、tests.test_gui 182 项、全量单元测试 486 项;python -m ruff check app tests main.py、py -3.10 -m compileall -q app main.py、git diff --check 均通过。全量测试使用仅含本任务改动的干净工作树,未纳入工作区中用户未提交的提示词改名等无关变更。