122 lines
5.8 KiB
Python
122 lines
5.8 KiB
Python
def handle_turnstile(self, tab=None, max_retries: int = 2, retry_interval: tuple = (1, 2)) -> bool:
|
||
"""
|
||
处理Turnstile验证
|
||
|
||
Args:
|
||
tab: 浏览器标签对象
|
||
max_retries: 最大重试次数
|
||
retry_interval: 重试间隔范围(最小值, 最大值)
|
||
|
||
Returns:
|
||
bool: 验证是否成功
|
||
|
||
Raises:
|
||
TurnstileError: 验证过程中的异常
|
||
"""
|
||
# 如果没有传入tab参数,则使用实例的tab属性
|
||
tab = tab or self.tab
|
||
|
||
# 记录开始检测Turnstile验证的日志
|
||
logging.info(get_translation("detecting_turnstile"))
|
||
# 保存验证开始前的屏幕截图
|
||
save_screenshot(tab, "start")
|
||
|
||
# 初始化重试计数器
|
||
retry_count = 0
|
||
|
||
try:
|
||
# 在最大重试次数内循环尝试验证
|
||
while retry_count < max_retries:
|
||
# 增加重试计数
|
||
retry_count += 1
|
||
# 记录当前是第几次尝试验证
|
||
logging.debug(get_translation("retry_verification", count=retry_count))
|
||
|
||
try:
|
||
# 初始化元素变量
|
||
element = None
|
||
try:
|
||
# 尝试通过层级结构定位到Turnstile验证框的容器元素
|
||
element = (
|
||
tab.ele(".main-content") # 找到 .main-content 元素
|
||
.ele("tag:div") # 找到第一个子 div
|
||
.ele("tag:div") # 找到第二个子 div
|
||
.ele("tag:div") # 找到第三个子 div
|
||
)
|
||
except Exception as e:
|
||
# 如果无法通过第一种方式找到元素,忽略异常继续执行
|
||
pass
|
||
|
||
if element:
|
||
# 如果找到了容器元素,则在其中定位验证框的输入元素
|
||
challenge_check = (
|
||
element
|
||
.shadow_root.ele("tag:iframe") # 找到shadow DOM中的iframe
|
||
.ele("tag:body") # 找到iframe中的body
|
||
.sr("tag:input") # 找到body中的input元素
|
||
)
|
||
else:
|
||
# 如果没有找到容器元素,则尝试另一种方式定位验证框
|
||
challenge_check = (
|
||
tab.ele("@id=cf-turnstile", timeout=2) # 通过id直接找到turnstile元素
|
||
.child() # 获取其子元素
|
||
.shadow_root.ele("tag:iframe") # 找到shadow DOM中的iframe
|
||
.ele("tag:body") # 找到iframe中的body
|
||
.sr("tag:input") # 找到body中的input元素
|
||
)
|
||
|
||
if challenge_check:
|
||
# 如果找到了验证输入元素,记录日志
|
||
logging.info(get_translation("detected_turnstile"))
|
||
# 点击前随机延迟,模拟人工操作
|
||
time.sleep(random.uniform(1, 3))
|
||
# 点击验证元素触发验证
|
||
challenge_check.click()
|
||
# 等待验证处理
|
||
time.sleep(2)
|
||
|
||
# 保存点击验证后的屏幕截图
|
||
save_screenshot(tab, "clicked")
|
||
|
||
# 检查验证是否成功
|
||
if check_verification_success(tab):
|
||
# 验证成功,记录日志
|
||
logging.info(get_translation("turnstile_verification_passed"))
|
||
# 保存验证成功的屏幕截图
|
||
save_screenshot(tab, "success")
|
||
# 返回验证成功
|
||
return True
|
||
|
||
except Exception as e:
|
||
# 记录当前尝试失败的详细信息
|
||
logging.debug(f"Current attempt unsuccessful: {str(e)}")
|
||
|
||
# 再次检查验证是否已经成功(可能在异常处理过程中已经通过验证)
|
||
if check_verification_success(tab):
|
||
# 返回验证成功
|
||
return True
|
||
|
||
# 在下一次尝试前随机延迟
|
||
time.sleep(random.uniform(*retry_interval))
|
||
|
||
# 超过最大重试次数,验证失败
|
||
logging.error(get_translation("verification_failed_max_retries", max_retries=max_retries))
|
||
# 提供额外的帮助信息,引导用户访问开源项目
|
||
logging.error(
|
||
"Please visit the open source project for more information: https://github.com/wangffei/wf-cursor-auto-free.git"
|
||
)
|
||
# 保存验证失败的屏幕截图
|
||
save_screenshot(tab, "failed")
|
||
# 返回验证失败
|
||
return False
|
||
|
||
except Exception as e:
|
||
# 捕获整个验证过程中的异常
|
||
# 构建错误信息
|
||
error_msg = get_translation("turnstile_exception", error=str(e))
|
||
# 记录错误日志
|
||
logging.error(error_msg)
|
||
# 保存发生错误时的屏幕截图
|
||
save_screenshot(tab, "error")
|
||
# 抛出TurnstileError异常
|
||
raise TurnstileError(error_msg) |