fix(切号): 等面板/等回读改成轮询(固定 sleep 会把"没加载出来"误判成"本机没登这个号")+ 实测选择器入档
A01(抖音 40.6.0)实测: · 冷启动后按固定 sleep(1.2s) 找账号列表行 → 列表还没渲染 → 判成"本机没登这个号" → **漏发且不报错**; 现在两处都轮询到 deadline:等面板出目标行、等回读变成目标名。 · 实测选择器(写进 doc/research/U2_ELEMENT_SELECTORS.md §七 与 .env.example): 昵称 `resourceId=com.ss.android.ugc.aweme:id/tk+`、切换入口 `descriptionContains=切换账号`、 切号按名字点行 `textContains=<名字>`(行 TextView 不可点但 u2 按中心坐标点,行容器接住)、 「我」页签 `descriptionContains=我`(desc 是「我,按钮」)。 · 并记下"为什么不要用 (…b7w)[N]":序号型会随列表行数/顺序错位 → 点错号 = 发到别人号上。 · 冷启动切号 17.2s 成功、热态 12.9s;A01 最终已切回原账号。
This commit is contained in:
@@ -172,3 +172,61 @@
|
||||
`core/uiauto_helper.py` 里 `_child_path()` 的注释与 `doc/TASK_DEV.md` §5.4 都记了这两个坑,
|
||||
避免以后又写回来。
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 七、抖音「我」页面 + 账号切换列表的选择器(2026-10-12,A01 实测)
|
||||
|
||||
**背景**:发布计划改成按**名字**发(`doc/TASK_DEV.md` §4.7),平台需要两处控件:
|
||||
① 「我」页面上的**昵称**(读当前登的是谁);② 「我」页面右上角的**切换账号**入口。
|
||||
抖音 40.6.0 / 720×1650 实测(A01 = `192.168.20.82:5555`)。
|
||||
|
||||
### 用哪个(已实测可用)
|
||||
|
||||
| 用途 | 选择器 | 说明 |
|
||||
|---|---|---|
|
||||
| **读昵称** | `resourceId = com.ss.android.ugc.aweme:id/tk+` | 读回来就是昵称原文(如 `周周苏州吃喝玩乐`)。等价 xpath:`//*[@resource-id="com.ss.android.ugc.aweme:id/tk+"]` |
|
||||
| **进切换列表** | `descriptionContains = 切换账号` | 右上角那个按钮是个 ImageView,**只有 content-desc**(`切换账号`),没有文字 |
|
||||
| **切到某个号** | `textContains = <名字>` 点它 | 列表每行的名字是 `TextView`(id `tv_nickname`),**本身 `clickable=false`** —— 但 u2 的 `click()` 是**按中心坐标点屏**,行容器(无 id 的 `ViewGroup`,`clickable=true`)会接住这次点击,实测能切成 |
|
||||
| **底部「我」页签** | `descriptionContains = 我` | 页签的 content-desc 是 `我,按钮`(**全角逗号**),`包含` 就能命中;别用 `text=我`(会撞上「我的订单」等) |
|
||||
|
||||
### 结构(40.6.0)
|
||||
|
||||
```
|
||||
「我」页面
|
||||
└ LinearLayout uj+ 资料块
|
||||
├ ukd → s=g → TextView tk+ = 昵称 ← 读名字就用它
|
||||
│ └ j2f → 1gp → ImageView oxp(desc=切换账号) ← 点它进列表
|
||||
└ ukc → l1= → j6c → g7j = 抖音号:xxx
|
||||
|
||||
切换账号列表(点 oxp 后弹出的面板)
|
||||
└ View(desc=返回,铺满面板,可点) ← "点面板外关掉"那层
|
||||
├ ViewGroup(无 id,clickable)894~1060 ← 第 1 行(当前号)
|
||||
│ ├ ImageView iv_avatar / TextView tv_nickname / TextView 37_(粉丝数)/ CheckBox b7w
|
||||
├ ViewGroup 1060~1228 ← 第 2 行
|
||||
├ ViewGroup 1228~1396 ← 第 3 行
|
||||
└ ViewGroup 1396~1556(添加或注册新账号)
|
||||
```
|
||||
|
||||
### 为什么**不要**用 `(…b7w)[N]`
|
||||
|
||||
`b7w` 是每行那个单选框(CheckBox)的 id —— `(…b7w)[2]` 看着能选中第 2 行,
|
||||
但这正是本文 §二说的**序号型**:`[N]` 依赖"列表里有几行、面板从哪一行开始",号一多/一少、
|
||||
或者抖音把「添加或注册新账号」挪个位置就点到别人号上了(**把内容发到别人号上**,最严重的一类错)。
|
||||
按名字点(`textContains=<名字>`)永远指着那一行本身。
|
||||
|
||||
### 实测记录
|
||||
|
||||
- 冷启动(`app_stop` → `app_start`)后切号:**17.2s** 成功;热态切号 12.9s
|
||||
- ⚠ **第一次实现踩的坑**:把"进列表"后的等待写成**固定 sleep(1.2s) 再找一次**,
|
||||
冷启动时列表还没渲染出来 → 判成"本机没登这个号" → **漏发**(还不会报错,只是不发)。
|
||||
现在两处都改成**轮询到 deadline**(`max(6s, timeout)`):等面板出目标行、等回读变成目标名。
|
||||
教训同 §一:**"找不到"和"没加载出来"必须用等待区分开**。
|
||||
|
||||
### 抓取命令(下次 App 改版后重抓)
|
||||
|
||||
```bash
|
||||
# 前台确保是抖音且在「我」页,然后
|
||||
.venv/Scripts/python -c "import uiautomator2 as u2; d=u2.connect('<serial>'); open('me.xml','w',encoding='utf-8').write(d.dump_hierarchy())"
|
||||
# 在 me.xml 里找 text 是昵称、或 content-desc 是「切换账号」的节点,看它的 resource-id
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user