Add browser-automation/cloakbrowser
This commit is contained in:
@@ -0,0 +1,302 @@
|
|||||||
|
---
|
||||||
|
name: cloakbrowser
|
||||||
|
description: CamouFox反检测浏览器(CloakBrowser) — 完美通过所有bot检测,支持Google等强反自动化站点登录。含2FA文件轮询方案、备用验证码使用、常见陷阱。
|
||||||
|
version: 1.0
|
||||||
|
tags: [camoufox, anti-detection, google, 2fa, bot-detection]
|
||||||
|
---
|
||||||
|
|
||||||
|
# CloakBrowser (CamouFox Anti-Detection Browser)
|
||||||
|
|
||||||
|
CamouFox是经过反检测改造的Firefox浏览器,在headless模式下完美通过所有bot检测。
|
||||||
|
|
||||||
|
## Gitea 镜像
|
||||||
|
|
||||||
|
- **源码镜像**: [admin9webs/CamouFox](https://gitea9webs.sh3.ikuai7.com/admin9webs/CamouFox) (~8MB, 不含bundle/)
|
||||||
|
- **上游**: [github.com/daijro/camoufox](https://github.com/daijro/camoufox) (~1.5GB 含bundle二进制)
|
||||||
|
- Gitea 仓库只含源码(badges/patches/pythonlib/settings/scripts等),不含bundle/目录
|
||||||
|
|
||||||
|
## Bot检测结果
|
||||||
|
|
||||||
|
| 测试 | 结果 |
|
||||||
|
|------|------|
|
||||||
|
| navigator.webdriver | ✅ false(最关键) |
|
||||||
|
| WebDriver 检测 | ✅ passed |
|
||||||
|
| Chrome runtime | ✅ present |
|
||||||
|
| Headless 检测 | ✅ 通过 |
|
||||||
|
| 指纹一致性 | ✅ 5 plugins, Win32 平台 |
|
||||||
|
|
||||||
|
## Gmail 2FA 登录脚本
|
||||||
|
|
||||||
|
仓库中提供了可直接运行的 Gmail 2FA 登录脚本:
|
||||||
|
- **Gitea**: `admin9webs/browser-automation-toolkit/scripts/gmail_2fa_login.py`
|
||||||
|
- **本地**: `~/hermes/skills/browser-automation/cloakbrowser/scripts/gmail_2fa_login.py`
|
||||||
|
- 用法:`python3 -u gmail_2fa_login.py` 后台启动 → 写入 `/tmp/gmail_code.txt` → 自动完成登录
|
||||||
|
- 功能:CamouFox 反检测登录 → SMS 接收 → 文件轮询等待验证码 → Cookie 持久化
|
||||||
|
|
||||||
|
## 安装与导入
|
||||||
|
|
||||||
|
```python
|
||||||
|
from camoufox.sync_api import Camoufox
|
||||||
|
```
|
||||||
|
|
||||||
|
无需额外安装,venv中已有camoufox包。
|
||||||
|
Python路径: `/home/ubuntu/.hermes/hermes-agent/venv/bin/python3`
|
||||||
|
|
||||||
|
## 基本启动参数
|
||||||
|
|
||||||
|
```python
|
||||||
|
with Camoufox(headless=True, geoip=True, humanize=True) as browser:
|
||||||
|
page = browser.new_page()
|
||||||
|
page.goto("https://example.com", timeout=30000)
|
||||||
|
```
|
||||||
|
|
||||||
|
- `headless=True`: 无头模式
|
||||||
|
- `geoip=True`: 自动匹配IP地理位置的时区/语言
|
||||||
|
- `humanize=True`: 模拟人类输入延迟
|
||||||
|
|
||||||
|
## Google登录 + 2FA完整流程
|
||||||
|
|
||||||
|
Google是最严格的反自动化站点,普通Playwright Chromium会被拦截到`/signin/rejected`。
|
||||||
|
CamouFox可以绕过,但2FA需要特殊处理。
|
||||||
|
|
||||||
|
### 核心陷阱:验证码时效性
|
||||||
|
|
||||||
|
**每次新登录会话都会使之前的SMS验证码失效!**
|
||||||
|
不能"先登录触发短信 → 等用户给码 → 重新登录输入",因为重新登录=新会话=旧码失效。
|
||||||
|
|
||||||
|
### 解决方案:后台脚本 + 文件轮询
|
||||||
|
|
||||||
|
用后台进程保持浏览器会话存活,通过文件传递验证码:
|
||||||
|
|
||||||
|
```python
|
||||||
|
CODE_FILE = "/tmp/gmail_code.txt"
|
||||||
|
SIGNAL_FILE = "/tmp/gmail_signal.txt"
|
||||||
|
|
||||||
|
with Camoufox(headless=True, geoip=True, humanize=True) as browser:
|
||||||
|
page = browser.new_page()
|
||||||
|
|
||||||
|
# Step 1: Email
|
||||||
|
page.goto("https://accounts.google.com/signin", timeout=30000)
|
||||||
|
page.wait_for_load_state("networkidle", timeout=15000)
|
||||||
|
time.sleep(2)
|
||||||
|
page.query_selector("input[type=email]").fill(email)
|
||||||
|
time.sleep(1)
|
||||||
|
page.query_selector("#identifierNext").click()
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
# Step 2: Password
|
||||||
|
page.query_selector("input[type=password]").fill(password)
|
||||||
|
time.sleep(1)
|
||||||
|
page.query_selector("#passwordNext").click()
|
||||||
|
time.sleep(6)
|
||||||
|
|
||||||
|
# Step 3: 点击SMS验证码选项
|
||||||
|
page.evaluate("""() => {
|
||||||
|
const items = document.querySelectorAll("[role=link]");
|
||||||
|
for (const item of items) {
|
||||||
|
const t = (item.innerText || "");
|
||||||
|
if (t.includes("验证码") || t.includes("verification code") || t.includes("••47")) {
|
||||||
|
item.click(); return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}""")
|
||||||
|
time.sleep(6)
|
||||||
|
|
||||||
|
# Step 4: 通知外部就绪,等待验证码文件
|
||||||
|
with open(SIGNAL_FILE, "w") as f:
|
||||||
|
f.write("READY")
|
||||||
|
|
||||||
|
for i in range(120):
|
||||||
|
if os.path.exists(CODE_FILE):
|
||||||
|
with open(CODE_FILE, "r") as f:
|
||||||
|
code = f.read().strip()
|
||||||
|
if len(code) == 6 and code.isdigit():
|
||||||
|
break
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
# Step 5: 输入验证码(用keyboard.type而非fill)
|
||||||
|
pin = page.query_selector("#idvPin")
|
||||||
|
pin.click()
|
||||||
|
time.sleep(0.5)
|
||||||
|
page.keyboard.type(code, delay=100) # 逐字符输入,更拟人
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
# Step 6: 点击下一步
|
||||||
|
page.evaluate("""() => {
|
||||||
|
const btns = document.querySelectorAll("button");
|
||||||
|
for (const b of btns) {
|
||||||
|
const t = (b.innerText || "").trim();
|
||||||
|
if (t === "下一步" || t === "Next") { b.click(); return; }
|
||||||
|
}
|
||||||
|
}""")
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
# Step 7: 验证登录
|
||||||
|
page.goto("https://mail.google.com", timeout=20000)
|
||||||
|
time.sleep(5)
|
||||||
|
if "mail.google.com" in page.url:
|
||||||
|
# 登录成功!保存Cookie
|
||||||
|
cookies = page.context.cookies()
|
||||||
|
with open(cookie_path, "w") as f:
|
||||||
|
json.dump(cookies, f)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 前端操作流程
|
||||||
|
|
||||||
|
1. 启动后台脚本: `terminal(background=true)`
|
||||||
|
2. 等待信号文件: `while [ ! -f /tmp/gmail_signal.txt ]; do sleep 2; done`
|
||||||
|
3. 告诉用户"验证码已发送,请查收短信"
|
||||||
|
4. 用户给验证码后: `write_file("/tmp/gmail_code.txt", "123456")`
|
||||||
|
5. 检查脚本输出: `process(action="poll")`
|
||||||
|
|
||||||
|
### 备用验证码方式
|
||||||
|
|
||||||
|
如果SMS不可用,Google 2FA选择页会显示"请输入您的其中一个8位数备用验证码"。
|
||||||
|
选择"试试其他方式"可能触发安全锁定,**不要点!**直接在选择页找到备用验证码选项。
|
||||||
|
|
||||||
|
备用验证码格式: 8位数字(无空格),如 `74361085`
|
||||||
|
|
||||||
|
当前备用验证码保存在: `/home/ubuntu/.hermes/credentials/accounts.md`
|
||||||
|
|
||||||
|
## 与其他浏览器对比
|
||||||
|
|
||||||
|
| 方案 | Google登录 | navigator.webdriver | 适用场景 |
|
||||||
|
|------|-----------|---------------------|---------|
|
||||||
|
| CamouFox (CloakBrowser) | ✅ 通过 | ✅ false | Google/强反自动化站点 |
|
||||||
|
| Playwright Chromium | ❌ /signin/rejected | ❌ true | 普通网站 |
|
||||||
|
| DrissionPage Chromium | ❌ 被拦截 | ❌ true | ERP系统(妙手/通途) |
|
||||||
|
|
||||||
|
## 多IP多指纹并发
|
||||||
|
|
||||||
|
CamouFox 原生支持多IP + 多指纹并发,每个实例自动生成独立随机指纹,配合不同 proxy 实现完整账号隔离。
|
||||||
|
|
||||||
|
### 代理(多IP)
|
||||||
|
|
||||||
|
`proxy` 参数接受 dict,支持 HTTP/SOCKS5:
|
||||||
|
|
||||||
|
```python
|
||||||
|
proxy={"server": "http://proxy-host:port", "username": "user", "password": "pass"}
|
||||||
|
```
|
||||||
|
|
||||||
|
配合 `geoip=True` 会**自动通过代理获取出口IP**,然后匹配对应的时区/语言/经纬度/WebRTC IP。
|
||||||
|
|
||||||
|
### 多指纹(每个实例独立)
|
||||||
|
|
||||||
|
每次启动 CamouFox **默认生成随机指纹**(基于 BrowserForge),包括:User-Agent、屏幕分辨率、WebGL vendor/renderer、Canvas aaOffset、字体列表+spacing seed、插件/Navigator、窗口位置。每个实例 = 全新独立指纹,天然互不相同。
|
||||||
|
|
||||||
|
关键指纹控制参数:
|
||||||
|
|
||||||
|
| 参数 | 作用 |
|
||||||
|
|------|------|
|
||||||
|
| `os` | 指纹OS平台:`"windows"`/`"macos"`/`"linux"` 或列表随机选 |
|
||||||
|
| `screen` | 约束屏幕分辨率(`browserforge.fingerprints.Screen` 实例)|
|
||||||
|
| `window` | 固定窗口大小 `(width, height)` |
|
||||||
|
| `fingerprint` | 传入自定义 `Fingerprint` 对象(可序列化复用) |
|
||||||
|
| `webgl_config` | 指定 WebGL vendor/renderer `(vendor, renderer)` |
|
||||||
|
| `locale` | 指定语言环境 |
|
||||||
|
| `fonts` | 附加字体列表 |
|
||||||
|
|
||||||
|
### 异步并发示例
|
||||||
|
|
||||||
|
```python
|
||||||
|
from camoufox.async_api import AsyncCamoufox
|
||||||
|
|
||||||
|
async def run_account(proxy_server, target_os):
|
||||||
|
async with AsyncCamoufox(
|
||||||
|
headless=True, geoip=True, humanize=True,
|
||||||
|
proxy={"server": proxy_server},
|
||||||
|
os=target_os, # 不同OS指纹
|
||||||
|
) as browser:
|
||||||
|
page = await browser.new_page()
|
||||||
|
await page.goto("https://example.com")
|
||||||
|
```
|
||||||
|
|
||||||
|
### 指纹持久化(跨会话复用同一身份)
|
||||||
|
|
||||||
|
CamouFox 不自带指纹持久化,需手动管理:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from camoufox.fingerprints import generate_fingerprint
|
||||||
|
import json
|
||||||
|
|
||||||
|
# 生成并保存
|
||||||
|
fp = generate_fingerprint(os="windows")
|
||||||
|
with open("fingerprint_account1.json", "w") as f:
|
||||||
|
json.dump(fp.__dict__, f)
|
||||||
|
|
||||||
|
# 下次复用
|
||||||
|
from browserforge.fingerprints import Fingerprint
|
||||||
|
with open("fingerprint_account1.json") as f:
|
||||||
|
fp = Fingerprint(**json.load(f))
|
||||||
|
|
||||||
|
with Camoufox(headless=True, fingerprint=fp, geoip=True, proxy=...) as browser:
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
## 完整 launch_options 参数速查
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `proxy` | `Dict[str,str]` | 代理 `{"server","username","password"}` |
|
||||||
|
| `os` | `str/List[str]` | 指纹OS:`"windows"`/`"macos"`/`"linux"` |
|
||||||
|
| `geoip` | `bool/str` | True=自动查IP;或传IP字符串 |
|
||||||
|
| `humanize` | `bool/float` | 拟人鼠标移动,float=最大秒数 |
|
||||||
|
| `headless` | `bool/str` | True无头;Linux下`"virtual"`用Xvfb |
|
||||||
|
| `fingerprint` | `Fingerprint` | 自定义BrowserForge指纹 |
|
||||||
|
| `screen` | `Screen` | 屏幕约束 |
|
||||||
|
| `window` | `Tuple[int,int]` | 固定窗口尺寸 |
|
||||||
|
| `locale` | `str/List[str]` | 语言环境 |
|
||||||
|
| `fonts` | `List[str]` | 附加字体 |
|
||||||
|
| `custom_fonts_only` | `bool` | 仅使用自定义字体 |
|
||||||
|
| `addons` | `List[str]` | Firefox扩展路径 |
|
||||||
|
| `exclude_addons` | `List[DefaultAddons]` | 排除默认扩展 |
|
||||||
|
| `block_images` | `bool` | 屏蔽图片 |
|
||||||
|
| `block_webrtc` | `bool` | 屏蔽WebRTC |
|
||||||
|
| `block_webgl` | `bool` | 屏蔽WebGL |
|
||||||
|
| `webgl_config` | `Tuple[str,str]` | 指定WebGL `(vendor, renderer)` |
|
||||||
|
| `disable_coop` | `bool` | 禁用COOP(允许跨域iframe点击) |
|
||||||
|
| `enable_cache` | `bool` | 启用页面/请求缓存(多用内存) |
|
||||||
|
| `ff_version` | `int` | Firefox版本号 |
|
||||||
|
| `main_world_eval` | `bool` | 允许主世界脚本执行 |
|
||||||
|
| `firefox_user_prefs` | `Dict` | Firefox偏好设置 |
|
||||||
|
| `config` | `Dict` | 直接传Camoufox属性配置 |
|
||||||
|
| `i_know_what_im_doing` | `bool` | 抑制安全警告 |
|
||||||
|
|
||||||
|
## 反爬两层防御模型
|
||||||
|
|
||||||
|
很多网站的反爬系统分两层,必须同时突破才能访问:
|
||||||
|
|
||||||
|
| 层级 | 检测内容 | CamouFox能否绕过 | 解决方案 |
|
||||||
|
|------|---------|-----------------|---------|
|
||||||
|
| 第1层:浏览器指纹 | navigator.webdriver, headless检测, Chrome runtime, 插件/字体指纹 | ✅ 天然绕过 | CamouFox本身 |
|
||||||
|
| 第2层:IP信誉 | 数据中心IP检测, 出口IP地理位置, IP历史行为 | ❌ 无法绕过 | 住宅代理(proxy参数) |
|
||||||
|
|
||||||
|
关键判断:如果CamouFox打开网站后仍被拦截(如1688的"Access denied"页面),说明是**IP层**被封锁,不是指纹层问题。此时唯一方案是配合住宅代理。
|
||||||
|
|
||||||
|
常见被IP层封锁的站点:
|
||||||
|
- **1688.com** — 阿里云WAF,数据中心IP直接拒绝,必须用国内住宅代理
|
||||||
|
- **Taobao.com** — 同上,阿里云体系
|
||||||
|
- **Google** — 指纹+IP双层,但IP层通常只降权不直接拒绝
|
||||||
|
|
||||||
|
## GFW 绕过
|
||||||
|
|
||||||
|
CamouFox 部署在境外服务器(如 HK)时,可以绕过 GFW 访问被墙的国际站点。
|
||||||
|
此场景下 Desktop(位于中国大陆)无法访问的网站(Imgur、Medium、Reddit 等),
|
||||||
|
服务器端 CamouFox 可直接加载。
|
||||||
|
|
||||||
|
**使用模式:**
|
||||||
|
1. 服务器用 CamouFox 访问目标站点
|
||||||
|
2. 遇到 CAPTCHA 时截图传给用户手动完成
|
||||||
|
3. 完成后保存 session,后续自动化复用
|
||||||
|
|
||||||
|
**已被墙站点(从中国 Desktop 无法访问):** Imgur、Medium、Flipboard、Steemit
|
||||||
|
**CamouFox 能绕过但需 CAPTCHA:** Reddit(有时超时)、Quora(Cloudflare Turnstile)、Pinterest(reCAPTCHA)
|
||||||
|
|
||||||
|
1. **fill() vs type()**: 验证码输入框可能disabled,用`page.keyboard.type(code, delay=100)`代替`pin.fill(code)`
|
||||||
|
2. **storage_state无法恢复2FA会话**: Google的2FA页面有一次性TL token,保存storage_state后恢复会得到Error 400
|
||||||
|
3. **多次错误验证码 → 安全锁定**: 连续3-4次验证码错误后,Google会显示"无法登录",需等待冷却
|
||||||
|
4. **不要点"试试其他方式"**: 在2FA选择页点击此按钮可能直接触发安全锁定
|
||||||
|
5. **geoip=True很关键**: 自动匹配IP的时区和语言,否则Google可能检测到不一致
|
||||||
|
6. **proxy务必配geoip**: 用代理不设geoip会触发LeakWarning,地理位置与时区不一致易被检测
|
||||||
|
7. **Python路径**: 必须用venv的python: `/home/ubuntu/.hermes/hermes-agent/venv/bin/python3`
|
||||||
|
8. **IP层封锁诊断**: 如果CamouFox打开页面仍被拒(标题含"Access denied"/URL含"punish"/"deny"),说明是IP层问题,需配proxy参数使用住宅代理
|
||||||
Reference in New Issue
Block a user