fix(client): bind SKU entry to verified parent chain

This commit is contained in:
QiuSW
2026-08-04 18:21:30 +08:00
parent 13547728fc
commit 44586fef38
3 changed files with 149 additions and 16 deletions
+51 -2
View File
@@ -17,6 +17,9 @@ EXPECTED_UNIT_PRICE = "12.88"
TASK_TO_UI_SELECTION = {("黑色CHA(纯棉)", "M(建议100-115)"): ("黑色 CHA (纯棉)", "M(建议100-115)")}
_TARGET_COLOR_UI, _TARGET_SIZE_UI = next(iter(TASK_TO_UI_SELECTION.values()))
_ENTRY = "快要抢光"
_ENTRY_TEXT_BOUNDS = "[900,1312][1056,1355]"
_ENTRY_INNER_BOUNDS = "[712,1312][1056,1355]"
_ENTRY_ACTION_BOUNDS = "[0,1256][1080,1355]"
_SIZE = "尺码"
_W, _H = 1080, 2376
_PRICE_PARENT = "[396,498][895,570]"
@@ -352,9 +355,55 @@ def _choice(node: _Node) -> bool:
def _eligible_entries(nodes: list[_Node]) -> list[_Node]:
# 面板与底部硬拒绝区绝不能被误作商品页入口;入口仍只按经取证精确文案、包、状态判定。
# 入口文本本身不可点击:必须逐层证明它仍位于已取证的唯一可点击祖先中,但动作坐标继续
# 使用文本子节点的窄 bounds,避免把同一祖先内未知区域变成坐标兜底。“免拼购买”等底部
# 容器既不属于这条祖先链,也绝不能作为替代入口。
if any(node.bounds == _PRICE_PARENT for node in nodes): return []
return [node for node in nodes if _live(node) and node.element.get("class") == "android.widget.TextView" and node.text == _ENTRY]
entry_labels = [
node for node in nodes
if node.text == _ENTRY
and node.element.get("package") == PDD_PACKAGE
and node.element.get("class") == "android.widget.TextView"
]
if len(entry_labels) != 1:
return entry_labels
action_ancestors = [
node for node in nodes
if _exact_entry_node(node, "android.view.ViewGroup", _ENTRY_ACTION_BOUNDS, "true")
]
if len(action_ancestors) != 1:
return []
action_ancestor = action_ancestors[0]
entries: list[_Node] = []
for node in entry_labels:
if not _exact_entry_node(node, "android.widget.TextView", _ENTRY_TEXT_BOUNDS, "false"):
return []
inner = node.parent
switcher = inner.parent if inner is not None else None
frame = switcher.parent if switcher is not None else None
ancestor = frame.parent if frame is not None else None
if (
inner is not None
and _exact_entry_node(inner, "android.view.ViewGroup", _ENTRY_INNER_BOUNDS, "false")
and switcher is not None
and _exact_entry_node(switcher, "android.widget.ViewSwitcher", _ENTRY_INNER_BOUNDS, "false")
and frame is not None
and _exact_entry_node(frame, "android.widget.FrameLayout", _ENTRY_INNER_BOUNDS, "false")
and ancestor is action_ancestor
):
entries.append(node)
return entries
def _exact_entry_node(node: _Node, class_name: str, bounds: str, clickable: str) -> bool:
return (
node.element.get("package") == PDD_PACKAGE
and node.element.get("class") == class_name
and node.bounds == bounds
and node.element.get("clickable") == clickable
and node.element.get("enabled") == "true"
and node.element.get("visible-to-user") == "true"
)
def _action_bounds(bounds: str) -> tuple[int, int, int, int]: