fix(client): bind revealed current-only price layout
This commit is contained in:
@@ -337,26 +337,22 @@ def _candidate_projection(nodes: list[Any]) -> tuple[tuple[str, ...], ...]:
|
||||
[node for node in nodes if node.parent is surface and _exact_inert(node, "android.widget.LinearLayout", "[0,366][1080,1000]")],
|
||||
"候选面板头部不唯一。",
|
||||
)
|
||||
if len([child for child in header.element if child.tag == "node"]) != 4:
|
||||
raise SkuSelectionError("候选面板头部子节点数量漂移。")
|
||||
outer = _one(
|
||||
[node for node in nodes if node.parent is surface and _exact_recycler(node, "[0,1000][1080,2079]")],
|
||||
"候选维度容器不唯一。",
|
||||
)
|
||||
price_row = _one(
|
||||
[node for node in nodes if _descendant(node, header) and _exact_inert(node, "android.widget.LinearLayout", "[396,498][895,570]")],
|
||||
"候选价格行不唯一。",
|
||||
)
|
||||
current = _one(
|
||||
[node for node in nodes if node.parent is price_row and _exact_readonly_text(node, "快卖完 ¥12.88", "[396,503][712,570]")],
|
||||
"候选当前价不唯一。",
|
||||
)
|
||||
original = _one(
|
||||
[node for node in nodes if node.parent is price_row and _exact_readonly_text(node, "¥29.88", "[730,503][895,570]")],
|
||||
"候选原价不唯一。",
|
||||
)
|
||||
if _clickable_before(current, surface):
|
||||
raise SkuSelectionError("候选当前价位于可点击内容祖先下。")
|
||||
price_content, price_frame = _candidate_price_container(nodes, header)
|
||||
price_nodes = _candidate_price_nodes(nodes, header, surface, price_frame)
|
||||
summary = _one(
|
||||
[node for node in nodes if _descendant(node, header) and _exact_readonly_text(node, _COLOR_ONLY_SUMMARY, "[396,654][1053,716]")],
|
||||
[
|
||||
node
|
||||
for node in nodes
|
||||
if node.parent is price_content
|
||||
and _exact_readonly_text(node, _COLOR_ONLY_SUMMARY, "[396,654][1053,716]")
|
||||
and len(node.element) == 0
|
||||
],
|
||||
"候选摘要不唯一。",
|
||||
)
|
||||
color_region = _one(
|
||||
@@ -414,7 +410,189 @@ def _candidate_projection(nodes: list[Any]) -> tuple[tuple[str, ...], ...]:
|
||||
node.element.get("selected", ""),
|
||||
node.element.get("clickable", ""),
|
||||
)
|
||||
for node in (surface, header, outer, price_row, current, original, summary, color_region, color, size_label, size_options, s_action, m_action, dangerous[0])
|
||||
for node in (
|
||||
surface,
|
||||
header,
|
||||
outer,
|
||||
*price_nodes,
|
||||
summary,
|
||||
color_region,
|
||||
color,
|
||||
size_label,
|
||||
size_options,
|
||||
s_action,
|
||||
m_action,
|
||||
dangerous[0],
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _candidate_price_nodes(
|
||||
nodes: list[Any],
|
||||
header: Any,
|
||||
surface: Any,
|
||||
price_frame: Any,
|
||||
) -> tuple[Any, Any, Any]:
|
||||
matches: list[tuple[Any, Any, Any]] = []
|
||||
for matcher in (_candidate_dual_price_nodes, _candidate_current_only_price_nodes):
|
||||
try:
|
||||
match = matcher(nodes, header, surface, price_frame)
|
||||
except SkuSelectionError:
|
||||
continue
|
||||
matches.append(match)
|
||||
if len(matches) != 1:
|
||||
raise SkuSelectionError("候选价格布局不符合唯一完整取证变体。")
|
||||
return matches[0]
|
||||
|
||||
|
||||
def _candidate_dual_price_nodes(
|
||||
nodes: list[Any],
|
||||
header: Any,
|
||||
surface: Any,
|
||||
price_frame: Any,
|
||||
) -> tuple[Any, Any, Any]:
|
||||
price_row = _one(
|
||||
[
|
||||
node
|
||||
for node in nodes
|
||||
if node.parent is price_frame
|
||||
and _exact_inert(node, "android.widget.LinearLayout", "[396,498][895,570]")
|
||||
],
|
||||
"候选双价格行不唯一。",
|
||||
)
|
||||
if len([child for child in price_row.element if child.tag == "node"]) != 2:
|
||||
raise SkuSelectionError("候选双价格行子节点数量漂移。")
|
||||
current = _one(
|
||||
[
|
||||
node
|
||||
for node in nodes
|
||||
if node.parent is price_row
|
||||
and _exact_readonly_text(node, "快卖完 ¥12.88", "[396,503][712,570]")
|
||||
and len(node.element) == 0
|
||||
],
|
||||
"候选双价格当前价不唯一。",
|
||||
)
|
||||
original = _one(
|
||||
[
|
||||
node
|
||||
for node in nodes
|
||||
if node.parent is price_row
|
||||
and _exact_readonly_text(node, "¥29.88", "[730,503][895,570]")
|
||||
and len(node.element) == 0
|
||||
],
|
||||
"候选双价格原价不唯一。",
|
||||
)
|
||||
if _clickable_before(current, surface):
|
||||
raise SkuSelectionError("候选双价格当前价位于可点击内容祖先下。")
|
||||
if any(
|
||||
_candidate_current_only_fragment(node)
|
||||
for node in nodes
|
||||
if _descendant(node, header)
|
||||
):
|
||||
raise SkuSelectionError("候选双价格布局混入单价格残片。")
|
||||
return price_row, current, original
|
||||
|
||||
|
||||
def _candidate_current_only_price_nodes(
|
||||
nodes: list[Any],
|
||||
header: Any,
|
||||
surface: Any,
|
||||
price_frame: Any,
|
||||
) -> tuple[Any, Any, Any]:
|
||||
price_row = _one(
|
||||
[
|
||||
node
|
||||
for node in nodes
|
||||
if node.parent is price_frame
|
||||
and _exact_inert(node, "android.widget.LinearLayout", "[396,498][693,570]")
|
||||
],
|
||||
"候选单价格行父子关系漂移。",
|
||||
)
|
||||
if len([child for child in price_row.element if child.tag == "node"]) != 1:
|
||||
raise SkuSelectionError("候选单价格行子节点数量漂移。")
|
||||
current = _one(
|
||||
[
|
||||
node
|
||||
for node in nodes
|
||||
if node.parent is price_row
|
||||
and _exact_readonly_text(node, "限1件 ¥12.88 ", "[396,503][675,570]")
|
||||
and len(node.element) == 0
|
||||
],
|
||||
"候选单价格当前价不唯一。",
|
||||
)
|
||||
if any(node.text in {"¥29.88", "券前¥29.88"} for node in nodes):
|
||||
raise SkuSelectionError("候选单价格变体出现原价角色。")
|
||||
if any(
|
||||
_candidate_dual_fragment(node)
|
||||
for node in nodes
|
||||
if _descendant(node, header)
|
||||
):
|
||||
raise SkuSelectionError("候选单价格布局混入双价格残片。")
|
||||
if _clickable_before(current, surface):
|
||||
raise SkuSelectionError("候选单价格当前价位于可点击内容祖先下。")
|
||||
return price_frame, price_row, current
|
||||
|
||||
|
||||
def _candidate_price_container(nodes: list[Any], header: Any) -> tuple[Any, Any]:
|
||||
content_frame = _one(
|
||||
[
|
||||
node
|
||||
for node in nodes
|
||||
if node.parent is header
|
||||
and _exact_inert(node, "android.widget.FrameLayout", "[0,474][1080,863]")
|
||||
],
|
||||
"候选价格内容外框不唯一。",
|
||||
)
|
||||
if len([child for child in content_frame.element if child.tag == "node"]) != 1:
|
||||
raise SkuSelectionError("候选价格内容外框子节点数量漂移。")
|
||||
relative = _one(
|
||||
[
|
||||
node
|
||||
for node in nodes
|
||||
if node.parent is content_frame
|
||||
and _exact_inert(node, "android.widget.RelativeLayout", "[0,474][1080,863]")
|
||||
],
|
||||
"候选价格 RelativeLayout 父子关系漂移。",
|
||||
)
|
||||
if len([child for child in relative.element if child.tag == "node"]) != 1:
|
||||
raise SkuSelectionError("候选价格 RelativeLayout 子节点数量漂移。")
|
||||
content = _one(
|
||||
[
|
||||
node
|
||||
for node in nodes
|
||||
if node.parent is relative
|
||||
and _exact_inert(node, "android.view.ViewGroup", "[0,474][1080,863]")
|
||||
],
|
||||
"候选价格内容 ViewGroup 父子关系漂移。",
|
||||
)
|
||||
if len([child for child in content.element if child.tag == "node"]) != 8:
|
||||
raise SkuSelectionError("候选价格内容 ViewGroup 子节点数量漂移。")
|
||||
price_frame = _one(
|
||||
[
|
||||
node
|
||||
for node in nodes
|
||||
if node.parent is content
|
||||
and _exact_inert(node, "android.widget.FrameLayout", "[396,498][1053,570]")
|
||||
],
|
||||
"候选价格 FrameLayout 父子关系漂移。",
|
||||
)
|
||||
if len([child for child in price_frame.element if child.tag == "node"]) != 1:
|
||||
raise SkuSelectionError("候选价格 FrameLayout 子节点数量漂移。")
|
||||
return content, price_frame
|
||||
|
||||
|
||||
def _candidate_current_only_fragment(node: Any) -> bool:
|
||||
return (
|
||||
_exact_inert(node, "android.widget.LinearLayout", "[396,498][693,570]")
|
||||
or _exact_readonly_text(node, "限1件 ¥12.88 ", "[396,503][675,570]")
|
||||
)
|
||||
|
||||
|
||||
def _candidate_dual_fragment(node: Any) -> bool:
|
||||
return (
|
||||
_exact_inert(node, "android.widget.LinearLayout", "[396,498][895,570]")
|
||||
or _exact_readonly_text(node, "快卖完 ¥12.88", "[396,503][712,570]")
|
||||
or _exact_readonly_text(node, "¥29.88", "[730,503][895,570]")
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user