实现邮箱API集成和注册数量限制功能

This commit is contained in:
hkyc
2025-05-22 22:43:44 +08:00
parent 4ee6a2e195
commit 3fb99d17e0
5 changed files with 348 additions and 70 deletions

84
EmailAPIClient.py Normal file
View File

@@ -0,0 +1,84 @@
import requests
import json
from loguru import logger
class EmailAPIClient:
"""自建邮箱API客户端
用于从API获取邮箱账号
"""
def __init__(self, api_url="https://steamapi.cursorpro.com.cn/api/create_user"):
"""初始化API客户端
Args:
api_url: API服务器地址
"""
self.api_url = api_url
def create_email_account(self):
"""创建新的邮箱账号
通过调用API创建一个新的邮箱账号
Returns:
dict: 包含以下字段的字典如果失败则返回None
- id: 账号ID
- username: 用户名
- email: 邮箱地址
- password: 邮箱密码
- success: 是否成功
- message: 信息
"""
try:
logger.info(f"正在从API获取邮箱账号: {self.api_url}")
response = requests.post(self.api_url, timeout=30)
if response.status_code != 200:
logger.error(f"API请求失败状态码: {response.status_code}")
return None
try:
result = response.json()
except json.JSONDecodeError:
logger.error("API返回的数据不是有效的JSON格式")
return None
if not result.get("success", False):
logger.error(f"API返回错误: {result.get('message', '未知错误')}")
return None
logger.info(f"成功获取邮箱账号: {result.get('email')}")
return result
except Exception as e:
logger.error(f"获取邮箱账号出错: {str(e)}")
return None
def get_email_credentials(self):
"""获取邮箱凭据
获取邮箱地址和密码,并格式化为凭据字典
Returns:
dict: 包含email和password字段的字典如果失败则返回None
"""
account = self.create_email_account()
if not account:
return None
return {
'email': account.get('email'),
'password': account.get('password')
}
# 测试代码
if __name__ == "__main__":
client = EmailAPIClient()
email_data = client.get_email_credentials()
if email_data:
print(f"获取到的邮箱: {email_data['email']}")
print(f"获取到的密码: {email_data['password']}")
else:
print("获取邮箱账号失败")

View File

@@ -8,16 +8,17 @@ from tkinter import filedialog
from ThreadManagerWithPyno import GUIThreadManagerWithPyno from ThreadManagerWithPyno import GUIThreadManagerWithPyno
from PynoCaptchaSolver import PynoCaptchaConfig, PynoCaptchaSolver from PynoCaptchaSolver import PynoCaptchaConfig, PynoCaptchaSolver
from SteamCaptchaHelper import SteamCaptchaHelper from SteamCaptchaHelper import SteamCaptchaHelper
from EmailAPIClient import EmailAPIClient
import time import time
# 配置日志 # 配置日志
from loguru import logger from loguru import logger
logger.add("steam_registration_pyno.log", rotation="10 MB") logger.add("steam_registration.log", rotation="10 MB")
class RegistrationGUIWithPynoV2: class SteamRegistrationGUI:
def __init__(self, root): def __init__(self, root):
self.root = root self.root = root
self.root.title("Steam注册 - PyNoCaptcha V2") self.root.title("Steam账号注册助手")
self.root.geometry("800x800") self.root.geometry("800x800")
self.root.minsize(800, 800) # 设置最小窗口大小 self.root.minsize(800, 800) # 设置最小窗口大小
@@ -30,7 +31,7 @@ class RegistrationGUIWithPynoV2:
top_frame.pack(fill="x", side="top", padx=5, pady=5) top_frame.pack(fill="x", side="top", padx=5, pady=5)
# 创建配置框架 # 创建配置框架
config_frame = ttk.LabelFrame(top_frame, text="配置信息") config_frame = ttk.LabelFrame(top_frame, text="基本配置")
config_frame.pack(fill="x", padx=5, pady=5) config_frame.pack(fill="x", padx=5, pady=5)
# 加载默认配置 # 加载默认配置
@@ -42,11 +43,11 @@ class RegistrationGUIWithPynoV2:
self.config_vars = {} self.config_vars = {}
self._create_config_widgets(config_frame) self._create_config_widgets(config_frame)
# 创建PyNoCaptcha配置框架 # 创建验证码配置框架
captcha_frame = ttk.LabelFrame(top_frame, text="PyNoCaptcha配置") captcha_frame = ttk.LabelFrame(top_frame, text="验证码配置")
captcha_frame.pack(fill="x", padx=5, pady=5) captcha_frame.pack(fill="x", padx=5, pady=5)
# 创建PyNoCaptcha配置输入框 # 创建验证码配置输入框
self.captcha_vars = {} self.captcha_vars = {}
self._create_captcha_widgets(captcha_frame) self._create_captcha_widgets(captcha_frame)
@@ -71,17 +72,51 @@ class RegistrationGUIWithPynoV2:
ttk.Button(steam_frame, text="刷新验证信息", ttk.Button(steam_frame, text="刷新验证信息",
command=self._refresh_steam_info).grid(row=3, column=0, columnspan=2, padx=5, pady=5) command=self._refresh_steam_info).grid(row=3, column=0, columnspan=2, padx=5, pady=5)
# 创建邮箱选项框架
email_option_frame = ttk.LabelFrame(top_frame, text="邮箱设置")
email_option_frame.pack(fill="x", padx=5, pady=5)
# 添加邮箱来源选择
self.email_source_var = tk.StringVar(value="txt_file")
email_source_options = [
("自建邮箱API", "api"),
("本地文件", "txt_file"),
("微软Graph", "graph")
]
# 注册数量设置
reg_count_frame = ttk.Frame(email_option_frame)
reg_count_frame.pack(fill="x", padx=5, pady=5)
ttk.Label(reg_count_frame, text="注册数量:").grid(row=0, column=0, padx=5, pady=2, sticky="e")
self.reg_count_var = tk.StringVar(value="10")
ttk.Entry(reg_count_frame, textvariable=self.reg_count_var, width=10).grid(row=0, column=1, padx=5, pady=2, sticky="w")
ttk.Label(reg_count_frame, text="(0表示不限制)").grid(row=0, column=2, padx=5, pady=2, sticky="w")
# 邮箱来源选择
email_source_frame = ttk.Frame(email_option_frame)
email_source_frame.pack(fill="x", padx=5, pady=5)
for i, (text, value) in enumerate(email_source_options):
ttk.Radiobutton(
email_source_frame,
text=text,
variable=self.email_source_var,
value=value,
command=self._toggle_email_source
).grid(row=0, column=i, padx=10, pady=2)
# 创建文件选择框架 # 创建文件选择框架
files_frame = ttk.LabelFrame(top_frame, text="文件选择") self.files_frame = ttk.LabelFrame(top_frame, text="文件选择")
files_frame.pack(fill="x", padx=5, pady=5) self.files_frame.pack(fill="x", padx=5, pady=5)
# 邮箱文件选择 # 邮箱文件选择
self.email_path = tk.StringVar(value=os.path.join(self.script_dir, 'email_password.txt')) self.email_path = tk.StringVar(value=os.path.join(self.script_dir, 'email_password.txt'))
self._create_file_selector(files_frame, "邮箱文件:", self.email_path, 0) self._create_file_selector(self.files_frame, "邮箱文件:", self.email_path, 0)
# 代理文件选择 # 代理文件选择
self.proxy_path = tk.StringVar(value=os.path.join(self.script_dir, 'proxy_ips.txt')) self.proxy_path = tk.StringVar(value=os.path.join(self.script_dir, 'proxy_ips.txt'))
self._create_file_selector(files_frame, "代理文件:", self.proxy_path, 1) self._create_file_selector(self.files_frame, "代理文件:", self.proxy_path, 1)
# 按钮框架 - 直接放在主界面上,任务列表上方 # 按钮框架 - 直接放在主界面上,任务列表上方
button_frame = ttk.Frame(main_frame) button_frame = ttk.Frame(main_frame)
@@ -92,7 +127,7 @@ class RegistrationGUIWithPynoV2:
button_frame, button_frame,
text="开始注册", text="开始注册",
command=self.start_registration, command=self.start_registration,
width=20 width=15
) )
self.start_button.pack(side="left", padx=10, pady=5, expand=True) self.start_button.pack(side="left", padx=10, pady=5, expand=True)
@@ -102,7 +137,7 @@ class RegistrationGUIWithPynoV2:
text="停止注册", text="停止注册",
command=self.stop_registration, command=self.stop_registration,
state="disabled", state="disabled",
width=20 width=15
) )
self.stop_button.pack(side="left", padx=10, pady=5, expand=True) self.stop_button.pack(side="left", padx=10, pady=5, expand=True)
@@ -111,10 +146,19 @@ class RegistrationGUIWithPynoV2:
button_frame, button_frame,
text="测试验证码", text="测试验证码",
command=self.test_captcha, command=self.test_captcha,
width=20 width=15
) )
self.test_captcha_button.pack(side="left", padx=10, pady=5, expand=True) self.test_captcha_button.pack(side="left", padx=10, pady=5, expand=True)
# 添加获取邮箱测试按钮
self.test_email_button = ttk.Button(
button_frame,
text="测试邮箱API",
command=self.test_email_api,
width=15
)
self.test_email_button.pack(side="left", padx=10, pady=5, expand=True)
# 中间框架 - 包含任务状态表格 # 中间框架 - 包含任务状态表格
middle_frame = ttk.Frame(main_frame) middle_frame = ttk.Frame(main_frame)
middle_frame.pack(fill="both", expand=True, padx=5, pady=5) middle_frame.pack(fill="both", expand=True, padx=5, pady=5)
@@ -162,9 +206,31 @@ class RegistrationGUIWithPynoV2:
self._stop_progress_update = False self._stop_progress_update = False
# 添加版本标签 # 添加版本标签
version_label = ttk.Label(main_frame, text="PyNoCaptcha V2 版本", foreground="blue") version_label = ttk.Label(main_frame, text="Steam账号注册助手 V3.0", foreground="blue")
version_label.pack(side="bottom", padx=5, pady=5) version_label.pack(side="bottom", padx=5, pady=5)
# 初始化邮箱API客户端
self.email_api_client = EmailAPIClient()
# 初始设置邮箱来源
self._toggle_email_source()
def _toggle_email_source(self):
"""根据邮箱来源选择切换界面显示"""
source = self.email_source_var.get()
# 首先隐藏所有与邮箱相关的文件选择框
for widget in self.files_frame.winfo_children():
if "邮箱文件" in str(widget):
widget.grid_remove()
# 根据所选邮箱来源显示相应控件
if source == "txt_file":
# 显示邮箱文件选择框
for widget in self.files_frame.winfo_children():
if "邮箱文件" in str(widget):
widget.grid()
def _refresh_steam_info(self): def _refresh_steam_info(self):
"""刷新Steam验证信息""" """刷新Steam验证信息"""
threading.Thread(target=self._refresh_steam_info_thread, daemon=True).start() threading.Thread(target=self._refresh_steam_info_thread, daemon=True).start()
@@ -209,11 +275,11 @@ class RegistrationGUIWithPynoV2:
] ]
for i, (key, label, options) in enumerate(config_items): for i, (key, label, options) in enumerate(config_items):
ttk.Label(parent, text=label,width=10).grid(row=i, column=0, padx=5, pady=2, sticky="e") ttk.Label(parent, text=label, width=10).grid(row=i, column=0, padx=5, pady=2, sticky="e")
if options: if options:
var = tk.StringVar(value=str(self.config.get(key, ""))) var = tk.StringVar(value=str(self.config.get(key, "")))
widget = ttk.Combobox(parent, textvariable=var, values=options,width=50) widget = ttk.Combobox(parent, textvariable=var, values=options, width=50)
else: else:
var = tk.StringVar(value=str(self.config.get(key, ""))) var = tk.StringVar(value=str(self.config.get(key, "")))
widget = ttk.Entry(parent, textvariable=var, width=50) widget = ttk.Entry(parent, textvariable=var, width=50)
@@ -222,22 +288,22 @@ class RegistrationGUIWithPynoV2:
self.config_vars[key] = var self.config_vars[key] = var
def _create_captcha_widgets(self, parent): def _create_captcha_widgets(self, parent):
"""创建PyNoCaptcha配置输入控件""" """创建验证码配置输入控件"""
captcha_items = [ captcha_items = [
("pyno_user_token", "PyNoCaptcha API密钥:", None), ("pyno_user_token", "API密钥:", None),
("pyno_sitekey", "验证码网站Key:", None), ("pyno_sitekey", "网站Key:", None),
("pyno_referer", "网站Referer:", None), ("pyno_referer", "Referer:", None),
("pyno_user_agent", "User-Agent:", None), ("pyno_user_agent", "User-Agent:", None),
("pyno_timeout", "超时时间(秒):", None), ("pyno_timeout", "超时时间(秒):", None),
("pyno_debug", "调试模式:", ["True", "False"]) ("pyno_debug", "调试模式:", ["True", "False"])
] ]
for i, (key, label, options) in enumerate(captcha_items): for i, (key, label, options) in enumerate(captcha_items):
ttk.Label(parent, text=label,width=12).grid(row=i, column=0, padx=5, pady=2, sticky="e") ttk.Label(parent, text=label, width=10).grid(row=i, column=0, padx=5, pady=2, sticky="e")
if options: if options:
var = tk.StringVar(value=str(self.config.get(key, "True" if key == "pyno_debug" else "False"))) var = tk.StringVar(value=str(self.config.get(key, "True" if key == "pyno_debug" else "False")))
widget = ttk.Combobox(parent, textvariable=var, values=options,width=50) widget = ttk.Combobox(parent, textvariable=var, values=options, width=50)
else: else:
default_value = "" default_value = ""
if key == "pyno_sitekey": if key == "pyno_sitekey":
@@ -334,7 +400,7 @@ class RegistrationGUIWithPynoV2:
value = value.lower() == "true" value = value.lower() == "true"
config[key] = value config[key] = value
# 保存PyNoCaptcha配置 # 保存验证码配置
for key, var in self.captcha_vars.items(): for key, var in self.captcha_vars.items():
value = var.get() value = var.get()
if key == "pyno_timeout": if key == "pyno_timeout":
@@ -343,6 +409,10 @@ class RegistrationGUIWithPynoV2:
value = value.lower() == "true" value = value.lower() == "true"
config[key] = value config[key] = value
# 保存邮箱来源配置
config['email_source'] = self.email_source_var.get()
config['reg_count'] = int(self.reg_count_var.get())
with open(self.config_path, 'w') as f: with open(self.config_path, 'w') as f:
json.dump(config, f, indent=2) json.dump(config, f, indent=2)
return True return True
@@ -352,7 +422,9 @@ class RegistrationGUIWithPynoV2:
def _validate_inputs(self): def _validate_inputs(self):
"""验证输入""" """验证输入"""
if not os.path.exists(self.email_path.get()): # 检查邮箱来源
email_source = self.email_source_var.get()
if email_source == "txt_file" and not os.path.exists(self.email_path.get()):
messagebox.showerror("错误", "邮箱文件不存在") messagebox.showerror("错误", "邮箱文件不存在")
return False return False
@@ -366,17 +438,27 @@ class RegistrationGUIWithPynoV2:
messagebox.showerror("错误", f"请填写 {key} 配置项") messagebox.showerror("错误", f"请填写 {key} 配置项")
return False return False
# 验证PyNoCaptcha配置 # 验证验证码配置
required_captcha_keys = ["pyno_user_token"] required_captcha_keys = ["pyno_user_token"]
for key in required_captcha_keys: for key in required_captcha_keys:
if not self.captcha_vars[key].get().strip(): if not self.captcha_vars[key].get().strip():
messagebox.showerror("错误", f"请填写 {key} 配置项") messagebox.showerror("错误", f"请填写 {key} 配置项")
return False return False
# 验证注册数量
try:
count = int(self.reg_count_var.get())
if count < 0:
messagebox.showerror("错误", "注册数量不能为负数")
return False
except ValueError:
messagebox.showerror("错误", "注册数量必须是整数")
return False
return True return True
def get_captcha_config(self): def get_captcha_config(self):
"""获取PyNoCaptcha配置""" """获取验证码配置"""
return PynoCaptchaConfig( return PynoCaptchaConfig(
user_token=self.captcha_vars["pyno_user_token"].get(), user_token=self.captcha_vars["pyno_user_token"].get(),
sitekey=self.captcha_vars["pyno_sitekey"].get(), sitekey=self.captcha_vars["pyno_sitekey"].get(),
@@ -386,11 +468,52 @@ class RegistrationGUIWithPynoV2:
debug=self.captcha_vars["pyno_debug"].get().lower() == "true" debug=self.captcha_vars["pyno_debug"].get().lower() == "true"
) )
def test_email_api(self):
"""测试邮箱API功能"""
# 禁用测试按钮
self.test_email_button.config(state="disabled")
# 在新线程中测试
threading.Thread(target=self._test_email_api_thread, daemon=True).start()
def _test_email_api_thread(self):
"""在新线程中测试邮箱API"""
try:
test_id = "测试邮箱API"
self.update_status(test_id, status="正在从API获取邮箱...")
# 获取邮箱账号
email_data = self.email_api_client.get_email_credentials()
if not email_data:
self.update_status(test_id, status="获取邮箱失败", result="失败")
messagebox.showerror("错误", "无法从API获取邮箱账号")
return
# 显示结果
self.update_status(
test_id,
status=f"获取邮箱成功: {email_data['email']}",
account_name="N/A",
password=email_data['password'],
result="成功"
)
messagebox.showinfo("成功", f"成功获取邮箱: {email_data['email']}")
except Exception as e:
logger.error(f"测试邮箱API出错: {str(e)}")
messagebox.showerror("错误", f"测试过程中出错: {str(e)}")
self.update_status(test_id, status=f"出错: {str(e)}", result="错误")
finally:
# 恢复按钮状态
self.test_email_button.config(state="normal")
def test_captcha(self): def test_captcha(self):
"""测试PyNoCaptcha验证码""" """测试验证码"""
# 验证配置 # 验证配置
if not self.captcha_vars["pyno_user_token"].get().strip(): if not self.captcha_vars["pyno_user_token"].get().strip():
messagebox.showerror("错误", "请先填写PyNoCaptcha API密钥") messagebox.showerror("错误", "请先填写验证码API密钥")
return return
# 保存配置 # 保存配置
@@ -404,9 +527,9 @@ class RegistrationGUIWithPynoV2:
threading.Thread(target=self._test_captcha_thread, daemon=True).start() threading.Thread(target=self._test_captcha_thread, daemon=True).start()
def _test_captcha_thread(self): def _test_captcha_thread(self):
"""在新线程中测试PyNoCaptcha""" """在新线程中测试验证码"""
try: try:
test_id = "测试PyNoCaptcha" test_id = "测试验证码"
self.update_status(test_id, status="正在准备验证码测试...") self.update_status(test_id, status="正在准备验证码测试...")
# 首先获取动态sitekey # 首先获取动态sitekey
@@ -481,7 +604,7 @@ class RegistrationGUIWithPynoV2:
except Exception as e: except Exception as e:
logger.error(f"测试过程中出错: {str(e)}") logger.error(f"测试过程中出错: {str(e)}")
messagebox.showerror("错误", f"测试过程中出错: {str(e)}") messagebox.showerror("错误", f"测试过程中出错: {str(e)}")
self.update_status("测试PyNoCaptcha", status=f"出错: {str(e)}", result="错误") self.update_status("测试验证码", status=f"出错: {str(e)}", result="错误")
finally: finally:
# 恢复按钮状态 # 恢复按钮状态
self.test_captcha_button.config(state="normal") self.test_captcha_button.config(state="normal")
@@ -547,17 +670,24 @@ class RegistrationGUIWithPynoV2:
messagebox.showerror("错误", f"获取Steam验证信息失败: {str(e)}") messagebox.showerror("错误", f"获取Steam验证信息失败: {str(e)}")
return return
# 使用PyNoCaptcha版本的GUIThreadManager # 创建参数字典
self.manager = GUIThreadManagerWithPyno( manager_params = {
self.config_path, 'config_path': self.config_path,
self.email_path.get(), 'email_path': self.email_path.get(),
self.proxy_path.get(), 'proxy_path': self.proxy_path.get(),
self, 'gui': self,
completed_tasks 'completed_tasks': completed_tasks,
) 'email_source': self.email_source_var.get(),
'reg_count': int(self.reg_count_var.get()),
'email_api_client': self.email_api_client if self.email_source_var.get() == "api" else None
}
# 使用线程管理器
self.manager = GUIThreadManagerWithPyno(**manager_params)
self.manager.start() self.manager.start()
except Exception as e: except Exception as e:
logger.error(f"启动注册线程出错: {str(e)}")
messagebox.showerror("错误", str(e)) messagebox.showerror("错误", str(e))
finally: finally:
self.start_button.config(state="normal") self.start_button.config(state="normal")
@@ -572,7 +702,7 @@ class RegistrationGUIWithPynoV2:
if __name__ == "__main__": if __name__ == "__main__":
root = tk.Tk() root = tk.Tk()
gui = RegistrationGUIWithPynoV2(root) gui = SteamRegistrationGUI(root)
# 启动时自动刷新Steam信息 # 启动时自动刷新Steam信息
threading.Thread(target=gui._refresh_steam_info_thread, daemon=True).start() threading.Thread(target=gui._refresh_steam_info_thread, daemon=True).start()
root.mainloop() root.mainloop()

View File

@@ -4,11 +4,12 @@ import os
import threading import threading
from ProxyPool import ProxyPool from ProxyPool import ProxyPool
from SteamRegistrationWithPyno import SteamRegistrationWithPyno from SteamRegistrationWithPyno import SteamRegistrationWithPyno
from EmailAPIClient import EmailAPIClient
class ThreadManagerWithPyno: class ThreadManagerWithPyno:
"""线程管理器 - 使用PyNoCaptcha版本""" """线程管理器 - 使用验证码解决方案"""
def __init__(self, config_path, email_file_path, proxy_file_path): def __init__(self, config_path, email_file_path, proxy_file_path, email_source="txt_file", reg_count=0, email_api_client=None):
self.config = self._load_config(config_path) self.config = self._load_config(config_path)
self._validate_config() self._validate_config()
self.proxy_pool = ProxyPool(proxy_file_path) self.proxy_pool = ProxyPool(proxy_file_path)
@@ -18,6 +19,11 @@ class ThreadManagerWithPyno:
self._running = True self._running = True
self._registrations = set() self._registrations = set()
self._registrations_lock = threading.Lock() self._registrations_lock = threading.Lock()
self.email_source = email_source
self.reg_count = reg_count
self.processed_count = 0
self.count_lock = threading.Lock()
self.email_api_client = email_api_client or EmailAPIClient()
def _validate_config(self): def _validate_config(self):
"""验证配置有效性""" """验证配置有效性"""
@@ -62,10 +68,28 @@ class ThreadManagerWithPyno:
return self._registration_local.registration return self._registration_local.registration
def process_email(self, email_data): def process_email(self, email_data):
"""处理一个邮箱账号的注册"""
# 检查是否达到注册数量限制
if self.reg_count > 0:
with self.count_lock:
if self.processed_count >= self.reg_count:
print(f"已达到注册数量限制: {self.reg_count}")
return
self.processed_count += 1
registration = self._get_registration() registration = self._get_registration()
registration.main(email_data) registration.main(email_data)
def get_email_from_api(self):
"""从API获取邮箱账号"""
try:
email_data = self.email_api_client.get_email_credentials()
if email_data:
return email_data
except Exception as e:
print(f"从API获取邮箱失败: {e}")
return None
def stop(self): def stop(self):
"""停止所有任务""" """停止所有任务"""
self._running = False self._running = False
@@ -92,28 +116,47 @@ class ThreadManagerWithPyno:
"""启动处理""" """启动处理"""
self._running = True self._running = True
try: try:
with open(self.email_file, "r") as file: if self.email_source == "api":
for line in file: # 使用API获取邮箱
if not self._running: while self._running and (self.reg_count == 0 or self.processed_count < self.reg_count):
email_data = self.get_email_from_api()
if not email_data:
print("无法从API获取邮箱任务停止")
break break
try: self.executor.submit(self.process_email, email_data)
email_data = self.parse_email_credentials(line.strip()) else:
self.executor.submit(self.process_email, email_data) # 使用本地文件获取邮箱
except ValueError as e: with open(self.email_file, "r", encoding="utf-8") as file:
print(f"错误的邮箱格式: {e}") for line in file:
continue if not self._running or (self.reg_count > 0 and self.processed_count >= self.reg_count):
break
try:
email_data = self.parse_email_credentials(line.strip())
self.executor.submit(self.process_email, email_data)
except ValueError as e:
print(f"错误的邮箱格式: {e}")
continue
finally: finally:
self.executor.shutdown(wait=True) self.executor.shutdown(wait=True)
class GUIThreadManagerWithPyno(ThreadManagerWithPyno): class GUIThreadManagerWithPyno(ThreadManagerWithPyno):
def __init__(self, config_path, email_file_path, proxy_file_path, gui, completed_tasks=None): def __init__(self, config_path, email_path, proxy_path, gui, completed_tasks=None, email_source="txt_file", reg_count=0, email_api_client=None):
super().__init__(config_path, email_file_path, proxy_file_path) super().__init__(config_path, email_path, proxy_path, email_source, reg_count, email_api_client)
self.gui = gui self.gui = gui
self.completed_tasks = completed_tasks or set() self.completed_tasks = completed_tasks or set()
def process_email(self, email_data): def process_email(self, email_data):
"""处理单个邮件账号""" """处理单个邮件账号"""
try: try:
# 检查是否达到注册数量限制
if self.reg_count > 0:
with self.count_lock:
if self.processed_count >= self.reg_count:
print(f"已达到注册数量限制: {self.reg_count}")
return
self.processed_count += 1
print(f"当前处理数量: {self.processed_count}/{self.reg_count}")
if not self._running: # 检查是否应该继续 if not self._running: # 检查是否应该继续
self.gui.update_status(email_data['email'], "任务已停止") self.gui.update_status(email_data['email'], "任务已停止")
return return
@@ -141,15 +184,36 @@ class GUIThreadManagerWithPyno(ThreadManagerWithPyno):
def start(self): def start(self):
"""启动处理""" """启动处理"""
self._running = True self._running = True
with open(self.email_file, 'r', encoding='utf-8') as file: self.processed_count = 0 # 重置计数器
with ThreadPoolExecutor(max_workers=self.config['executornum']) as self.executor:
for line in file: try:
if not self._running: if self.email_source == "api":
break # 使用API获取邮箱
try: with ThreadPoolExecutor(max_workers=self.config['executornum']) as self.executor:
email_data = self.parse_email_credentials(line) while self._running and (self.reg_count == 0 or self.processed_count < self.reg_count):
email_data = self.get_email_from_api()
if not email_data:
self.gui.update_status("API错误", "无法从API获取邮箱", result="失败")
break
# 跳过已完成的任务 # 跳过已完成的任务
if email_data['email'] not in self.completed_tasks: if email_data['email'] not in self.completed_tasks:
self.executor.submit(self.process_email, email_data) self.executor.submit(self.process_email, email_data)
except ValueError as e: else:
self.gui.update_status(email_data['email'],f"解析邮箱文件失败: {e}") print(f"跳过已完成的邮箱: {email_data['email']}")
else:
# 使用本地文件获取邮箱
with open(self.email_file, 'r', encoding='utf-8') as file:
with ThreadPoolExecutor(max_workers=self.config['executornum']) as self.executor:
for line in file:
if not self._running or (self.reg_count > 0 and self.processed_count >= self.reg_count):
break
try:
email_data = self.parse_email_credentials(line)
# 跳过已完成的任务
if email_data['email'] not in self.completed_tasks:
self.executor.submit(self.process_email, email_data)
except ValueError as e:
self.gui.update_status("解析错误", f"解析邮箱文件失败: {e}")
except Exception as e:
self.gui.update_status("系统错误", f"启动任务失败: {str(e)}", result="失败")

View File

@@ -2,16 +2,16 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Steam注册程序 - PyNoCaptcha V3版本启动器 Steam注册程序 - V3版本启动器
使用PyNoCaptcha解决验证码解决了sitekey获取问题 支持API获取邮箱账号和注册数量限制功能
""" """
import tkinter as tk import tkinter as tk
from RegistrationGUIWithPynoV2 import RegistrationGUIWithPynoV2 from RegistrationGUIWithPynoV2 import SteamRegistrationGUI
if __name__ == "__main__": if __name__ == "__main__":
print("正在启动Steam注册助手 PyNoCaptcha V3版本...") print("正在启动Steam账号注册助手 V3.0...")
print("这个版本修复了验证码头信息问题使用正确的User-Agent获取sitekey") print("这个版本新增自建邮箱API获取功能和注册数量限制功能")
root = tk.Tk() root = tk.Tk()
gui = RegistrationGUIWithPynoV2(root) gui = SteamRegistrationGUI(root)
root.mainloop() root.mainloop()