1072 lines
39 KiB
Python
1072 lines
39 KiB
Python
# -*- coding: UTF-8 -*-
|
||
'''
|
||
@Project :domainScanDemo
|
||
@File :system_settings.py
|
||
@IDE :PyCharm
|
||
@Author :梦伴
|
||
@Date :2026/4/10 15:00
|
||
@explain : 系统设置页面
|
||
'''
|
||
|
||
from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QLineEdit, QGroupBox, QCheckBox
|
||
from PySide6.QtCore import QTimer, QThreadPool, QRunnable, Slot
|
||
from PySide6.QtCore import Qt, QThread, Signal
|
||
from loguru import logger
|
||
import os
|
||
import json
|
||
import redis
|
||
|
||
from detect.juming import JM
|
||
from detect.juziseo import Juziseo
|
||
from detect.jucha import JC
|
||
from app.config import config
|
||
|
||
|
||
class RedisTask(QRunnable):
|
||
"""
|
||
Redis操作后台任务
|
||
"""
|
||
def __init__(self, func, *args, **kwargs):
|
||
"""
|
||
初始化Redis任务
|
||
|
||
:param func: 要执行的函数
|
||
:param args: 函数参数
|
||
:param kwargs: 函数关键字参数
|
||
"""
|
||
super().__init__()
|
||
self.func = func
|
||
self.args = args
|
||
self.kwargs = kwargs
|
||
|
||
@Slot()
|
||
def run(self):
|
||
"""
|
||
执行Redis操作
|
||
"""
|
||
try:
|
||
self.func(*self.args, **self.kwargs)
|
||
except Exception as e:
|
||
logger.error(f"Redis操作失败: {e}")
|
||
|
||
|
||
class LoginThread(QThread):
|
||
"""
|
||
登录线程
|
||
"""
|
||
finished = Signal(bool, str)
|
||
|
||
def __init__(self, email, password, platform):
|
||
"""
|
||
初始化登录线程
|
||
|
||
:param email: 账号
|
||
:param password: 密码
|
||
:param platform: 平台 (juming: 聚名, juziseo: 桔子SEO)
|
||
"""
|
||
super().__init__()
|
||
self.email = email
|
||
self.password = password
|
||
self.platform = platform
|
||
|
||
def run(self):
|
||
"""
|
||
运行登录线程
|
||
"""
|
||
try:
|
||
if self.platform == "juming":
|
||
# 初始化聚名客户端
|
||
jm = JM()
|
||
|
||
# 加载 Cookie
|
||
jm.load_cookies()
|
||
logger.info("已加载聚名 Cookie")
|
||
|
||
# 登录
|
||
logger.info(f"开始登录聚名网: {self.email}")
|
||
login_result = jm.user_zh_p_login(self.email, self.password)
|
||
if not login_result[0]:
|
||
self.finished.emit(False, f"登录失败: {login_result[1]}")
|
||
return
|
||
logger.info("登录成功")
|
||
|
||
# 保存cookies
|
||
jm.save_cookies()
|
||
logger.info("已保存聚名 Cookie")
|
||
|
||
self.finished.emit(True, "登录成功")
|
||
elif self.platform == "juziseo":
|
||
# 初始化桔子SEO客户端
|
||
juziseo = Juziseo()
|
||
|
||
# 加载 Cookie
|
||
juziseo.load_cookies()
|
||
logger.info("已加载桔子SEO Cookie")
|
||
|
||
# 登录
|
||
logger.info(f"开始登录桔子SEO: {self.email}")
|
||
login_result = juziseo.login(self.email, self.password)
|
||
if not login_result[0]:
|
||
self.finished.emit(False, f"登录失败: {login_result[1]}")
|
||
return
|
||
logger.info("登录成功")
|
||
|
||
# 保存cookies
|
||
juziseo.save_cookies()
|
||
logger.info("已保存桔子SEO Cookie")
|
||
|
||
self.finished.emit(True, "登录成功")
|
||
elif self.platform == "jucha":
|
||
# 初始化聚查客户端
|
||
jc = JC()
|
||
|
||
# 加载聚名 Cookie
|
||
jc.load_juming_cookies()
|
||
logger.info("已加载聚名 Cookie")
|
||
|
||
# 登录
|
||
logger.info("开始登录聚查网")
|
||
login_result = jc.auth_login()
|
||
if not login_result[0]:
|
||
self.finished.emit(False, f"登录失败: {login_result[1]}")
|
||
return
|
||
logger.info("登录成功")
|
||
|
||
# 保存cookies
|
||
jc.save_cookies()
|
||
logger.info("已保存聚查 Cookie")
|
||
|
||
self.finished.emit(True, "登录成功")
|
||
except Exception as e:
|
||
logger.error(f"登录失败: {e}")
|
||
self.finished.emit(False, f"登录失败: {str(e)}")
|
||
|
||
|
||
class SystemSettingsWidget(QWidget):
|
||
"""
|
||
系统设置页面
|
||
"""
|
||
|
||
def __init__(self):
|
||
"""
|
||
初始化系统设置页面
|
||
"""
|
||
super().__init__()
|
||
|
||
# 初始化Redis客户端
|
||
self.redis_client = None
|
||
self.use_redis = False
|
||
self.thread_pool = QThreadPool()
|
||
self.thread_pool.setMaxThreadCount(5) # 最大线程数
|
||
self.init_redis()
|
||
|
||
# 创建布局
|
||
layout = QVBoxLayout(self)
|
||
|
||
# 创建登录区域容器
|
||
login_container = QGroupBox("登录设置")
|
||
login_container.setStyleSheet("""
|
||
QGroupBox {
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
margin-bottom: 20px;
|
||
padding: 15px;
|
||
}
|
||
""")
|
||
login_layout = QVBoxLayout(login_container)
|
||
|
||
# 聚名登录区域
|
||
juming_subgroup = QGroupBox("聚名网登录")
|
||
juming_subgroup.setStyleSheet("""
|
||
QGroupBox {
|
||
font-size: 13px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
border: 1px solid #eee;
|
||
border-radius: 4px;
|
||
margin-bottom: 15px;
|
||
padding: 10px;
|
||
}
|
||
""")
|
||
juming_layout = QVBoxLayout(juming_subgroup)
|
||
|
||
# 聚名输入区域(两列布局)
|
||
juming_input_layout = QHBoxLayout()
|
||
juming_input_layout.setSpacing(20)
|
||
|
||
# 邮箱输入
|
||
email_layout = QVBoxLayout()
|
||
email_label = QLabel("邮箱:")
|
||
email_label.setStyleSheet("font-size: 14px; color: #666; margin-bottom: 8px;")
|
||
self.juming_email_input = QLineEdit()
|
||
self.juming_email_input.setPlaceholderText("请输入聚名网账号")
|
||
self.juming_email_input.setStyleSheet("""
|
||
QLineEdit {
|
||
font-size: 14px;
|
||
padding: 8px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
min-width: 250px;
|
||
min-height: 22px;
|
||
}
|
||
QLineEdit:focus {
|
||
border-color: #4CAF50;
|
||
outline: none;
|
||
}
|
||
""")
|
||
email_layout.addWidget(email_label)
|
||
email_layout.addWidget(self.juming_email_input)
|
||
juming_input_layout.addLayout(email_layout)
|
||
|
||
# 密码输入
|
||
password_layout = QVBoxLayout()
|
||
password_label = QLabel("密码:")
|
||
password_label.setStyleSheet("font-size: 14px; color: #666; margin-bottom: 8px;")
|
||
self.juming_password_input = QLineEdit()
|
||
self.juming_password_input.setPlaceholderText("请输入聚名网密码")
|
||
self.juming_password_input.setEchoMode(QLineEdit.Password)
|
||
self.juming_password_input.setStyleSheet("""
|
||
QLineEdit {
|
||
font-size: 14px;
|
||
padding: 8px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
min-width: 250px;
|
||
min-height: 22px;
|
||
}
|
||
QLineEdit:focus {
|
||
border-color: #4CAF50;
|
||
outline: none;
|
||
}
|
||
""")
|
||
password_layout.addWidget(password_label)
|
||
password_layout.addWidget(self.juming_password_input)
|
||
juming_input_layout.addLayout(password_layout)
|
||
juming_layout.addLayout(juming_input_layout)
|
||
|
||
# 登录说明
|
||
juming_note = QLabel("聚名聚查联名登录:登录聚名后会自动登录聚查")
|
||
juming_note.setStyleSheet("font-size: 12px; color: #666; margin-top: 12px; margin-bottom: 12px;")
|
||
juming_layout.addWidget(juming_note)
|
||
|
||
# 登录按钮布局
|
||
juming_btn_layout = QHBoxLayout()
|
||
juming_btn_layout.addStretch() # 添加弹性空间,将按钮推到右侧
|
||
juming_login_btn = QPushButton("登录聚名网")
|
||
juming_login_btn.clicked.connect(self.login_juming)
|
||
juming_login_btn.setStyleSheet("""
|
||
QPushButton {
|
||
font-size: 14px;
|
||
padding: 8px 16px;
|
||
background-color: #4CAF50;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 4px;
|
||
}
|
||
QPushButton:hover {
|
||
background-color: #45a049;
|
||
}
|
||
QPushButton:disabled {
|
||
background-color: #cccccc;
|
||
}
|
||
""")
|
||
juming_btn_layout.addWidget(juming_login_btn)
|
||
juming_layout.addLayout(juming_btn_layout)
|
||
|
||
login_layout.addWidget(juming_subgroup)
|
||
|
||
# 桔子SEO登录区域
|
||
juziseo_subgroup = QGroupBox("桔子SEO登录")
|
||
juziseo_subgroup.setStyleSheet("""
|
||
QGroupBox {
|
||
font-size: 13px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
border: 1px solid #eee;
|
||
border-radius: 4px;
|
||
margin-bottom: 15px;
|
||
padding: 10px;
|
||
}
|
||
""")
|
||
juziseo_layout = QVBoxLayout(juziseo_subgroup)
|
||
|
||
# 桔子SEO输入区域(两列布局)
|
||
juziseo_input_layout = QHBoxLayout()
|
||
juziseo_input_layout.setSpacing(20)
|
||
|
||
# 账号输入
|
||
juziseo_email_layout = QVBoxLayout()
|
||
juziseo_email_label = QLabel("账号:")
|
||
juziseo_email_label.setStyleSheet("font-size: 14px; color: #666; margin-bottom: 8px;")
|
||
self.juziseo_email_input = QLineEdit()
|
||
self.juziseo_email_input.setPlaceholderText("请输入桔子SEO账号")
|
||
self.juziseo_email_input.setStyleSheet("""
|
||
QLineEdit {
|
||
font-size: 14px;
|
||
padding: 8px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
min-width: 250px;
|
||
min-height: 22px;
|
||
}
|
||
QLineEdit:focus {
|
||
border-color: #2196F3;
|
||
outline: none;
|
||
}
|
||
""")
|
||
juziseo_email_layout.addWidget(juziseo_email_label)
|
||
juziseo_email_layout.addWidget(self.juziseo_email_input)
|
||
juziseo_input_layout.addLayout(juziseo_email_layout)
|
||
|
||
# 密码输入
|
||
juziseo_password_layout = QVBoxLayout()
|
||
juziseo_password_label = QLabel("密码:")
|
||
juziseo_password_label.setStyleSheet("font-size: 14px; color: #666; margin-bottom: 8px;")
|
||
self.juziseo_password_input = QLineEdit()
|
||
self.juziseo_password_input.setPlaceholderText("请输入桔子SEO密码")
|
||
self.juziseo_password_input.setEchoMode(QLineEdit.Password)
|
||
self.juziseo_password_input.setStyleSheet("""
|
||
QLineEdit {
|
||
font-size: 14px;
|
||
padding: 8px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
min-width: 250px;
|
||
min-height: 22px;
|
||
}
|
||
QLineEdit:focus {
|
||
border-color: #2196F3;
|
||
outline: none;
|
||
}
|
||
""")
|
||
juziseo_password_layout.addWidget(juziseo_password_label)
|
||
juziseo_password_layout.addWidget(self.juziseo_password_input)
|
||
juziseo_input_layout.addLayout(juziseo_password_layout)
|
||
juziseo_layout.addLayout(juziseo_input_layout)
|
||
|
||
# 登录按钮布局
|
||
juziseo_btn_layout = QHBoxLayout()
|
||
juziseo_btn_layout.addStretch() # 添加弹性空间,将按钮推到右侧
|
||
juziseo_login_btn = QPushButton("登录桔子SEO")
|
||
juziseo_login_btn.clicked.connect(self.login_juziseo)
|
||
juziseo_login_btn.setStyleSheet("""
|
||
QPushButton {
|
||
font-size: 14px;
|
||
padding: 8px 16px;
|
||
background-color: #2196F3;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 4px;
|
||
}
|
||
QPushButton:hover {
|
||
background-color: #0b7dda;
|
||
}
|
||
QPushButton:disabled {
|
||
background-color: #cccccc;
|
||
}
|
||
""")
|
||
juziseo_btn_layout.addWidget(juziseo_login_btn)
|
||
juziseo_layout.addLayout(juziseo_btn_layout)
|
||
|
||
login_layout.addWidget(juziseo_subgroup)
|
||
|
||
layout.addWidget(login_container)
|
||
|
||
# 创建代理IP配置区域
|
||
proxy_group = QGroupBox("代理IP配置")
|
||
proxy_group.setStyleSheet("""
|
||
QGroupBox {
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
margin-bottom: 20px;
|
||
padding: 15px;
|
||
}
|
||
""")
|
||
proxy_layout = QVBoxLayout(proxy_group)
|
||
|
||
# 启用代理IP复选框
|
||
proxy_enable_layout = QHBoxLayout()
|
||
proxy_enable_label = QLabel("启用代理IP:")
|
||
proxy_enable_label.setStyleSheet("font-size: 14px; color: #333; min-width: 100px; font-weight: bold;")
|
||
self.proxy_enable_checkbox = QCheckBox()
|
||
self.proxy_enable_checkbox.setStyleSheet("""
|
||
QCheckBox {
|
||
font-size: 14px;
|
||
spacing: 8px;
|
||
}
|
||
QCheckBox::indicator {
|
||
width: 20px;
|
||
height: 20px;
|
||
}
|
||
QCheckBox::indicator:unchecked {
|
||
border: 2px solid #999;
|
||
background-color: white;
|
||
border-radius: 4px;
|
||
}
|
||
QCheckBox::indicator:checked {
|
||
border: 2px solid #9c27b0;
|
||
background-color: #9c27b0;
|
||
border-radius: 4px;
|
||
}
|
||
QCheckBox::indicator:checked::after {
|
||
content: '✓';
|
||
color: white;
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
position: absolute;
|
||
top: 0px;
|
||
left: 3px;
|
||
}
|
||
""")
|
||
self.proxy_enable_checkbox.stateChanged.connect(self.save_proxy_config)
|
||
proxy_enable_layout.addWidget(proxy_enable_label)
|
||
proxy_enable_layout.addWidget(self.proxy_enable_checkbox)
|
||
proxy_enable_layout.setContentsMargins(0, 0, 0, 10)
|
||
proxy_layout.addLayout(proxy_enable_layout)
|
||
|
||
# 代理IP链接输入
|
||
proxy_url_layout = QHBoxLayout()
|
||
proxy_url_label = QLabel("代理IP链接:")
|
||
proxy_url_label.setStyleSheet("font-size: 14px; color: #666; min-width: 100px;")
|
||
self.proxy_url_input = QLineEdit()
|
||
self.proxy_url_input.setPlaceholderText("请输入获取代理IP的链接")
|
||
self.proxy_url_input.setStyleSheet("""
|
||
QLineEdit {
|
||
font-size: 14px;
|
||
padding: 8px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
}
|
||
QLineEdit:focus {
|
||
border-color: #9c27b0;
|
||
outline: none;
|
||
}
|
||
""")
|
||
# 输入时自动保存
|
||
self.proxy_url_input.textChanged.connect(self.save_proxy_config)
|
||
proxy_url_layout.addWidget(proxy_url_label)
|
||
proxy_url_layout.addWidget(self.proxy_url_input)
|
||
proxy_url_layout.setContentsMargins(0, 0, 0, 15)
|
||
proxy_layout.addLayout(proxy_url_layout)
|
||
|
||
layout.addWidget(proxy_group)
|
||
|
||
# 创建域名后缀配置区域
|
||
domain_suffix_group = QGroupBox("域名后缀配置")
|
||
domain_suffix_group.setStyleSheet("""
|
||
QGroupBox {
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
margin-bottom: 20px;
|
||
padding: 15px;
|
||
}
|
||
""")
|
||
domain_suffix_layout = QVBoxLayout(domain_suffix_group)
|
||
|
||
# 域名后缀输入
|
||
suffix_layout = QHBoxLayout()
|
||
suffix_label = QLabel("保留后缀:")
|
||
suffix_label.setStyleSheet("font-size: 14px; color: #666; min-width: 80px;")
|
||
self.suffix_input = QLineEdit()
|
||
self.suffix_input.setPlaceholderText("请输入需要保留的域名后缀,多个用逗号分隔,如:.com,.net")
|
||
self.suffix_input.setStyleSheet("""
|
||
QLineEdit {
|
||
font-size: 14px;
|
||
padding: 8px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
}
|
||
QLineEdit:focus {
|
||
border-color: #ff9800;
|
||
outline: none;
|
||
}
|
||
""")
|
||
# 输入时自动保存
|
||
self.suffix_input.textChanged.connect(self.save_suffixes)
|
||
suffix_layout.addWidget(suffix_label)
|
||
suffix_layout.addWidget(self.suffix_input)
|
||
suffix_layout.setContentsMargins(0, 0, 0, 5)
|
||
domain_suffix_layout.addLayout(suffix_layout)
|
||
|
||
# 添加分隔符提示
|
||
suffix_note = QLabel("提示:多个域名后缀请用英文逗号分割")
|
||
suffix_note.setStyleSheet("font-size: 12px; color: #999; margin-bottom: 10px;")
|
||
domain_suffix_layout.addWidget(suffix_note)
|
||
|
||
layout.addWidget(domain_suffix_group)
|
||
|
||
# 创建检测选项配置区域
|
||
detect_group = QGroupBox("检测选项配置")
|
||
detect_group.setStyleSheet("""
|
||
QGroupBox {
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
margin-bottom: 20px;
|
||
padding: 15px;
|
||
}
|
||
""")
|
||
detect_layout = QVBoxLayout(detect_group)
|
||
|
||
# 检测选项列表
|
||
self.detect_checkboxes = {}
|
||
detect_options = [
|
||
("detect_register", "1. 检测注册"),
|
||
("detect_chinaz", "2. 站长之家查询"),
|
||
("detect_aizhan", "3. 爱站网查询"),
|
||
("detect_baidu_site", "4. 百度site查询"),
|
||
("detect_360_site", "5. 360的site查询"),
|
||
("detect_baidu_security", "6. 百度网址安全中心查询"),
|
||
("detect_whois", "7. 聚查中的WHOIS 查询"),
|
||
("detect_beian", "8. 聚查中的备案相关查询"),
|
||
("detect_intercept", "9. 聚查中的拦截检测相关查询"),
|
||
("detect_juziseo", "10. 桔子历史"),
|
||
("detect_juziseo_outlink", "11. 桔子外链")
|
||
]
|
||
|
||
# 创建横向布局容器
|
||
detect_checkbox_container = QHBoxLayout()
|
||
detect_checkbox_container.setSpacing(20)
|
||
detect_checkbox_container.setContentsMargins(0, 0, 0, 0)
|
||
|
||
# 创建两列布局
|
||
left_column = QVBoxLayout()
|
||
right_column = QVBoxLayout()
|
||
|
||
# 将检测选项分为两列
|
||
for i, (key, label_text) in enumerate(detect_options):
|
||
checkbox = QCheckBox(label_text)
|
||
checkbox.setStyleSheet("font-size: 14px;")
|
||
checkbox.stateChanged.connect(self.save_detect_options)
|
||
self.detect_checkboxes[key] = checkbox
|
||
|
||
# 前5个选项放在左列,后5个放在右列
|
||
if i < 5:
|
||
left_column.addWidget(checkbox)
|
||
else:
|
||
right_column.addWidget(checkbox)
|
||
|
||
# 添加列到容器
|
||
detect_checkbox_container.addLayout(left_column)
|
||
detect_checkbox_container.addLayout(right_column)
|
||
|
||
# 添加容器到检测布局
|
||
detect_layout.addLayout(detect_checkbox_container)
|
||
|
||
# 创建检测配置容器
|
||
detect_config_container = QHBoxLayout()
|
||
detect_config_container.setSpacing(20)
|
||
detect_config_container.setContentsMargins(0, 0, 0, 20)
|
||
|
||
# 添加检测选项配置
|
||
detect_config_container.addWidget(detect_group, 2) # 占2份空间
|
||
|
||
# 创建检测线程配置区域
|
||
thread_group = QGroupBox("检测线程配置")
|
||
thread_group.setStyleSheet("""
|
||
QGroupBox {
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
margin-bottom: 20px;
|
||
padding: 15px;
|
||
}
|
||
""")
|
||
thread_layout = QVBoxLayout(thread_group)
|
||
|
||
# 检测线程数输入
|
||
thread_count_layout = QHBoxLayout()
|
||
thread_count_label = QLabel("线程数量:")
|
||
thread_count_label.setStyleSheet("font-size: 14px; color: #666; min-width: 80px;")
|
||
self.thread_count_input = QLineEdit()
|
||
self.thread_count_input.setPlaceholderText("请输入检测线程数量,默认为100")
|
||
self.thread_count_input.setStyleSheet("""
|
||
QLineEdit {
|
||
font-size: 14px;
|
||
padding: 8px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
}
|
||
QLineEdit:focus {
|
||
border-color: #2196F3;
|
||
outline: none;
|
||
}
|
||
""")
|
||
# 输入时自动保存
|
||
self.thread_count_input.textChanged.connect(self.save_thread_count)
|
||
thread_count_layout.addWidget(thread_count_label)
|
||
thread_count_layout.addWidget(self.thread_count_input)
|
||
thread_count_layout.setContentsMargins(0, 0, 0, 5)
|
||
thread_layout.addLayout(thread_count_layout)
|
||
|
||
# 添加线程数提示
|
||
thread_note = QLabel("提示:线程数量不宜设置过大,建议根据服务器性能调整")
|
||
thread_note.setStyleSheet("font-size: 12px; color: #999; margin-bottom: 10px;")
|
||
thread_layout.addWidget(thread_note)
|
||
|
||
# 添加检测线程配置到容器
|
||
detect_config_container.addWidget(thread_group, 1) # 占1份空间
|
||
|
||
# 将容器添加到主布局
|
||
layout.addLayout(detect_config_container)
|
||
|
||
# 创建状态标签
|
||
self.status_label = QLabel("")
|
||
self.status_label.setAlignment(Qt.AlignCenter)
|
||
self.status_label.setStyleSheet("font-size: 14px; color: #333; margin-top: 10px; padding: 10px; background-color: #f0f8ff; border-radius: 4px;")
|
||
layout.addWidget(self.status_label)
|
||
|
||
# 加载保存的账号密码
|
||
self.load_credentials()
|
||
|
||
# 加载域名后缀
|
||
self.load_suffixes()
|
||
|
||
# 加载检测线程数
|
||
self.load_thread_count()
|
||
|
||
# 加载cookie
|
||
self.load_cookies()
|
||
|
||
# 加载检测选项
|
||
self.load_detect_options()
|
||
|
||
# 加载代理IP配置
|
||
self.load_proxy_config()
|
||
|
||
logger.info("系统设置页面创建完成")
|
||
|
||
def init_redis(self):
|
||
"""
|
||
初始化Redis客户端连接
|
||
"""
|
||
try:
|
||
# 使用连接池
|
||
pool = redis.ConnectionPool(
|
||
host=config.REDIS_HOST,
|
||
port=config.REDIS_PORT,
|
||
password=config.REDIS_PASSWORD,
|
||
db=config.REDIS_DB,
|
||
decode_responses=True,
|
||
socket_connect_timeout=3, # 减少连接超时时间
|
||
socket_timeout=3, # 减少操作超时时间
|
||
max_connections=10 # 连接池大小
|
||
)
|
||
self.redis_client = redis.Redis(connection_pool=pool)
|
||
# 测试连接
|
||
self.redis_client.ping()
|
||
logger.info(f"Redis 连接成功: {config.REDIS_HOST}:{config.REDIS_PORT}")
|
||
self.use_redis = True
|
||
except Exception as e:
|
||
logger.warning(f"Redis 连接失败: {e},将只保存到本地文件")
|
||
self.redis_client = None
|
||
self.use_redis = False
|
||
|
||
def check_redis_connection(self):
|
||
"""
|
||
检查Redis连接状态,如果连接已断开则重新连接
|
||
"""
|
||
if not self.use_redis or self.redis_client is None:
|
||
return False
|
||
|
||
try:
|
||
# 测试连接
|
||
self.redis_client.ping()
|
||
return True
|
||
except Exception as e:
|
||
logger.warning(f"Redis 连接已断开,尝试重新连接: {e}")
|
||
# 重新连接
|
||
self.init_redis()
|
||
return self.use_redis
|
||
|
||
def save_credentials(self):
|
||
"""
|
||
保存账号密码到本地文件和Redis
|
||
"""
|
||
credentials = {
|
||
"juming": {
|
||
"email": self.juming_email_input.text().strip(),
|
||
"password": self.juming_password_input.text().strip()
|
||
},
|
||
"juziseo": {
|
||
"email": self.juziseo_email_input.text().strip(),
|
||
"password": self.juziseo_password_input.text().strip()
|
||
}
|
||
}
|
||
|
||
try:
|
||
# 保存到本地文件(UI线程执行)
|
||
with open('credentials.json', 'w', encoding='utf-8') as f:
|
||
json.dump(credentials, f, indent=2, ensure_ascii=False)
|
||
logger.info("账号密码保存成功")
|
||
|
||
# 保存到Redis(后台线程执行)
|
||
def save_to_redis():
|
||
if self.check_redis_connection():
|
||
self.redis_client.set('domain_tool:credentials', json.dumps(credentials))
|
||
logger.info("账号密码已同步到Redis")
|
||
# 发布配置更新消息
|
||
self.redis_client.publish('domain_tool:config_update', 'credentials')
|
||
|
||
# 提交到线程池执行
|
||
task = RedisTask(save_to_redis)
|
||
self.thread_pool.start(task)
|
||
except Exception as e:
|
||
logger.error(f"保存账号密码失败: {e}")
|
||
|
||
def save_suffixes(self):
|
||
"""
|
||
保存域名后缀到本地文件和Redis
|
||
"""
|
||
suffixes = self.suffix_input.text().strip()
|
||
|
||
try:
|
||
# 保存到本地文件(UI线程执行)
|
||
with open('domain_suffixes.json', 'w', encoding='utf-8') as f:
|
||
json.dump({"suffixes": suffixes}, f, indent=2, ensure_ascii=False)
|
||
logger.info("域名后缀保存成功")
|
||
|
||
# 保存到Redis(后台线程执行)
|
||
def save_to_redis():
|
||
if self.check_redis_connection():
|
||
self.redis_client.set('domain_tool:domain_suffixes', suffixes)
|
||
logger.info("域名后缀已同步到Redis")
|
||
# 发布配置更新消息
|
||
self.redis_client.publish('domain_tool:config_update', 'domain_suffixes')
|
||
|
||
# 提交到线程池执行
|
||
task = RedisTask(save_to_redis)
|
||
self.thread_pool.start(task)
|
||
except Exception as e:
|
||
logger.error(f"保存域名后缀失败: {e}")
|
||
|
||
def load_suffixes(self):
|
||
"""
|
||
从本地文件加载域名后缀
|
||
"""
|
||
try:
|
||
if os.path.exists('domain_suffixes.json'):
|
||
with open('domain_suffixes.json', 'r', encoding='utf-8') as f:
|
||
data = json.load(f)
|
||
suffixes = data.get('suffixes', '.com,.net')
|
||
self.suffix_input.setText(suffixes)
|
||
logger.info("域名后缀加载成功")
|
||
else:
|
||
# 默认值
|
||
self.suffix_input.setText('.com,.net')
|
||
self.save_suffixes()
|
||
logger.info("使用默认域名后缀")
|
||
except Exception as e:
|
||
logger.error(f"加载域名后缀失败: {e}")
|
||
# 使用默认值
|
||
self.suffix_input.setText('.com,.net')
|
||
|
||
def load_credentials(self):
|
||
"""
|
||
从本地文件加载账号密码
|
||
"""
|
||
try:
|
||
if os.path.exists('credentials.json'):
|
||
with open('credentials.json', 'r', encoding='utf-8') as f:
|
||
credentials = json.load(f)
|
||
|
||
# 加载聚名账号密码
|
||
if 'juming' in credentials:
|
||
self.juming_email_input.setText(credentials['juming'].get('email', ''))
|
||
self.juming_password_input.setText(credentials['juming'].get('password', ''))
|
||
|
||
# 加载桔子SEO账号密码
|
||
if 'juziseo' in credentials:
|
||
self.juziseo_email_input.setText(credentials['juziseo'].get('email', ''))
|
||
self.juziseo_password_input.setText(credentials['juziseo'].get('password', ''))
|
||
|
||
logger.info("账号密码加载成功")
|
||
except Exception as e:
|
||
logger.error(f"加载账号密码失败: {e}")
|
||
|
||
def load_cookies(self):
|
||
"""
|
||
加载cookie
|
||
"""
|
||
try:
|
||
# 加载聚名cookie
|
||
jm = JM()
|
||
jm.load_cookies()
|
||
logger.info("聚名cookie加载成功")
|
||
|
||
# 加载桔子SEO cookie
|
||
juziseo = Juziseo()
|
||
juziseo.load_cookies()
|
||
logger.info("桔子SEO cookie加载成功")
|
||
|
||
# 加载聚查cookie
|
||
jc = JC()
|
||
jc.load_cookies()
|
||
logger.info("聚查cookie加载成功")
|
||
except Exception as e:
|
||
logger.error(f"加载cookie失败: {e}")
|
||
|
||
def login_juming(self):
|
||
"""
|
||
登录聚名网
|
||
"""
|
||
email = self.juming_email_input.text().strip()
|
||
password = self.juming_password_input.text().strip()
|
||
|
||
if not email or not password:
|
||
self.status_label.setText("请输入账号和密码")
|
||
return
|
||
|
||
self.status_label.setText("正在登录聚名网...")
|
||
|
||
# 创建并启动登录线程
|
||
self.login_thread = LoginThread(email, password, "juming")
|
||
self.login_thread.finished.connect(self.login_finished)
|
||
self.login_thread.start()
|
||
|
||
logger.info(f"开始登录聚名网: {email}")
|
||
|
||
def login_juziseo(self):
|
||
"""
|
||
登录桔子SEO
|
||
"""
|
||
email = self.juziseo_email_input.text().strip()
|
||
password = self.juziseo_password_input.text().strip()
|
||
|
||
if not email or not password:
|
||
self.status_label.setText("请输入账号和密码")
|
||
return
|
||
|
||
self.status_label.setText("正在登录桔子SEO...")
|
||
|
||
# 创建并启动登录线程
|
||
self.login_thread = LoginThread(email, password, "juziseo")
|
||
self.login_thread.finished.connect(self.login_finished)
|
||
self.login_thread.start()
|
||
|
||
logger.info(f"开始登录桔子SEO: {email}")
|
||
|
||
def login_jucha(self):
|
||
"""
|
||
登录聚查网
|
||
"""
|
||
# 检查聚名Cookie是否存在
|
||
if not os.path.exists('juming_cookies.pkl'):
|
||
self.status_label.setText("请先登录聚名网")
|
||
return
|
||
|
||
self.status_label.setText("正在登录聚查网...")
|
||
|
||
# 创建并启动登录线程
|
||
self.login_thread = LoginThread("", "", "jucha")
|
||
self.login_thread.finished.connect(self.login_finished)
|
||
self.login_thread.start()
|
||
|
||
logger.info("开始登录聚查网")
|
||
|
||
def save_detect_options(self):
|
||
"""
|
||
保存检测选项到本地文件和Redis
|
||
"""
|
||
detect_options = {}
|
||
for key, checkbox in self.detect_checkboxes.items():
|
||
detect_options[key] = checkbox.isChecked()
|
||
|
||
try:
|
||
# 保存到本地文件(UI线程执行)
|
||
with open('detect_options.json', 'w', encoding='utf-8') as f:
|
||
json.dump(detect_options, f, indent=2, ensure_ascii=False)
|
||
logger.info("检测选项保存成功")
|
||
|
||
# 保存到Redis(后台线程执行)
|
||
def save_to_redis():
|
||
if self.check_redis_connection():
|
||
self.redis_client.set('domain_tool:detect_options', json.dumps(detect_options))
|
||
logger.info("检测选项已同步到Redis")
|
||
# 发布配置更新消息
|
||
self.redis_client.publish('domain_tool:config_update', 'detect_options')
|
||
|
||
# 提交到线程池执行
|
||
task = RedisTask(save_to_redis)
|
||
self.thread_pool.start(task)
|
||
except Exception as e:
|
||
logger.error(f"保存检测选项失败: {e}")
|
||
|
||
def load_detect_options(self):
|
||
"""
|
||
从本地文件加载检测选项
|
||
"""
|
||
try:
|
||
if os.path.exists('detect_options.json'):
|
||
with open('detect_options.json', 'r', encoding='utf-8') as f:
|
||
detect_options = json.load(f)
|
||
|
||
for key, checked in detect_options.items():
|
||
if key in self.detect_checkboxes:
|
||
self.detect_checkboxes[key].setChecked(checked)
|
||
|
||
logger.info("检测选项加载成功")
|
||
else:
|
||
# 默认值:全部勾选
|
||
for checkbox in self.detect_checkboxes.values():
|
||
checkbox.setChecked(True)
|
||
self.save_detect_options()
|
||
logger.info("使用默认检测选项")
|
||
except Exception as e:
|
||
logger.error(f"加载检测选项失败: {e}")
|
||
# 使用默认值
|
||
for checkbox in self.detect_checkboxes.values():
|
||
checkbox.setChecked(True)
|
||
|
||
def save_proxy_config(self):
|
||
"""
|
||
保存代理IP配置到本地文件和Redis
|
||
"""
|
||
proxy_enable = self.proxy_enable_checkbox.isChecked()
|
||
proxy_url = self.proxy_url_input.text().strip()
|
||
|
||
try:
|
||
# 保存到本地文件(UI线程执行)
|
||
with open('proxy_config.json', 'w', encoding='utf-8') as f:
|
||
json.dump({"proxy_enable": proxy_enable, "proxy_url": proxy_url}, f, indent=2, ensure_ascii=False)
|
||
logger.info("代理IP配置保存成功")
|
||
|
||
# 保存到Redis(后台线程执行)
|
||
def save_to_redis():
|
||
if self.check_redis_connection():
|
||
self.redis_client.set('domain_tool:proxy_config', json.dumps({"proxy_enable": proxy_enable, "proxy_url": proxy_url}))
|
||
logger.info("代理IP配置已同步到Redis")
|
||
# 发布配置更新消息
|
||
self.redis_client.publish('domain_tool:config_update', 'proxy_config')
|
||
|
||
# 提交到线程池执行
|
||
task = RedisTask(save_to_redis)
|
||
self.thread_pool.start(task)
|
||
except Exception as e:
|
||
logger.error(f"保存代理IP配置失败: {e}")
|
||
|
||
def load_proxy_config(self):
|
||
"""
|
||
从本地文件加载代理IP配置
|
||
"""
|
||
try:
|
||
if os.path.exists('proxy_config.json'):
|
||
with open('proxy_config.json', 'r', encoding='utf-8') as f:
|
||
proxy_config = json.load(f)
|
||
proxy_enable = proxy_config.get('proxy_enable', False)
|
||
proxy_url = proxy_config.get('proxy_url', '')
|
||
self.proxy_enable_checkbox.setChecked(proxy_enable)
|
||
self.proxy_url_input.setText(proxy_url)
|
||
logger.info("代理IP配置加载成功")
|
||
else:
|
||
# 默认值:未启用,空链接
|
||
self.proxy_enable_checkbox.setChecked(False)
|
||
self.proxy_url_input.setText('')
|
||
self.save_proxy_config()
|
||
logger.info("使用默认代理IP配置")
|
||
except Exception as e:
|
||
logger.error(f"加载代理IP配置失败: {e}")
|
||
# 使用默认值
|
||
self.proxy_enable_checkbox.setChecked(False)
|
||
self.proxy_url_input.setText('')
|
||
|
||
def toggle_password_visibility(self, password_input):
|
||
"""
|
||
切换密码输入框的可见性
|
||
|
||
:param password_input: 密码输入框
|
||
"""
|
||
if password_input.echoMode() == QLineEdit.Password:
|
||
password_input.setEchoMode(QLineEdit.Normal)
|
||
# 找到对应的按钮并修改图标
|
||
if password_input == self.juming_password_input:
|
||
self.juming_password_visibility_btn.setText("🙈")
|
||
elif password_input == self.juziseo_password_input:
|
||
self.juziseo_password_visibility_btn.setText("🙈")
|
||
else:
|
||
password_input.setEchoMode(QLineEdit.Password)
|
||
# 找到对应的按钮并修改图标
|
||
if password_input == self.juming_password_input:
|
||
self.juming_password_visibility_btn.setText("👁")
|
||
elif password_input == self.juziseo_password_input:
|
||
self.juziseo_password_visibility_btn.setText("👁")
|
||
|
||
def login_finished(self, success, message):
|
||
"""
|
||
登录完成
|
||
|
||
:param success: 是否成功
|
||
:param message: 消息
|
||
"""
|
||
self.status_label.setText(message)
|
||
|
||
# 登录成功后保存账号密码
|
||
if success:
|
||
self.save_credentials()
|
||
# 聚名登录成功后自动登录聚查
|
||
if self.login_thread.platform == "juming":
|
||
self.status_label.setText("聚名登录成功,正在自动登录聚查...")
|
||
# 延迟一秒后登录聚查,确保聚名cookie已保存
|
||
QTimer.singleShot(1000, self.login_jucha)
|
||
|
||
logger.info(f"登录完成: {message}")
|
||
|
||
def save_thread_count(self):
|
||
"""
|
||
保存检测线程数到本地文件和Redis
|
||
"""
|
||
thread_count = self.thread_count_input.text().strip()
|
||
|
||
try:
|
||
# 保存到本地文件(UI线程执行)
|
||
with open('thread_count.json', 'w', encoding='utf-8') as f:
|
||
json.dump({"thread_count": thread_count}, f, indent=2, ensure_ascii=False)
|
||
logger.info("检测线程数配置保存成功")
|
||
|
||
# 保存到Redis(后台线程执行)
|
||
def save_to_redis():
|
||
if self.check_redis_connection():
|
||
self.redis_client.set('domain_tool:thread_count', thread_count)
|
||
logger.info("检测线程数配置已同步到Redis")
|
||
# 发布配置更新消息
|
||
self.redis_client.publish('domain_tool:config_update', 'thread_count')
|
||
|
||
# 提交到线程池执行
|
||
task = RedisTask(save_to_redis)
|
||
self.thread_pool.start(task)
|
||
except Exception as e:
|
||
logger.error(f"保存检测线程数配置失败: {e}")
|
||
|
||
def load_thread_count(self):
|
||
"""
|
||
从本地文件加载检测线程数
|
||
"""
|
||
try:
|
||
if os.path.exists('thread_count.json'):
|
||
with open('thread_count.json', 'r', encoding='utf-8') as f:
|
||
thread_config = json.load(f)
|
||
thread_count = thread_config.get('thread_count', '100')
|
||
self.thread_count_input.setText(thread_count)
|
||
logger.info("检测线程数配置加载成功")
|
||
else:
|
||
# 默认值:100
|
||
self.thread_count_input.setText('100')
|
||
self.save_thread_count()
|
||
logger.info("使用默认检测线程数配置")
|
||
except Exception as e:
|
||
logger.error(f"加载检测线程数配置失败: {e}")
|
||
# 使用默认值
|
||
self.thread_count_input.setText('100') |