tt-help-cli-ycl 1.3.61 → 1.3.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tt-help-cli-ycl",
3
- "version": "1.3.61",
3
+ "version": "1.3.62",
4
4
  "description": "TikTok user & video data scraper - extract ttSeller, verified, locationCreated from HTML source",
5
5
  "type": "module",
6
6
  "bin": {
@@ -104,30 +104,54 @@ export async function isLoggedIn(page) {
104
104
 
105
105
  /**
106
106
  * 通过 DOM 元素判断登录状态(验真方案)
107
+ * 使用 locator API + state: 'attached' 来避免 CDP 连接下 waitForSelector 的可见性问题
107
108
  * @returns {boolean|null} true=已登录, false=明确未登录, null=无法判断
108
109
  */
109
110
  export async function isLoggedInByDom(page) {
110
- // 先等客户端渲染完成:登录态元素或登录按钮,哪个先出现就停止等待
111
- const loginOrLoggedInSelector = [
112
- '[class*="DivProfileContainer"]',
113
- '[class*="DivUserContainer"]',
114
- '[class*="UserMenu"]',
115
- '[class*="CurrentUserInfo"]',
116
- 'button:has-text("登录")',
117
- 'button:has-text("Log in")',
118
- 'button:has-text("Sign in")',
119
- ].join(", ");
120
-
121
- const selectorFound = await page
122
- .waitForSelector(loginOrLoggedInSelector, { timeout: DOM_CHECK_TIMEOUT })
123
- .then(() => true)
124
- .catch(() => false);
125
-
126
- if (!selectorFound) {
127
- // 等待超时,DOM 无法判断
128
- return null;
111
+ // 使用 Promise.race 等待:已登录元素 或 登录按钮,哪个先出现就停止
112
+ const loggedInLocators = [
113
+ page.locator('[class*="DivProfileContainer"]'),
114
+ page.locator('[class*="DivUserContainer"]'),
115
+ page.locator('[class*="UserMenu"]'),
116
+ page.locator('[class*="CurrentUserInfo"]'),
117
+ ];
118
+
119
+ const loginButtonLocators = [
120
+ page.getByText("登录", { exact: true }),
121
+ page.getByText("Log in", { exact: true }),
122
+ page.getByText("Sign in", { exact: true }),
123
+ ];
124
+
125
+ // 并发等待:已登录元素 vs 登录按钮
126
+ const waitForLoggedIn = Promise.any(
127
+ loggedInLocators.map((loc) =>
128
+ loc.first().waitFor({ state: "attached", timeout: DOM_CHECK_TIMEOUT }),
129
+ ),
130
+ )
131
+ .then(() => "loggedIn")
132
+ .catch(() => null);
133
+
134
+ const waitForLoginButton = Promise.any(
135
+ loginButtonLocators.map((loc) =>
136
+ loc.first().waitFor({ state: "attached", timeout: DOM_CHECK_TIMEOUT }),
137
+ ),
138
+ )
139
+ .then(() => "loginButton")
140
+ .catch(() => null);
141
+
142
+ // 哪个先完成就返回哪个结果
143
+ const result = await Promise.race([waitForLoggedIn, waitForLoginButton]);
144
+
145
+ if (result === "loginButton") {
146
+ // 明确看到登录按钮 → 未登录
147
+ return false;
148
+ }
149
+ if (result === "loggedIn") {
150
+ // 看到已登录元素 → 已登录
151
+ return true;
129
152
  }
130
153
 
154
+ // 都超时了,回退到 evaluate 做最终判断
131
155
  return page.evaluate(() => {
132
156
  const hasProfileContainer = !!document.querySelector(
133
157
  '[class*="DivProfileContainer"], [class*="DivUserContainer"]',
@@ -143,7 +167,7 @@ export async function isLoggedInByDom(page) {
143
167
  if (hasLoginButton) return false;
144
168
  // 看到已登录元素 → 已登录
145
169
  if (hasProfileContainer || hasUserMenu) return true;
146
- // 元素已出现但都不是登录/未登录标志 → 无法判断
170
+ // 都无法判断
147
171
  return null;
148
172
  });
149
173
  }