StarrySkyWorld commited on
Commit
a935e3c
·
verified ·
1 Parent(s): 7df5e11

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +36 -183
main.py CHANGED
@@ -14,6 +14,9 @@ context = None
14
  config = None
15
  scheduler = AsyncIOScheduler()
16
 
 
 
 
17
  def load_config():
18
  """加载配置文件"""
19
  with open("config.json", "r", encoding="utf-8") as f:
@@ -65,11 +68,11 @@ def load_cookies():
65
  return converted_cookies
66
 
67
  async def activate_task():
68
- """定时激活任务"""
69
  if config and config.get("activateLink"):
70
  try:
71
- async with httpx.AsyncClient() as client:
72
- response = await client.get(config["activateLink"], timeout=30)
73
  print(f"[Activate] GET {config['activateLink']} - Status: {response.status_code}")
74
  except Exception as e:
75
  print(f"[Activate] Error: {e}")
@@ -84,23 +87,15 @@ async def auto_click_task():
84
 
85
  try:
86
  for text in click_buttons:
87
- # 精确选择器列表(针对 Google AI Studio 的 Material Dialog)
88
  selectors = [
89
- # 最精确:mat-dialog-actions 中的按钮
90
  f'mat-dialog-actions button:has-text("{text}")',
91
  f'mat-dialog-actions button.ms-button-primary',
92
- # CDK overlay 中的按钮
93
  f'.cdk-overlay-container button:has-text("{text}")',
94
  f'.cdk-overlay-container button.ms-button-primary',
95
  f'.cdk-overlay-pane button:has-text("{text}")',
96
- # Material dialog
97
  f'.mat-mdc-dialog-actions button:has-text("{text}")',
98
- f'.mdc-dialog__actions button:has-text("{text}")',
99
- f'mat-dialog-container button:has-text("{text}")',
100
- # 通用
101
  f'button.ms-button-primary:has-text("{text}")',
102
  f'button:has-text("{text}")',
103
- f'[role="button"]:has-text("{text}")',
104
  ]
105
 
106
  for selector in selectors:
@@ -110,86 +105,64 @@ async def auto_click_task():
110
  if count > 0:
111
  element = locator.first
112
  if await element.is_visible(timeout=300):
113
- # 尝试点击
114
  await element.click(timeout=3000, force=True)
115
- print(f'[AutoClick] Clicked "{text}" via selector: {selector}')
116
  return
117
- except Exception as e:
118
  continue
119
 
120
- # 备用方案:使用 JavaScript 点击
121
  try:
122
  clicked = await page.evaluate('''(searchText) => {
123
- // 查找 mat-dialog-actions 中的按钮
124
  const dialogActions = document.querySelector('mat-dialog-actions');
125
  if (dialogActions) {
126
  const buttons = dialogActions.querySelectorAll('button');
127
  for (const btn of buttons) {
128
- const btnText = btn.textContent.trim();
129
- if (btnText.toLowerCase() === searchText.toLowerCase()) {
130
  btn.click();
131
- return 'dialog-actions';
132
  }
133
  }
134
  }
135
-
136
- // 查找 cdk-overlay-container 中的按钮
137
  const overlay = document.querySelector('.cdk-overlay-container');
138
  if (overlay) {
139
  const buttons = overlay.querySelectorAll('button');
140
  for (const btn of buttons) {
141
- const btnText = btn.textContent.trim();
142
- if (btnText.toLowerCase() === searchText.toLowerCase()) {
143
- btn.click();
144
- return 'overlay';
145
- }
146
- }
147
- }
148
-
149
- // 查找 ms-button-primary
150
- const primaryBtns = document.querySelectorAll('button.ms-button-primary');
151
- for (const btn of primaryBtns) {
152
- const btnText = btn.textContent.trim();
153
- if (btnText.toLowerCase() === searchText.toLowerCase()) {
154
- btn.click();
155
- return 'primary-button';
156
- }
157
- }
158
-
159
- // 全局查找
160
- const allButtons = document.querySelectorAll('button');
161
- for (const btn of allButtons) {
162
- const btnText = btn.textContent.trim();
163
- if (btnText.toLowerCase() === searchText.toLowerCase()) {
164
- const rect = btn.getBoundingClientRect();
165
- if (rect.width > 0 && rect.height > 0) {
166
  btn.click();
167
- return 'global';
168
  }
169
  }
170
  }
171
-
172
- return null;
173
  }''', text)
174
 
175
  if clicked:
176
- print(f'[AutoClick] Clicked "{text}" via JavaScript ({clicked})')
177
  return
178
- except Exception as e:
179
  pass
180
 
181
- except Exception as e:
182
  pass
183
 
184
  async def init_browser():
185
- """初始化浏览器"""
186
  global browser, page, context, config
187
 
188
  config = load_config()
189
  cookies = load_cookies()
190
 
191
  playwright = await async_playwright().start()
192
- browser = await playwright.chromium.launch(headless=True)
 
 
 
 
 
 
 
 
193
  context = await browser.new_context(
194
  viewport={"width": 1920, "height": 1080},
195
  user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
@@ -201,8 +174,8 @@ async def init_browser():
201
  try:
202
  if cookie.get("name") and cookie.get("value") and cookie.get("domain"):
203
  valid_cookies.append(cookie)
204
- except Exception as e:
205
- print(f"[Cookie] Skip invalid cookie: {e}")
206
 
207
  if valid_cookies:
208
  try:
@@ -210,14 +183,6 @@ async def init_browser():
210
  print(f"[Browser] Loaded {len(valid_cookies)} cookies")
211
  except Exception as e:
212
  print(f"[Browser] Error loading cookies: {e}")
213
- success_count = 0
214
- for cookie in valid_cookies:
215
- try:
216
- await context.add_cookies([cookie])
217
- success_count += 1
218
- except Exception as ce:
219
- print(f"[Cookie] Failed to add cookie '{cookie.get('name')}' for {cookie.get('domain')}: {ce}")
220
- print(f"[Browser] Loaded {success_count}/{len(valid_cookies)} cookies individually")
221
 
222
  page = await context.new_page()
223
 
@@ -239,7 +204,6 @@ async def lifespan(app: FastAPI):
239
  """应用生命周期管理"""
240
  await init_browser()
241
 
242
- # 定时激活任务
243
  if config and config.get("activateLink"):
244
  interval = config.get("activateInterval", 60)
245
  scheduler.add_job(
@@ -252,7 +216,6 @@ async def lifespan(app: FastAPI):
252
  )
253
  print(f"[Scheduler] Activate task started with interval: {interval}s")
254
 
255
- # 自动点击按钮任务
256
  click_interval = config.get("autoClickInterval", 5)
257
  scheduler.add_job(
258
  auto_click_task,
@@ -326,123 +289,13 @@ async def navigate_to(url: str):
326
  except Exception as e:
327
  return {"status": "warning", "message": f"Navigation completed with issue: {e}"}
328
 
329
- @app.get("/click")
330
- async def manual_click(text: str):
331
- """手动点击包含指定文本的按钮"""
332
- global page
333
- if not page:
334
- return {"status": "error", "message": "Browser not initialized"}
335
-
336
  try:
337
- # 尝试用选择器点击
338
- selectors = [
339
- f'mat-dialog-actions button:has-text("{text}")',
340
- f'.cdk-overlay-container button:has-text("{text}")',
341
- f'button.ms-button-primary:has-text("{text}")',
342
- f'button:has-text("{text}")',
343
- ]
344
-
345
- for selector in selectors:
346
- try:
347
- locator = page.locator(selector)
348
- if await locator.count() > 0:
349
- element = locator.first
350
- if await element.is_visible(timeout=1000):
351
- await element.click(timeout=3000, force=True)
352
- return {"status": "success", "message": f'Clicked "{text}" via selector: {selector}'}
353
- except:
354
- continue
355
-
356
- # JavaScript 备用
357
- clicked = await page.evaluate('''(searchText) => {
358
- const dialogActions = document.querySelector('mat-dialog-actions');
359
- if (dialogActions) {
360
- const buttons = dialogActions.querySelectorAll('button');
361
- for (const btn of buttons) {
362
- if (btn.textContent.trim().toLowerCase() === searchText.toLowerCase()) {
363
- btn.click();
364
- return 'dialog-actions';
365
- }
366
- }
367
- }
368
-
369
- const allButtons = document.querySelectorAll('button');
370
- for (const btn of allButtons) {
371
- if (btn.textContent.trim().toLowerCase() === searchText.toLowerCase()) {
372
- btn.click();
373
- return 'global';
374
- }
375
- }
376
- return null;
377
- }''', text)
378
-
379
- if clicked:
380
- return {"status": "success", "message": f'Clicked "{text}" via JavaScript ({clicked})'}
381
-
382
- return {"status": "error", "message": f'Button with text "{text}" not found'}
383
- except Exception as e:
384
- return {"status": "error", "message": str(e)}
385
-
386
- @app.get("/debug/buttons")
387
- async def debug_buttons():
388
- """调试:列出所有按钮"""
389
- global page
390
- if not page:
391
- return {"status": "error", "message": "Browser not initialized"}
392
-
393
- try:
394
- buttons = await page.evaluate('''() => {
395
- const results = [];
396
- const allButtons = document.querySelectorAll('button, [role="button"]');
397
- allButtons.forEach((btn, i) => {
398
- const rect = btn.getBoundingClientRect();
399
- results.push({
400
- index: i,
401
- text: btn.textContent.trim().substring(0, 50),
402
- visible: rect.width > 0 && rect.height > 0,
403
- className: btn.className.substring(0, 50),
404
- inDialog: !!btn.closest('mat-dialog-container'),
405
- inOverlay: !!btn.closest('.cdk-overlay-container')
406
- });
407
- });
408
- return results;
409
- }''')
410
-
411
- return {"status": "success", "count": len(buttons), "buttons": buttons}
412
- except Exception as e:
413
- return {"status": "error", "message": str(e)}
414
-
415
- @app.get("/debug/search")
416
- async def debug_search(text: str):
417
- """调试:搜索包含指定文本的所有元素"""
418
- global page
419
- if not page:
420
- return {"status": "error", "message": "Browser not initialized"}
421
-
422
- try:
423
- elements = await page.evaluate('''(searchText) => {
424
- const results = [];
425
- const lowerText = searchText.toLowerCase();
426
- const allElements = document.querySelectorAll('*');
427
-
428
- allElements.forEach(el => {
429
- const text = (el.textContent || '').trim();
430
- if (text.toLowerCase().includes(lowerText) && text.length < 200) {
431
- const rect = el.getBoundingClientRect();
432
- results.push({
433
- tag: el.tagName.toLowerCase(),
434
- text: text.substring(0, 100),
435
- visible: rect.width > 0 && rect.height > 0,
436
- className: (el.className || '').substring(0, 50),
437
- id: el.id || ''
438
- });
439
- }
440
- });
441
-
442
- return results.slice(0, 50);
443
- }''', text)
444
-
445
- return {"status": "success", "count": len(elements), "elements": elements}
446
  except Exception as e:
447
  return {"status": "error", "message": str(e)}
448
 
@@ -453,4 +306,4 @@ async def health_check():
453
 
454
  if __name__ == "__main__":
455
  import uvicorn
456
- uvicorn.run(app, host="0.0.0.0", port=8000)
 
14
  config = None
15
  scheduler = AsyncIOScheduler()
16
 
17
+ # WARP 代理地址
18
+ PROXY_SERVER = "socks5://127.0.0.1:1080"
19
+
20
  def load_config():
21
  """加载配置文件"""
22
  with open("config.json", "r", encoding="utf-8") as f:
 
68
  return converted_cookies
69
 
70
  async def activate_task():
71
+ """定时激活任务(通过代理)"""
72
  if config and config.get("activateLink"):
73
  try:
74
+ async with httpx.AsyncClient(proxy=PROXY_SERVER, timeout=30) as client:
75
+ response = await client.get(config["activateLink"])
76
  print(f"[Activate] GET {config['activateLink']} - Status: {response.status_code}")
77
  except Exception as e:
78
  print(f"[Activate] Error: {e}")
 
87
 
88
  try:
89
  for text in click_buttons:
 
90
  selectors = [
 
91
  f'mat-dialog-actions button:has-text("{text}")',
92
  f'mat-dialog-actions button.ms-button-primary',
 
93
  f'.cdk-overlay-container button:has-text("{text}")',
94
  f'.cdk-overlay-container button.ms-button-primary',
95
  f'.cdk-overlay-pane button:has-text("{text}")',
 
96
  f'.mat-mdc-dialog-actions button:has-text("{text}")',
 
 
 
97
  f'button.ms-button-primary:has-text("{text}")',
98
  f'button:has-text("{text}")',
 
99
  ]
100
 
101
  for selector in selectors:
 
105
  if count > 0:
106
  element = locator.first
107
  if await element.is_visible(timeout=300):
 
108
  await element.click(timeout=3000, force=True)
109
+ print(f'[AutoClick] Clicked "{text}"')
110
  return
111
+ except:
112
  continue
113
 
114
+ # JavaScript 备用
115
  try:
116
  clicked = await page.evaluate('''(searchText) => {
 
117
  const dialogActions = document.querySelector('mat-dialog-actions');
118
  if (dialogActions) {
119
  const buttons = dialogActions.querySelectorAll('button');
120
  for (const btn of buttons) {
121
+ if (btn.textContent.trim().toLowerCase() === searchText.toLowerCase()) {
 
122
  btn.click();
123
+ return true;
124
  }
125
  }
126
  }
 
 
127
  const overlay = document.querySelector('.cdk-overlay-container');
128
  if (overlay) {
129
  const buttons = overlay.querySelectorAll('button');
130
  for (const btn of buttons) {
131
+ if (btn.textContent.trim().toLowerCase() === searchText.toLowerCase()) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  btn.click();
133
+ return true;
134
  }
135
  }
136
  }
137
+ return false;
 
138
  }''', text)
139
 
140
  if clicked:
141
+ print(f'[AutoClick] Clicked "{text}" via JS')
142
  return
143
+ except:
144
  pass
145
 
146
+ except:
147
  pass
148
 
149
  async def init_browser():
150
+ """初始化浏览器(使用 WARP 代理)"""
151
  global browser, page, context, config
152
 
153
  config = load_config()
154
  cookies = load_cookies()
155
 
156
  playwright = await async_playwright().start()
157
+
158
+ # 使用 WARP SOCKS5 代理
159
+ browser = await playwright.chromium.launch(
160
+ headless=True,
161
+ proxy={
162
+ "server": PROXY_SERVER
163
+ }
164
+ )
165
+
166
  context = await browser.new_context(
167
  viewport={"width": 1920, "height": 1080},
168
  user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
 
174
  try:
175
  if cookie.get("name") and cookie.get("value") and cookie.get("domain"):
176
  valid_cookies.append(cookie)
177
+ except:
178
+ pass
179
 
180
  if valid_cookies:
181
  try:
 
183
  print(f"[Browser] Loaded {len(valid_cookies)} cookies")
184
  except Exception as e:
185
  print(f"[Browser] Error loading cookies: {e}")
 
 
 
 
 
 
 
 
186
 
187
  page = await context.new_page()
188
 
 
204
  """应用生命周期管理"""
205
  await init_browser()
206
 
 
207
  if config and config.get("activateLink"):
208
  interval = config.get("activateInterval", 60)
209
  scheduler.add_job(
 
216
  )
217
  print(f"[Scheduler] Activate task started with interval: {interval}s")
218
 
 
219
  click_interval = config.get("autoClickInterval", 5)
220
  scheduler.add_job(
221
  auto_click_task,
 
289
  except Exception as e:
290
  return {"status": "warning", "message": f"Navigation completed with issue: {e}"}
291
 
292
+ @app.get("/ip")
293
+ async def get_ip():
294
+ """获取当前出口 IP(验证 WARP 是否生效)"""
 
 
 
 
295
  try:
296
+ async with httpx.AsyncClient(proxy=PROXY_SERVER, timeout=10) as client:
297
+ response = await client.get("https://api.ipify.org?format=json")
298
+ return response.json()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
  except Exception as e:
300
  return {"status": "error", "message": str(e)}
301
 
 
306
 
307
  if __name__ == "__main__":
308
  import uvicorn
309
+ uvicorn.run(app, host="0.0.0.0", port=7860)