myagent-ai 1.29.0 → 1.30.1
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/aiskills/browser_stealth.py +108 -45
- package/aiskills/site-douyin/SKILL.md +123 -0
- package/aiskills/site-gmail/SKILL.md +124 -0
- package/aiskills/site-mail139/SKILL.md +115 -0
- package/aiskills/site-wechat-mp/SKILL.md +116 -0
- package/aiskills/site-weibo/SKILL.md +135 -0
- package/aiskills/site-x-com/SKILL.md +138 -0
- package/aiskills/stealth_browser/SKILL.md +1 -1
- package/core/browser_profile.py +8 -2
- package/main.py +24 -0
- package/package.json +1 -1
- package/scripts/cli.py +2 -1
- package/worklog.md +25 -0
|
@@ -33,6 +33,7 @@ import asyncio
|
|
|
33
33
|
import json
|
|
34
34
|
import os
|
|
35
35
|
import shutil
|
|
36
|
+
import threading
|
|
36
37
|
import time
|
|
37
38
|
from pathlib import Path
|
|
38
39
|
from typing import Any, Dict, List, Optional
|
|
@@ -89,7 +90,9 @@ class StealthBrowser:
|
|
|
89
90
|
mgr = get_browser_profile_manager()
|
|
90
91
|
profile = mgr.get_profile(self.profile_name)
|
|
91
92
|
profile.ensure_dirs()
|
|
92
|
-
|
|
93
|
+
# DrissionPage 的 set_user_data_path 会自动在路径下创建 Default 目录
|
|
94
|
+
# 我们直接用 profile_dir 作为 user-data-dir,避免嵌套
|
|
95
|
+
self._user_data_dir = str(profile.profile_dir)
|
|
93
96
|
return self._user_data_dir
|
|
94
97
|
|
|
95
98
|
async def start(self) -> SkillResult:
|
|
@@ -107,8 +110,9 @@ class StealthBrowser:
|
|
|
107
110
|
co = ChromiumOptions()
|
|
108
111
|
|
|
109
112
|
# 设置用户数据目录(Profile 持久化)
|
|
113
|
+
# 注意:只用 set_argument,不用 set_user_data_path,因为后者会
|
|
114
|
+
# 在路径下再套一层 Default/ 子目录,导致路径混乱
|
|
110
115
|
if user_data:
|
|
111
|
-
co.set_user_data_path(user_data)
|
|
112
116
|
co.set_argument(f"--user-data-dir={user_data}")
|
|
113
117
|
|
|
114
118
|
# 反检测核心参数
|
|
@@ -120,20 +124,16 @@ class StealthBrowser:
|
|
|
120
124
|
co.set_argument("--disable-infobars")
|
|
121
125
|
co.set_argument("--disable-extensions")
|
|
122
126
|
|
|
123
|
-
#
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
# 容器环境(无论有无 DISPLAY 都加上,避免切换环境后出错)
|
|
128
|
+
co.set_argument("--no-sandbox")
|
|
129
|
+
co.set_argument("--disable-setuid-sandbox")
|
|
130
|
+
co.set_argument("--disable-dev-shm-usage")
|
|
131
|
+
co.set_argument("--disable-gpu")
|
|
126
132
|
|
|
127
133
|
# 无头模式
|
|
128
134
|
if self._headless:
|
|
129
135
|
co.headless()
|
|
130
136
|
|
|
131
|
-
# 容器环境
|
|
132
|
-
if not os.environ.get("DISPLAY"):
|
|
133
|
-
co.set_argument("--no-sandbox")
|
|
134
|
-
co.set_argument("--disable-setuid-sandbox")
|
|
135
|
-
co.set_argument("--disable-gpu")
|
|
136
|
-
|
|
137
137
|
# 自动检测浏览器路径
|
|
138
138
|
browser_path = self._detect_browser()
|
|
139
139
|
if browser_path:
|
|
@@ -146,17 +146,27 @@ class StealthBrowser:
|
|
|
146
146
|
self._browser = Chromium(co)
|
|
147
147
|
self._page = self._browser.latest_tab
|
|
148
148
|
|
|
149
|
+
# 如果浏览器已崩溃或无法获取 tab
|
|
150
|
+
if not self._page:
|
|
151
|
+
return SkillResult(
|
|
152
|
+
success=False,
|
|
153
|
+
error="启动浏览器后无法获取页面标签(Chrome 可能未正确启动)",
|
|
154
|
+
)
|
|
155
|
+
|
|
149
156
|
# 隐藏 webdriver 标志(额外注入)
|
|
150
157
|
try:
|
|
151
|
-
self._page.run_js(
|
|
152
|
-
Object.defineProperty(navigator,
|
|
153
|
-
Object.defineProperty(navigator,
|
|
154
|
-
Object.defineProperty(navigator,
|
|
155
|
-
window.chrome
|
|
156
|
-
|
|
158
|
+
self._page.run_js(
|
|
159
|
+
"Object.defineProperty(navigator,'webdriver',{get:()=>undefined});"
|
|
160
|
+
"Object.defineProperty(navigator,'plugins',{get:()=>[1,2,3,4,5]});"
|
|
161
|
+
"Object.defineProperty(navigator,'languages',{get:()=>['zh-CN','zh','en']});"
|
|
162
|
+
"window.chrome={runtime:{}};"
|
|
163
|
+
)
|
|
157
164
|
except Exception as e:
|
|
158
165
|
logger.debug(f"反检测 JS 注入提示: {e}")
|
|
159
166
|
|
|
167
|
+
# 等待浏览器完全就绪
|
|
168
|
+
time.sleep(1)
|
|
169
|
+
|
|
160
170
|
self._started = True
|
|
161
171
|
logger.info(
|
|
162
172
|
f"反检测浏览器已启动 (profile={self.profile_name}, "
|
|
@@ -177,17 +187,18 @@ class StealthBrowser:
|
|
|
177
187
|
|
|
178
188
|
async def close(self) -> SkillResult:
|
|
179
189
|
"""关闭浏览器"""
|
|
190
|
+
self._started = False
|
|
180
191
|
try:
|
|
181
192
|
if self._browser:
|
|
182
193
|
self._browser.quit()
|
|
183
194
|
self._browser = None
|
|
184
195
|
self._page = None
|
|
185
|
-
self._started = False
|
|
186
196
|
logger.info("反检测浏览器已关闭")
|
|
187
197
|
return SkillResult(success=True, message="浏览器已关闭")
|
|
188
198
|
except Exception as e:
|
|
189
199
|
logger.error(f"关闭浏览器异常: {e}")
|
|
190
|
-
|
|
200
|
+
self._browser = None
|
|
201
|
+
self._page = None
|
|
191
202
|
return SkillResult(success=True, message="浏览器已关闭")
|
|
192
203
|
|
|
193
204
|
async def navigate(self, url: str, wait: float = 2.0) -> SkillResult:
|
|
@@ -198,7 +209,7 @@ class StealthBrowser:
|
|
|
198
209
|
try:
|
|
199
210
|
self._page.get(url)
|
|
200
211
|
if wait > 0:
|
|
201
|
-
|
|
212
|
+
await asyncio.sleep(wait)
|
|
202
213
|
|
|
203
214
|
title = self._page.title or ""
|
|
204
215
|
current_url = self._page.url or ""
|
|
@@ -225,7 +236,7 @@ class StealthBrowser:
|
|
|
225
236
|
)
|
|
226
237
|
ele.click()
|
|
227
238
|
if wait > 0:
|
|
228
|
-
|
|
239
|
+
await asyncio.sleep(wait)
|
|
229
240
|
return SkillResult(success=True, message=f"已点击: {selector}")
|
|
230
241
|
except Exception as e:
|
|
231
242
|
return SkillResult(success=False, error=f"点击失败: {e}")
|
|
@@ -248,7 +259,7 @@ class StealthBrowser:
|
|
|
248
259
|
ele.clear()
|
|
249
260
|
ele.input(value)
|
|
250
261
|
if wait > 0:
|
|
251
|
-
|
|
262
|
+
await asyncio.sleep(wait)
|
|
252
263
|
return SkillResult(
|
|
253
264
|
success=True,
|
|
254
265
|
message=f"已填写 {selector}: {value[:50]}{'...' if len(value) > 50 else ''}",
|
|
@@ -303,7 +314,17 @@ class StealthBrowser:
|
|
|
303
314
|
return SkillResult(success=False, error="浏览器未启动")
|
|
304
315
|
|
|
305
316
|
try:
|
|
306
|
-
|
|
317
|
+
# Bug Fix: DrissionPage 没有 page.text 属性
|
|
318
|
+
# 需要通过 page.ele('tag:html').text 获取页面文本
|
|
319
|
+
try:
|
|
320
|
+
text = self._page.ele('tag:html').text or ""
|
|
321
|
+
except Exception:
|
|
322
|
+
# 降级:用 BS4 从 html 提取文本
|
|
323
|
+
try:
|
|
324
|
+
from bs4 import BeautifulSoup
|
|
325
|
+
text = BeautifulSoup(self._page.html or "", "html.parser").get_text(strip=True, separator="\n")
|
|
326
|
+
except Exception:
|
|
327
|
+
text = ""
|
|
307
328
|
title = self._page.title or ""
|
|
308
329
|
url = self._page.url or ""
|
|
309
330
|
|
|
@@ -375,16 +396,21 @@ class StealthBrowser:
|
|
|
375
396
|
return SkillResult(success=False, error="浏览器未启动")
|
|
376
397
|
|
|
377
398
|
try:
|
|
399
|
+
# DrissionPage cookies() 返回 CookiesList(list 子类),每项是 dict
|
|
378
400
|
cookies = self._page.cookies()
|
|
379
401
|
cookie_list = []
|
|
380
402
|
if cookies:
|
|
381
403
|
for c in cookies:
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
404
|
+
# CookiesList 中的每项是 dict,但 key 可能不全
|
|
405
|
+
if isinstance(c, dict):
|
|
406
|
+
cookie_list.append({
|
|
407
|
+
"name": c.get("name", ""),
|
|
408
|
+
"value": c.get("value", ""),
|
|
409
|
+
"domain": c.get("domain", ""),
|
|
410
|
+
"path": c.get("path", "/"),
|
|
411
|
+
})
|
|
412
|
+
else:
|
|
413
|
+
cookie_list.append(str(c))
|
|
388
414
|
|
|
389
415
|
return SkillResult(
|
|
390
416
|
success=True,
|
|
@@ -404,10 +430,15 @@ class StealthBrowser:
|
|
|
404
430
|
cookie_list = []
|
|
405
431
|
if cookies:
|
|
406
432
|
for c in cookies:
|
|
407
|
-
|
|
433
|
+
# CookiesList 中每项是 dict,确保可序列化
|
|
434
|
+
if isinstance(c, dict):
|
|
435
|
+
cookie_list.append(dict(c))
|
|
436
|
+
else:
|
|
437
|
+
cookie_list.append(str(c))
|
|
408
438
|
|
|
409
439
|
from core.browser_profile import get_browser_profile_manager
|
|
410
440
|
mgr = get_browser_profile_manager()
|
|
441
|
+
# 保存时用 profile_name 对应的原始 BrowserProfile(不加 user_data 子路径)
|
|
411
442
|
profile = mgr.get_profile(self.profile_name)
|
|
412
443
|
profile.save_cookies(cookie_list)
|
|
413
444
|
|
|
@@ -430,6 +461,8 @@ class StealthBrowser:
|
|
|
430
461
|
cookies = profile.load_cookies()
|
|
431
462
|
|
|
432
463
|
if cookies:
|
|
464
|
+
# Bug Fix: page.set.cookies 是 CookiesSetter 对象(可调用)
|
|
465
|
+
# 直接调用 page.set.cookies(cookies_list) 即可
|
|
433
466
|
self._page.set.cookies(cookies)
|
|
434
467
|
return SkillResult(
|
|
435
468
|
success=True,
|
|
@@ -449,7 +482,13 @@ class StealthBrowser:
|
|
|
449
482
|
return SkillResult(success=False, error="浏览器未启动")
|
|
450
483
|
|
|
451
484
|
try:
|
|
452
|
-
|
|
485
|
+
# Bug Fix: DrissionPage 没有 page.clear_cookies() 方法
|
|
486
|
+
# 正确方式是 page.set.cookies.clear() 或 page.clear_cache()
|
|
487
|
+
try:
|
|
488
|
+
self._page.set.cookies.clear()
|
|
489
|
+
except Exception:
|
|
490
|
+
self._page.clear_cache(cookies=True)
|
|
491
|
+
|
|
453
492
|
from core.browser_profile import get_browser_profile_manager
|
|
454
493
|
mgr = get_browser_profile_manager()
|
|
455
494
|
profile = mgr.get_profile(self.profile_name)
|
|
@@ -479,13 +518,17 @@ class StealthBrowser:
|
|
|
479
518
|
)
|
|
480
519
|
logger.info(f"[{self.profile_name}] 等待用户手动操作: {reason}")
|
|
481
520
|
|
|
482
|
-
#
|
|
521
|
+
# Bug Fix: 使用 asyncio.sleep 避免阻塞事件循环
|
|
483
522
|
start = time.time()
|
|
484
523
|
last_url = self._page.url if self._page else ""
|
|
524
|
+
poll_interval = 3
|
|
485
525
|
while time.time() - start < timeout:
|
|
486
|
-
|
|
526
|
+
await asyncio.sleep(poll_interval)
|
|
487
527
|
if self._page:
|
|
488
|
-
|
|
528
|
+
try:
|
|
529
|
+
current_url = self._page.url or ""
|
|
530
|
+
except Exception:
|
|
531
|
+
break # 浏览器已关闭
|
|
489
532
|
# 如果 URL 发生变化,说明用户完成了操作
|
|
490
533
|
if current_url != last_url and current_url:
|
|
491
534
|
elapsed = int(time.time() - start)
|
|
@@ -506,11 +549,13 @@ class StealthBrowser:
|
|
|
506
549
|
if not self._started or not self._page:
|
|
507
550
|
return False
|
|
508
551
|
try:
|
|
509
|
-
#
|
|
552
|
+
# 检查页面是否仍然有效(try 访问 url,如果浏览器已崩溃会抛异常)
|
|
510
553
|
_ = self._page.url
|
|
511
554
|
return True
|
|
512
555
|
except Exception:
|
|
513
|
-
|
|
556
|
+
# 不要在这里重置 _started,由 close() 方法负责
|
|
557
|
+
# 避免在异步上下文中误判
|
|
558
|
+
logger.debug(f"页面检查失败 (profile={self.profile_name}),浏览器可能已关闭")
|
|
514
559
|
return False
|
|
515
560
|
|
|
516
561
|
@staticmethod
|
|
@@ -560,10 +605,10 @@ class StealthBrowser:
|
|
|
560
605
|
# ── 全局浏览器实例管理 ──────────────────────────────────────
|
|
561
606
|
|
|
562
607
|
_browsers: Dict[str, StealthBrowser] = {}
|
|
563
|
-
_browser_lock =
|
|
608
|
+
_browser_lock = threading.Lock()
|
|
564
609
|
|
|
565
610
|
|
|
566
|
-
|
|
611
|
+
def get_stealth_browser(
|
|
567
612
|
profile_name: str = "default",
|
|
568
613
|
headless: bool = False,
|
|
569
614
|
) -> StealthBrowser:
|
|
@@ -571,8 +616,9 @@ async def get_stealth_browser(
|
|
|
571
616
|
获取反检测浏览器实例(按 profile_name 复用)。
|
|
572
617
|
|
|
573
618
|
同一 profile 名称返回相同实例,避免重复启动。
|
|
619
|
+
Bug Fix: 改用同步锁 + 同步返回,避免在非 async 上下文中死锁。
|
|
574
620
|
"""
|
|
575
|
-
|
|
621
|
+
with _browser_lock:
|
|
576
622
|
if profile_name in _browsers:
|
|
577
623
|
browser = _browsers[profile_name]
|
|
578
624
|
if browser._started and browser._ensure_page():
|
|
@@ -583,21 +629,37 @@ async def get_stealth_browser(
|
|
|
583
629
|
return browser
|
|
584
630
|
|
|
585
631
|
|
|
586
|
-
|
|
587
|
-
"""
|
|
588
|
-
|
|
632
|
+
def close_stealth_browser(profile_name: str = "") -> None:
|
|
633
|
+
"""关闭浏览器实例(同步版本)"""
|
|
634
|
+
with _browser_lock:
|
|
589
635
|
if profile_name and profile_name in _browsers:
|
|
590
|
-
|
|
636
|
+
browser = _browsers[profile_name]
|
|
637
|
+
# 同步调用内部关闭逻辑
|
|
638
|
+
browser._started = False
|
|
639
|
+
try:
|
|
640
|
+
if browser._browser:
|
|
641
|
+
browser._browser.quit()
|
|
642
|
+
except Exception:
|
|
643
|
+
pass
|
|
644
|
+
browser._browser = None
|
|
645
|
+
browser._page = None
|
|
591
646
|
del _browsers[profile_name]
|
|
592
647
|
elif not profile_name:
|
|
593
648
|
for name, browser in _browsers.items():
|
|
594
649
|
try:
|
|
595
|
-
|
|
650
|
+
browser._started = False
|
|
651
|
+
if browser._browser:
|
|
652
|
+
browser._browser.quit()
|
|
596
653
|
except Exception:
|
|
597
654
|
pass
|
|
598
655
|
_browsers.clear()
|
|
599
656
|
|
|
600
657
|
|
|
658
|
+
async def close_stealth_browser_async(profile_name: str = "") -> None:
|
|
659
|
+
"""关闭浏览器实例(异步版本,供 async 上下文调用)"""
|
|
660
|
+
close_stealth_browser(profile_name)
|
|
661
|
+
|
|
662
|
+
|
|
601
663
|
# ── 技能类(供 SkillRegistry 自动发现)─────────────────────
|
|
602
664
|
|
|
603
665
|
|
|
@@ -783,7 +845,8 @@ class StealthBrowserCloseSkill(Skill):
|
|
|
783
845
|
]
|
|
784
846
|
|
|
785
847
|
async def execute(self, profile: str = "", **kw) -> SkillResult:
|
|
786
|
-
|
|
848
|
+
# close_stealth_browser 现在是同步函数,直接调用
|
|
849
|
+
close_stealth_browser(profile_name=profile)
|
|
787
850
|
return SkillResult(success=True, message="浏览器已关闭")
|
|
788
851
|
|
|
789
852
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: site-douyin
|
|
3
|
+
description: |
|
|
4
|
+
抖音操作指南 — 使用反检测浏览器操作抖音网页版,包括登录、浏览、发布视频、评论等。
|
|
5
|
+
依赖 stealth browser (DrissionPage),使用独立 Profile: douyin
|
|
6
|
+
metadata:
|
|
7
|
+
category: site_operation
|
|
8
|
+
version: "1.30.0"
|
|
9
|
+
requires: ["stealth-browser"]
|
|
10
|
+
profile: "douyin"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# 抖音操作
|
|
14
|
+
|
|
15
|
+
## 概述
|
|
16
|
+
|
|
17
|
+
使用反检测浏览器操作抖音网页版。Profile 名称: `douyin`。
|
|
18
|
+
|
|
19
|
+
## 前置条件
|
|
20
|
+
|
|
21
|
+
1. 首次使用需要用户登录抖音
|
|
22
|
+
2. 抖音支持手机号登录、扫码登录、第三方登录
|
|
23
|
+
3. 登录成功后保存 Cookie
|
|
24
|
+
|
|
25
|
+
## 操作流程
|
|
26
|
+
|
|
27
|
+
### 1. 首次登录设置
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
stealth-open douyin --no-headless
|
|
31
|
+
stealth-navigate https://www.douyin.com/ -p douyin
|
|
32
|
+
stealth-screenshot -p douyin
|
|
33
|
+
|
|
34
|
+
# 抖音通常弹出登录提示
|
|
35
|
+
# 手机号登录:
|
|
36
|
+
stealth-click 'text=手机号登录' -p douyin
|
|
37
|
+
stealth-wait 1 -p douyin
|
|
38
|
+
stealth-fill 'input[type="tel"]' '手机号' -p douyin
|
|
39
|
+
stealth-click 'button:contains("获取验证码")' -p douyin
|
|
40
|
+
stealth-wait-manual "输入短信验证码" -t 300 -p douyin
|
|
41
|
+
|
|
42
|
+
# 或者直接等待用户扫码
|
|
43
|
+
stealth-wait-manual "抖音登录" -t 300 -p douyin
|
|
44
|
+
|
|
45
|
+
stealth-cookies save -p douyin
|
|
46
|
+
stealth-close douyin
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. 浏览首页推荐
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
stealth-open douyin --no-headless
|
|
53
|
+
stealth-navigate https://www.douyin.com/ -p douyin
|
|
54
|
+
stealth-wait 5 -p douyin
|
|
55
|
+
stealth-screenshot -p douyin
|
|
56
|
+
stealth-content -p douyin
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3. 搜索视频
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
stealth-navigate 'https://www.douyin.com/search/关键词' -p douyin
|
|
63
|
+
stealth-wait 5 -p douyin
|
|
64
|
+
stealth-content -p douyin
|
|
65
|
+
stealth-screenshot -p douyin
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 4. 发布视频
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# 进入创作者中心
|
|
72
|
+
stealth-navigate https://creator.douyin.com/ -p douyin
|
|
73
|
+
stealth-wait 5 -p douyin
|
|
74
|
+
stealth-screenshot -p douyin
|
|
75
|
+
|
|
76
|
+
# 点击发布视频
|
|
77
|
+
stealth-click 'text=发布视频' -p douyin
|
|
78
|
+
stealth-wait 2 -p douyin
|
|
79
|
+
|
|
80
|
+
# 抖音网页版上传视频需要通过文件选择器
|
|
81
|
+
# 注意:网页版上传功能可能有限制
|
|
82
|
+
stealth-screenshot -p douyin
|
|
83
|
+
stealth-content -p douyin
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 5. 查看个人主页
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
stealth-navigate https://www.douyin.com/ -p douyin
|
|
90
|
+
stealth-wait 3 -p douyin
|
|
91
|
+
stealth-click 'div[data-e2e="user-info"]' -p douyin
|
|
92
|
+
stealth-wait 3 -p douyin
|
|
93
|
+
stealth-content -p douyin
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 6. 评论
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# 打开视频页面后
|
|
100
|
+
stealth-click 'div[data-e2e="feed-comment-icon"]' -p douyin
|
|
101
|
+
stealth-wait 1 -p douyin
|
|
102
|
+
stealth-fill 'input[data-e2e="comment-input"]' '评论内容...' -p douyin
|
|
103
|
+
stealth-click 'button:contains("发送")' -p douyin
|
|
104
|
+
stealth-wait 3 -p douyin
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 抖音常用 URL
|
|
108
|
+
|
|
109
|
+
| 功能 | URL |
|
|
110
|
+
|---|---|
|
|
111
|
+
| 首页 | `https://www.douyin.com/` |
|
|
112
|
+
| 搜索 | `https://www.douyin.com/search/关键词` |
|
|
113
|
+
| 创作者中心 | `https://creator.douyin.com/` |
|
|
114
|
+
| 数据中心 | `https://creator.douyin.com/data` |
|
|
115
|
+
| 热榜 | `https://www.douyin.com/hot` |
|
|
116
|
+
|
|
117
|
+
## 重要提示
|
|
118
|
+
|
|
119
|
+
1. 抖音网页版功能有限,部分操作(如发布视频)可能需要创作者中心
|
|
120
|
+
2. 抖音对自动化操作检测严格,反检测浏览器必不可少
|
|
121
|
+
3. 上传视频需要处理文件选择器,可能需要使用 `stealth-eval` 执行 JS
|
|
122
|
+
4. 抖音页面使用大量前端框架渲染,元素加载需要充分等待
|
|
123
|
+
5. Cookie 过期较快,频繁操作时注意检查登录状态
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: site-gmail
|
|
3
|
+
description: |
|
|
4
|
+
Gmail 邮箱操作指南 — 使用反检测浏览器操作 Gmail,包括登录、收发邮件、搜索邮件、读取邮件内容等。
|
|
5
|
+
依赖 stealth browser (DrissionPage),使用独立 Profile: gmail
|
|
6
|
+
metadata:
|
|
7
|
+
category: site_operation
|
|
8
|
+
version: "1.30.0"
|
|
9
|
+
requires: ["stealth-browser"]
|
|
10
|
+
profile: "gmail"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Gmail 邮箱操作
|
|
14
|
+
|
|
15
|
+
## 概述
|
|
16
|
+
|
|
17
|
+
使用反检测浏览器操作 Gmail 邮箱。Profile 名称: `gmail`。
|
|
18
|
+
|
|
19
|
+
## 前置条件
|
|
20
|
+
|
|
21
|
+
1. 首次使用前,需要用户通过 `stealth-wait-manual` 手动完成 Google 登录(含验证码/2FA)
|
|
22
|
+
2. 登录成功后执行 `stealth-cookies save` 保存登录状态
|
|
23
|
+
3. 后续访问自动恢复登录态
|
|
24
|
+
|
|
25
|
+
## 操作流程
|
|
26
|
+
|
|
27
|
+
### 1. 首次登录设置
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
stealth-open gmail --no-headless
|
|
31
|
+
stealth-navigate https://accounts.google.com/signin -p gmail
|
|
32
|
+
stealth-screenshot -p gmail
|
|
33
|
+
|
|
34
|
+
# 填写账号密码(如果页面允许自动化填写)
|
|
35
|
+
stealth-fill 'input[type="email"]' 'user@gmail.com' -p gmail
|
|
36
|
+
stealth-click 'button:contains("下一步")' -p gmail
|
|
37
|
+
stealth-wait 'input[type="password"]' -p gmail
|
|
38
|
+
stealth-fill 'input[type="password"]' 'password' -p gmail
|
|
39
|
+
stealth-click 'button:contains("下一步")' -p gmail
|
|
40
|
+
|
|
41
|
+
# 如果出现验证码,等待用户手动操作
|
|
42
|
+
stealth-wait-manual "Google验证码或2FA" -t 300 -p gmail
|
|
43
|
+
|
|
44
|
+
# 登录成功后保存 Cookie
|
|
45
|
+
stealth-cookies save -p gmail
|
|
46
|
+
stealth-close gmail
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. 读取收件箱邮件
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
stealth-open gmail --no-headless
|
|
53
|
+
stealth-navigate https://mail.google.com/mail/u/0/#inbox -p gmail
|
|
54
|
+
stealth-wait 'table[class="F cf zt"]' -t 15 -p gmail
|
|
55
|
+
stealth-screenshot -p gmail
|
|
56
|
+
stealth-content -p gmail
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3. 搜索邮件
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
stealth-navigate 'https://mail.google.com/mail/u/0/#search/关键词' -p gmail
|
|
63
|
+
stealth-wait 3 -p gmail
|
|
64
|
+
stealth-screenshot -p gmail
|
|
65
|
+
stealth-content -p gmail
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 4. 读取邮件详情
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# 点击邮件主题行打开邮件
|
|
72
|
+
stealth-click 'tr.zE:contains("邮件主题关键词")' -p gmail
|
|
73
|
+
stealth-wait 2 -p gmail
|
|
74
|
+
stealth-content -p gmail
|
|
75
|
+
stealth-screenshot -p gmail
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 5. 发送邮件
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# 点击写邮件按钮
|
|
82
|
+
stealth-click 'div.T-I.T-I-KE.L3' -p gmail
|
|
83
|
+
stealth-wait 'textarea[name="to"]' -p gmail
|
|
84
|
+
|
|
85
|
+
# 填写收件人
|
|
86
|
+
stealth-fill 'textarea[name="to"]' 'recipient@example.com' -p gmail
|
|
87
|
+
|
|
88
|
+
# 填写主题
|
|
89
|
+
stealth-fill 'input[name="subjectbox"]' '邮件主题' -p gmail
|
|
90
|
+
|
|
91
|
+
# 填写正文
|
|
92
|
+
stealth-fill 'div[aria-label="邮件正文"]' '邮件正文内容' -p gmail
|
|
93
|
+
|
|
94
|
+
# 点击发送
|
|
95
|
+
stealth-click 'div.T-I.T-I-KE.L3:contains("发送")' -p gmail
|
|
96
|
+
stealth-wait 3 -p gmail
|
|
97
|
+
stealth-screenshot -p gmail
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 6. 查看附件
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# 打开含附件的邮件后
|
|
104
|
+
stealth-content -p gmail
|
|
105
|
+
# 附件链接会出现在页面内容中
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Gmail 常用 URL
|
|
109
|
+
|
|
110
|
+
| 功能 | URL |
|
|
111
|
+
|---|---|
|
|
112
|
+
| 收件箱 | `https://mail.google.com/mail/u/0/#inbox` |
|
|
113
|
+
| 已发送 | `https://mail.google.com/mail/u/0/#sent` |
|
|
114
|
+
| 草稿箱 | `https://mail.google.com/mail/u/0/#drafts` |
|
|
115
|
+
| 垃圾邮件 | `https://mail.google.com/mail/u/0/#spam` |
|
|
116
|
+
| 搜索 | `https://mail.google.com/mail/u/0/#search/关键词` |
|
|
117
|
+
|
|
118
|
+
## 重要提示
|
|
119
|
+
|
|
120
|
+
1. Google 登录安全严格,首次登录大概率需要人工处理验证码/手机验证
|
|
121
|
+
2. 建议使用 `--no-headless` 有头模式,方便通过 VNC 观察和操作
|
|
122
|
+
3. Gmail 页面使用大量动态渲染,导航后需要 `stealth-wait` 等待元素加载
|
|
123
|
+
4. 如果 Cookie 失效,需要重新走登录流程
|
|
124
|
+
5. Google 可能检测到新设备/IP 并要求安全验证
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: site-mail139
|
|
3
|
+
description: |
|
|
4
|
+
139邮箱操作指南 — 使用反检测浏览器操作中国移动139邮箱,包括登录、收发邮件、搜索邮件等。
|
|
5
|
+
依赖 stealth browser (DrissionPage),使用独立 Profile: mail139
|
|
6
|
+
metadata:
|
|
7
|
+
category: site_operation
|
|
8
|
+
version: "1.30.0"
|
|
9
|
+
requires: ["stealth-browser"]
|
|
10
|
+
profile: "mail139"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# 139邮箱操作
|
|
14
|
+
|
|
15
|
+
## 概述
|
|
16
|
+
|
|
17
|
+
使用反检测浏览器操作中国移动139邮箱。Profile 名称: `mail139`。
|
|
18
|
+
|
|
19
|
+
## 前置条件
|
|
20
|
+
|
|
21
|
+
1. 首次使用需要用户登录139邮箱
|
|
22
|
+
2. 支持139手机号+密码、短信验证登录
|
|
23
|
+
3. 登录成功后保存 Cookie
|
|
24
|
+
|
|
25
|
+
## 操作流程
|
|
26
|
+
|
|
27
|
+
### 1. 首次登录设置
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
stealth-open mail139 --no-headless
|
|
31
|
+
stealth-navigate https://mail.10086.cn/ -p mail139
|
|
32
|
+
stealth-screenshot -p mail139
|
|
33
|
+
|
|
34
|
+
# 填写手机号和密码
|
|
35
|
+
stealth-fill 'input[name="UserName"]' '139xxxxx' -p mail139
|
|
36
|
+
stealth-fill 'input[name="Password"]' 'password' -p mail139
|
|
37
|
+
stealth-click 'input[type="submit"]' -p mail139
|
|
38
|
+
|
|
39
|
+
# 可能需要短信验证
|
|
40
|
+
stealth-wait-manual "139邮箱短信验证" -t 300 -p mail139
|
|
41
|
+
|
|
42
|
+
stealth-cookies save -p mail139
|
|
43
|
+
stealth-close mail139
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. 读取收件箱
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
stealth-open mail139 --no-headless
|
|
50
|
+
stealth-navigate https://mail.10086.cn/ -p mail139
|
|
51
|
+
stealth-cookies load -p mail139
|
|
52
|
+
stealth-wait 5 -p mail139
|
|
53
|
+
stealth-screenshot -p mail139
|
|
54
|
+
stealth-content -p mail139
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 3. 搜索邮件
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
stealth-navigate 'https://mail.10086.cn/rm/mailbox' -p mail139
|
|
61
|
+
stealth-wait 3 -p mail139
|
|
62
|
+
stealth-fill 'input[placeholder*="搜索"]' '搜索关键词' -p mail139
|
|
63
|
+
stealth-click 'button:contains("搜索")' -p mail139
|
|
64
|
+
stealth-wait 3 -p mail139
|
|
65
|
+
stealth-content -p mail139
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 4. 发送邮件
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# 点击写邮件
|
|
72
|
+
stealth-click 'text=写邮件' -p mail139
|
|
73
|
+
stealth-wait 2 -p mail139
|
|
74
|
+
|
|
75
|
+
# 填写收件人
|
|
76
|
+
stealth-fill 'input[name="to"]' 'recipient@example.com' -p mail139
|
|
77
|
+
|
|
78
|
+
# 填写主题
|
|
79
|
+
stealth-fill 'input[name="subject"]' '邮件主题' -p mail139
|
|
80
|
+
|
|
81
|
+
# 填写正文
|
|
82
|
+
stealth-fill 'body#ComposeBody' '邮件正文内容...' -p mail139
|
|
83
|
+
|
|
84
|
+
# 发送
|
|
85
|
+
stealth-click 'text=发送' -p mail139
|
|
86
|
+
stealth-wait 3 -p mail139
|
|
87
|
+
stealth-screenshot -p mail139
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 5. 读取邮件详情
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# 点击邮件列表中的邮件
|
|
94
|
+
stealth-click 'div.mailItem:contains("邮件主题")' -p mail139
|
|
95
|
+
stealth-wait 2 -p mail139
|
|
96
|
+
stealth-content -p mail139
|
|
97
|
+
stealth-screenshot -p mail139
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## 139邮箱常用 URL
|
|
101
|
+
|
|
102
|
+
| 功能 | URL |
|
|
103
|
+
|---|---|
|
|
104
|
+
| 登录页 | `https://mail.10086.cn/` |
|
|
105
|
+
| 收件箱 | `https://mail.10086.cn/rm/mailbox` |
|
|
106
|
+
| 已发送 | `https://mail.10086.cn/rm/sent` |
|
|
107
|
+
| 草稿箱 | `https://mail.10086.cn/rm/drafts` |
|
|
108
|
+
| 通讯录 | `https://mail.10086.cn/rm/contacts` |
|
|
109
|
+
|
|
110
|
+
## 重要提示
|
|
111
|
+
|
|
112
|
+
1. 139邮箱登录时可能需要短信验证码,使用 `stealth-wait-manual` 等待用户输入
|
|
113
|
+
2. 139邮箱页面结构相对传统,选择器较稳定
|
|
114
|
+
3. Cookie 有效期通常较长(几天到几周)
|
|
115
|
+
4. 139邮箱支持附件上传,可通过文件选择器操作
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: site-wechat-mp
|
|
3
|
+
description: |
|
|
4
|
+
微信公众号平台操作指南 — 使用反检测浏览器操作微信公众号后台,包括登录、发布图文、查看数据等。
|
|
5
|
+
依赖 stealth browser (DrissionPage),使用独立 Profile: wechat_mp
|
|
6
|
+
metadata:
|
|
7
|
+
category: site_operation
|
|
8
|
+
version: "1.30.0"
|
|
9
|
+
requires: ["stealth-browser"]
|
|
10
|
+
profile: "wechat_mp"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# 微信公众号平台操作
|
|
14
|
+
|
|
15
|
+
## 概述
|
|
16
|
+
|
|
17
|
+
使用反检测浏览器操作微信公众号后台管理平台。Profile 名称: `wechat_mp`。
|
|
18
|
+
|
|
19
|
+
## 前置条件
|
|
20
|
+
|
|
21
|
+
1. 首次使用需要用户**扫码登录**微信公众号后台
|
|
22
|
+
2. 微信公众号后台仅支持扫码登录,无法通过账号密码自动登录
|
|
23
|
+
3. 登录成功后保存 Cookie
|
|
24
|
+
4. Cookie 有效期通常为几小时到一天
|
|
25
|
+
|
|
26
|
+
## 操作流程
|
|
27
|
+
|
|
28
|
+
### 1. 首次登录设置(必须人工扫码)
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
stealth-open wechat_mp --no-headless
|
|
32
|
+
stealth-navigate https://mp.weixin.qq.com/ -p wechat_mp
|
|
33
|
+
stealth-screenshot -p wechat_mp
|
|
34
|
+
|
|
35
|
+
# 等待用户扫码登录
|
|
36
|
+
stealth-wait-manual "扫码登录微信公众号" -t 300 -p wechat_mp
|
|
37
|
+
|
|
38
|
+
# 登录成功后保存 Cookie
|
|
39
|
+
stealth-cookies save -p wechat_mp
|
|
40
|
+
stealth-screenshot -p wechat_mp
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 2. 发布图文消息
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
stealth-open wechat_mp --no-headless
|
|
47
|
+
stealth-navigate https://mp.weixin.qq.com/ -p wechat_mp
|
|
48
|
+
stealth-cookies load -p wechat_mp
|
|
49
|
+
stealth-wait 3 -p wechat_mp
|
|
50
|
+
|
|
51
|
+
# 进入素材管理 -> 新建图文
|
|
52
|
+
stealth-click 'text=素材管理' -p wechat_mp
|
|
53
|
+
stealth-wait 2 -p wechat_mp
|
|
54
|
+
stealth-click 'text=新建图文' -p wechat_mp
|
|
55
|
+
stealth-wait 3 -p wechat_mp
|
|
56
|
+
|
|
57
|
+
# 填写标题
|
|
58
|
+
stealth-fill 'input#title' '文章标题' -p wechat_mp
|
|
59
|
+
|
|
60
|
+
# 填写作者(可选)
|
|
61
|
+
stealth-fill 'input#author' '作者名' -p wechat_mp
|
|
62
|
+
|
|
63
|
+
# 填写正文
|
|
64
|
+
# 微信编辑器使用 iframe 或 contenteditable div
|
|
65
|
+
stealth-click 'div#edui1_body' -p wechat_mp
|
|
66
|
+
stealth-fill 'div#edui1_body' '文章正文内容...' -p wechat_mp
|
|
67
|
+
|
|
68
|
+
# 保存并群发
|
|
69
|
+
stealth-screenshot -p wechat_mp
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 3. 查看消息
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
stealth-navigate https://mp.weixin.qq.com/cgi-bin/message?t=message/list -p wechat_mp
|
|
76
|
+
stealth-wait 3 -p wechat_mp
|
|
77
|
+
stealth-content -p wechat_mp
|
|
78
|
+
stealth-screenshot -p wechat_mp
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 4. 查看用户管理
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
stealth-navigate https://mp.weixin.qq.com/cgi-bin/contactmanagepage?t=user/index -p wechat_mp
|
|
85
|
+
stealth-wait 3 -p wechat_mp
|
|
86
|
+
stealth-content -p wechat_mp
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 5. 查看数据统计
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
stealth-navigate https://mp.weixin.qq.com/cgi-bin/home?t=home/index -p wechat_mp
|
|
93
|
+
stealth-wait 3 -p wechat_mp
|
|
94
|
+
stealth-content -p wechat_mp
|
|
95
|
+
stealth-screenshot -p wechat_mp
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 微信公众号常用 URL
|
|
99
|
+
|
|
100
|
+
| 功能 | URL |
|
|
101
|
+
|---|---|
|
|
102
|
+
| 首页 | `https://mp.weixin.qq.com/cgi-bin/home?t=home/index` |
|
|
103
|
+
| 消息管理 | `https://mp.weixin.qq.com/cgi-bin/message?t=message/list` |
|
|
104
|
+
| 素材管理 | `https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit` |
|
|
105
|
+
| 用户管理 | `https://mp.weixin.qq.com/cgi-bin/contactmanagepage?t=user/index` |
|
|
106
|
+
| 数据统计 | `https://mp.weixin.qq.com/cgi-bin/stats` |
|
|
107
|
+
| 设置 | `https://mp.weixin.qq.com/cgi-bin/settingpage?t=setting/index` |
|
|
108
|
+
|
|
109
|
+
## 重要提示
|
|
110
|
+
|
|
111
|
+
1. 微信公众号后台**仅支持扫码登录**,无法自动化输入账号密码
|
|
112
|
+
2. Cookie 有效期较短(几小时),可能需要频繁重新登录
|
|
113
|
+
3. 微信编辑器结构复杂,操作前务必截图确认
|
|
114
|
+
4. 群发操作有频率限制,每日 1 次服务号、多次订阅号
|
|
115
|
+
5. 敏感操作(群发/删除)可能需要管理员二次确认
|
|
116
|
+
6. 建议配合 `--no-headless` 和 VNC 使用,方便观察扫码页面
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: site-weibo
|
|
3
|
+
description: |
|
|
4
|
+
微博 操作指南 — 使用反检测浏览器操作新浪微博,包括登录、浏览、发微博、转发、评论等。
|
|
5
|
+
依赖 stealth browser (DrissionPage),使用独立 Profile: weibo
|
|
6
|
+
metadata:
|
|
7
|
+
category: site_operation
|
|
8
|
+
version: "1.30.0"
|
|
9
|
+
requires: ["stealth-browser"]
|
|
10
|
+
profile: "weibo"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# 微博操作
|
|
14
|
+
|
|
15
|
+
## 概述
|
|
16
|
+
|
|
17
|
+
使用反检测浏览器操作新浪微博。Profile 名称: `weibo`。
|
|
18
|
+
|
|
19
|
+
## 前置条件
|
|
20
|
+
|
|
21
|
+
1. 首次使用需要用户手动完成微博登录
|
|
22
|
+
2. 登录成功后保存 Cookie
|
|
23
|
+
3. 后续访问自动恢复登录态
|
|
24
|
+
|
|
25
|
+
## 操作流程
|
|
26
|
+
|
|
27
|
+
### 1. 首次登录设置
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
stealth-open weibo --no-headless
|
|
31
|
+
stealth-navigate https://passport.weibo.com/sso/signin -p weibo
|
|
32
|
+
stealth-screenshot -p weibo
|
|
33
|
+
|
|
34
|
+
# 微博支持多种登录方式(账号密码/手机/扫码)
|
|
35
|
+
# 账号密码登录:
|
|
36
|
+
stealth-fill 'input[name="username"]' 'username' -p weibo
|
|
37
|
+
stealth-fill 'input[name="password"]' 'password' -p weibo
|
|
38
|
+
stealth-click 'a[action-type="submit"]' -p weibo
|
|
39
|
+
|
|
40
|
+
# 可能需要验证码
|
|
41
|
+
stealth-wait-manual "微博验证码" -t 300 -p weibo
|
|
42
|
+
|
|
43
|
+
stealth-cookies save -p weibo
|
|
44
|
+
stealth-close weibo
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. 浏览首页
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
stealth-open weibo --no-headless
|
|
51
|
+
stealth-navigate https://weibo.com/ -p weibo
|
|
52
|
+
stealth-wait 5 -p weibo
|
|
53
|
+
stealth-screenshot -p weibo
|
|
54
|
+
stealth-content -p weibo
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 3. 发布微博
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# 点击发微博按钮
|
|
61
|
+
stealth-click 'textarea.WB_feed_editor' -p weibo
|
|
62
|
+
stealth-wait 1 -p weibo
|
|
63
|
+
|
|
64
|
+
# 输入微博内容
|
|
65
|
+
stealth-fill 'textarea.WB_feed_editor' '微博内容...' -p weibo
|
|
66
|
+
stealth-wait 1 -p weibo
|
|
67
|
+
|
|
68
|
+
# 点击发布按钮
|
|
69
|
+
stealth-click 'a[action-type="publish"]' -p weibo
|
|
70
|
+
stealth-wait 3 -p weibo
|
|
71
|
+
stealth-screenshot -p weibo
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 4. 转发微博
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# 打开目标微博页面
|
|
78
|
+
stealth-navigate 'https://weibo.com/detail/微博ID' -p weibo
|
|
79
|
+
stealth-wait 3 -p weibo
|
|
80
|
+
|
|
81
|
+
# 点击转发
|
|
82
|
+
stealth-click 'a[action-type="fl_forward"]' -p weibo
|
|
83
|
+
stealth-wait 1 -p weibo
|
|
84
|
+
|
|
85
|
+
# 填写转发理由(可选)
|
|
86
|
+
stealth-fill 'textarea.WB_feed_editor' '转发理由...' -p weibo
|
|
87
|
+
|
|
88
|
+
# 确认转发
|
|
89
|
+
stealth-click 'a[action-type="forward"]' -p weibo
|
|
90
|
+
stealth-wait 3 -p weibo
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 5. 评论
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
stealth-click 'a[action-type="fl_comment"]' -p weibo
|
|
97
|
+
stealth-wait 1 -p weibo
|
|
98
|
+
stealth-fill 'textarea.WB_feed_editor' '评论内容...' -p weibo
|
|
99
|
+
stealth-click 'a[action-type="comment"]' -p weibo
|
|
100
|
+
stealth-wait 3 -p weibo
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 6. 搜索
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
stealth-navigate 'https://s.weibo.com/weibo?q=关键词' -p weibo
|
|
107
|
+
stealth-wait 5 -p weibo
|
|
108
|
+
stealth-content -p weibo
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 7. 查看用户主页
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
stealth-navigate https://weibo.com/u/用户ID -p weibo
|
|
115
|
+
stealth-wait 3 -p weibo
|
|
116
|
+
stealth-content -p weibo
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## 微博常用 URL
|
|
120
|
+
|
|
121
|
+
| 功能 | URL |
|
|
122
|
+
|---|---|
|
|
123
|
+
| 首页 | `https://weibo.com/` |
|
|
124
|
+
| 热搜 | `https://s.weibo.com/top/summary` |
|
|
125
|
+
| 搜索 | `https://s.weibo.com/weibo?q=关键词` |
|
|
126
|
+
| 微博详情 | `https://weibo.com/detail/微博ID` |
|
|
127
|
+
| 个人主页 | `https://weibo.com/u/用户ID` |
|
|
128
|
+
| 超话 | `https://weibo.com/p/page/超话ID` |
|
|
129
|
+
|
|
130
|
+
## 重要提示
|
|
131
|
+
|
|
132
|
+
1. 微博有完善的反爬机制,建议使用 DrissionPage 反检测模式
|
|
133
|
+
2. 操作频率不要过高,避免被系统判定为机器行为
|
|
134
|
+
3. 微博页面元素经常变动,操作前务必截图确认当前页面结构
|
|
135
|
+
4. 微博可能弹出各种验证,使用 `stealth-wait-manual` 处理
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: site-x-com
|
|
3
|
+
description: |
|
|
4
|
+
X.com (Twitter) 操作指南 — 使用反检测浏览器操作 X.com,包括登录、浏览时间线、发推文、回复、点赞等。
|
|
5
|
+
依赖 stealth browser (DrissionPage),使用独立 Profile: x_com
|
|
6
|
+
metadata:
|
|
7
|
+
category: site_operation
|
|
8
|
+
version: "1.30.0"
|
|
9
|
+
requires: ["stealth-browser"]
|
|
10
|
+
profile: "x_com"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# X.com (Twitter) 操作
|
|
14
|
+
|
|
15
|
+
## 概述
|
|
16
|
+
|
|
17
|
+
使用反检测浏览器操作 X.com (Twitter)。Profile 名称: `x_com`。
|
|
18
|
+
|
|
19
|
+
## 前置条件
|
|
20
|
+
|
|
21
|
+
1. 首次使用需要用户手动完成 X.com 登录
|
|
22
|
+
2. 登录成功后保存 Cookie
|
|
23
|
+
3. 后续访问自动恢复登录态
|
|
24
|
+
|
|
25
|
+
## 操作流程
|
|
26
|
+
|
|
27
|
+
### 1. 首次登录设置
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
stealth-open x_com --no-headless
|
|
31
|
+
stealth-navigate https://x.com/i/flow/login -p x_com
|
|
32
|
+
stealth-screenshot -p x_com
|
|
33
|
+
|
|
34
|
+
# X.com 登录流程
|
|
35
|
+
stealth-fill 'input[autocomplete="username"]' 'username' -p x_com
|
|
36
|
+
stealth-click 'text=下一步' -p x_com
|
|
37
|
+
stealth-wait 'input[autocomplete="current-password"]' -p x_com
|
|
38
|
+
stealth-fill 'input[autocomplete="current-password"]' 'password' -p x_com
|
|
39
|
+
stealth-click 'text=登录' -p x_com
|
|
40
|
+
|
|
41
|
+
# 可能需要验证码
|
|
42
|
+
stealth-wait-manual "X.com验证" -t 300 -p x_com
|
|
43
|
+
|
|
44
|
+
stealth-cookies save -p x_com
|
|
45
|
+
stealth-close x_com
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. 浏览首页时间线
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
stealth-open x_com --no-headless
|
|
52
|
+
stealth-navigate https://x.com/home -p x_com
|
|
53
|
+
stealth-wait 'article' -t 15 -p x_com
|
|
54
|
+
stealth-screenshot -p x_com
|
|
55
|
+
stealth-content -p x_com
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 3. 发布推文
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
stealth-navigate https://x.com/compose/post -p x_com
|
|
62
|
+
|
|
63
|
+
# 点击发推文区域
|
|
64
|
+
stealth-click 'div[data-testid="tweetTextarea_0"]' -p x_com
|
|
65
|
+
stealth-wait 1 -p x_com
|
|
66
|
+
|
|
67
|
+
# 输入推文内容
|
|
68
|
+
stealth-fill 'div[data-testid="tweetTextarea_0"]' '推文内容...' -p x_com
|
|
69
|
+
stealth-wait 1 -p x_com
|
|
70
|
+
|
|
71
|
+
# 点击发送按钮
|
|
72
|
+
stealth-click 'button[data-testid="tweetButton"]' -p x_com
|
|
73
|
+
stealth-wait 3 -p x_com
|
|
74
|
+
stealth-screenshot -p x_com
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 4. 回复推文
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# 先导航到目标推文页面
|
|
81
|
+
stealth-navigate 'https://x.com/用户名/status/推文ID' -p x_com
|
|
82
|
+
stealth-wait 'article' -t 10 -p x_com
|
|
83
|
+
|
|
84
|
+
# 点击回复框
|
|
85
|
+
stealth-click 'div[data-testid="tweetTextarea_0"]' -p x_com
|
|
86
|
+
stealth-fill 'div[data-testid="tweetTextarea_0"]' '回复内容...' -p x_com
|
|
87
|
+
|
|
88
|
+
# 发送回复
|
|
89
|
+
stealth-click 'button[data-testid="tweetButtonInline"]' -p x_com
|
|
90
|
+
stealth-wait 3 -p x_com
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 5. 点赞/转推
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# 点赞
|
|
97
|
+
stealth-click 'button[data-testid="like"]' -p x_com
|
|
98
|
+
|
|
99
|
+
# 转推
|
|
100
|
+
stealth-click 'button[data-testid="retweet"]' -p x_com
|
|
101
|
+
stealth-click 'div[role="menuitem"]:contains("转推")' -p x_com
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 6. 搜索
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
stealth-navigate 'https://x.com/search?q=关键词&src=typed_query&f=top' -p x_com
|
|
108
|
+
stealth-wait 'article' -t 10 -p x_com
|
|
109
|
+
stealth-content -p x_com
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 7. 查看用户资料
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
stealth-navigate https://x.com/用户名 -p x_com
|
|
116
|
+
stealth-wait 3 -p x_com
|
|
117
|
+
stealth-content -p x_com
|
|
118
|
+
stealth-screenshot -p x_com
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## X.com 常用 URL
|
|
122
|
+
|
|
123
|
+
| 功能 | URL |
|
|
124
|
+
|---|---|
|
|
125
|
+
| 首页时间线 | `https://x.com/home` |
|
|
126
|
+
| 发推文 | `https://x.com/compose/post` |
|
|
127
|
+
| 通知 | `https://x.com/notifications` |
|
|
128
|
+
| 消息 | `https://x.com/messages` |
|
|
129
|
+
| 搜索 | `https://x.com/search?q=关键词` |
|
|
130
|
+
| 用户资料 | `https://x.com/用户名` |
|
|
131
|
+
| 个人设置 | `https://x.com/settings/account` |
|
|
132
|
+
|
|
133
|
+
## 重要提示
|
|
134
|
+
|
|
135
|
+
1. X.com 对自动化检测较为严格,DrissionPage 反检测模式可降低风险
|
|
136
|
+
2. 发推文、点赞等操作不宜过于频繁,避免触发频率限制
|
|
137
|
+
3. X.com 页面频繁更新,data-testid 选择器可能变化,操作前先截图确认
|
|
138
|
+
4. 建议操作间隔 3-5 秒,模拟人类操作节奏
|
package/core/browser_profile.py
CHANGED
|
@@ -141,8 +141,14 @@ class BrowserProfile:
|
|
|
141
141
|
self.profile_dir.mkdir(parents=True, exist_ok=True)
|
|
142
142
|
|
|
143
143
|
def is_initialized(self) -> bool:
|
|
144
|
-
"""检查 Profile 是否已初始化(有
|
|
145
|
-
|
|
144
|
+
"""检查 Profile 是否已初始化(有 profile 目录且包含浏览器数据)"""
|
|
145
|
+
if not self.profile_dir.is_dir():
|
|
146
|
+
return False
|
|
147
|
+
# 检查目录下是否有实际内容(不空)
|
|
148
|
+
try:
|
|
149
|
+
return any(self.profile_dir.iterdir())
|
|
150
|
+
except OSError:
|
|
151
|
+
return False
|
|
146
152
|
|
|
147
153
|
def get_size_mb(self) -> float:
|
|
148
154
|
"""获取 Profile 占用空间(MB)"""
|
package/main.py
CHANGED
|
@@ -426,6 +426,30 @@ class MyAgentApp:
|
|
|
426
426
|
]:
|
|
427
427
|
self.skill_registry.register(skill_cls())
|
|
428
428
|
|
|
429
|
+
# ── 反检测浏览器技能 (DrissionPage — v1.30.0) ──
|
|
430
|
+
try:
|
|
431
|
+
from aiskills.browser_stealth import (
|
|
432
|
+
StealthBrowserStartSkill, StealthBrowserNavigateSkill,
|
|
433
|
+
StealthBrowserClickSkill, StealthBrowserFillSkill,
|
|
434
|
+
StealthBrowserScreenshotSkill, StealthBrowserEvalSkill,
|
|
435
|
+
StealthBrowserGetContentSkill, StealthBrowserCookieSkill,
|
|
436
|
+
StealthBrowserCloseSkill, StealthBrowserWaitManualSkill,
|
|
437
|
+
StealthBrowserWaitSkill,
|
|
438
|
+
BrowserProfileListSkill, BrowserProfileCreateSkill, BrowserProfileDeleteSkill,
|
|
439
|
+
)
|
|
440
|
+
for skill_cls in [
|
|
441
|
+
StealthBrowserStartSkill, StealthBrowserNavigateSkill,
|
|
442
|
+
StealthBrowserClickSkill, StealthBrowserFillSkill,
|
|
443
|
+
StealthBrowserScreenshotSkill, StealthBrowserEvalSkill,
|
|
444
|
+
StealthBrowserGetContentSkill, StealthBrowserCookieSkill,
|
|
445
|
+
StealthBrowserCloseSkill, StealthBrowserWaitManualSkill,
|
|
446
|
+
StealthBrowserWaitSkill,
|
|
447
|
+
BrowserProfileListSkill, BrowserProfileCreateSkill, BrowserProfileDeleteSkill,
|
|
448
|
+
]:
|
|
449
|
+
self.skill_registry.register(skill_cls())
|
|
450
|
+
except ImportError as e:
|
|
451
|
+
self.logger.warning(f"反检测浏览器技能注册跳过(DrissionPage 未安装): {e}")
|
|
452
|
+
|
|
429
453
|
# ── [v1.22.0] 内置平台工具不再注册存根 ──
|
|
430
454
|
# command, recall_memory, file_send, playaudio, playvideo, web_control
|
|
431
455
|
# 由 ToolDispatcher 直接处理,其元数据通过 BUILTIN_TOOLS 常量
|
package/package.json
CHANGED
package/scripts/cli.py
CHANGED
|
@@ -859,7 +859,8 @@ async def cmd_stealth_close(args):
|
|
|
859
859
|
a = p.parse_args(args)
|
|
860
860
|
|
|
861
861
|
from aiskills.browser_stealth import close_stealth_browser
|
|
862
|
-
|
|
862
|
+
# close_stealth_browser 现在是同步函数
|
|
863
|
+
close_stealth_browser(profile_name=a.profile)
|
|
863
864
|
print("反检测浏览器已关闭")
|
|
864
865
|
|
|
865
866
|
|
package/worklog.md
CHANGED
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
---
|
|
2
|
+
Task ID: [20260421-01]
|
|
3
|
+
Agent: Main Agent
|
|
4
|
+
Task: 反检测浏览器集成 - Phase 2 网站专用技能 (v1.30.0)
|
|
5
|
+
|
|
6
|
+
Work Log:
|
|
7
|
+
- 检查现有实现状态:browser_stealth.py + browser_profile.py + CLI + SKILL.md 已在之前的会话中完成
|
|
8
|
+
- 修复 main.py _register_builtin_skills():添加 13 个 stealth browser 技能类注册
|
|
9
|
+
- 创建 6 个网站专用 SKILL.md 操作指南:
|
|
10
|
+
* aiskills/site-gmail/SKILL.md — Gmail 收发邮件、搜索、附件
|
|
11
|
+
* aiskills/site-x-com/SKILL.md — X.com 发推、回复、搜索、点赞
|
|
12
|
+
* aiskills/site-weibo/SKILL.md — 微博发帖、转发、评论、搜索
|
|
13
|
+
* aiskills/site-wechat-mp/SKILL.md — 微信公众号扫码登录、图文发布
|
|
14
|
+
* aiskills/site-douyin/SKILL.md — 抖音浏览、搜索、发布视频、评论
|
|
15
|
+
* aiskills/site-mail139/SKILL.md — 139邮箱收发邮件、搜索
|
|
16
|
+
- 更新版本号 1.29.0 → 1.30.0
|
|
17
|
+
- Git commit + push + npm publish
|
|
18
|
+
|
|
19
|
+
Stage Summary:
|
|
20
|
+
- 修复: stealth browser 技能类注册到 SkillRegistry
|
|
21
|
+
- 新增: 6 个网站操作 SKILL.md 指南 (约 20KB 内容)
|
|
22
|
+
- 发布: myagent-ai@1.30.0 (npm + GitHub)
|
|
23
|
+
- 架构: LLM → command 工具 → stealth-* CLI → DrissionPage → 各网站
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
2
27
|
Task ID: [20260420-04]
|
|
3
28
|
Agent: Main Agent
|
|
4
29
|
Task: 发布 npm 包 myagent-ai v1.26.0
|