derrickx 1 жил өмнө
parent
commit
da26e53dee
2 өөрчлөгдсөн 322 нэмэгдсэн , 316 устгасан
  1. 3 28
      main.py
  2. 319 288
      tools/utils.py

+ 3 - 28
main.py

@@ -7,7 +7,7 @@ import threading
 import time
 import time
 from datetime import datetime
 from datetime import datetime
 
 
-from PyQt5.QtCore import Qt, QUrl, QDateTime, pyqtSignal
+from PyQt5.QtCore import Qt, QUrl, QDateTime
 from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QFileDialog, QMessageBox, QDateTimeEdit, QPushButton
 from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QFileDialog, QMessageBox, QDateTimeEdit, QPushButton
 from PyQt5.QtGui import QDesktopServices
 from PyQt5.QtGui import QDesktopServices
 
 
@@ -67,28 +67,9 @@ def on_write_file_button_click():
     write_ticket_info("abcd", "1234556")
     write_ticket_info("abcd", "1234556")
 
 
 
 
-class WorkerThread(threading.Thread):
-    """用于执行下单逻辑的线程"""
-    signal = pyqtSignal(str)  # 定义一个信号,用于将信息传递回主线程
-
-    def __init__(self, thread_num, accounts_file, net_url):
-        super().__init__()
-        self.thread_num = thread_num
-        self.accounts_file = accounts_file
-        self.net_url = net_url
-
-    def run(self):
-        try:
-            run_threading_order(self.thread_num, self.accounts_file, self.net_url)
-            self.signal.emit("下单完成")  # 发送信号,通知主线程下单完成
-        except Exception as e:
-            self.signal.emit(f"下单失败: {e}")  # 发送信号,通知主线程下单失败
-
-
 class MainWindow(QMainWindow, Ui_menu):
 class MainWindow(QMainWindow, Ui_menu):
     def __init__(self, param1, param2):
     def __init__(self, param1, param2):
         super().__init__()
         super().__init__()
-        self.worker_thread = None
         self.setupUi(self)
         self.setupUi(self)
 
 
         # 使用传递的参数
         # 使用传递的参数
@@ -199,10 +180,8 @@ class MainWindow(QMainWindow, Ui_menu):
         if self.urlLineEdit:
         if self.urlLineEdit:
             net_url = self.urlLineEdit.text()
             net_url = self.urlLineEdit.text()
 
 
-        # 创建线程并启动
-        self.worker_thread = WorkerThread(thread_num, get_resource_path("accounts.txt"), net_url)
-        self.worker_thread.signal.connect(self.on_worker_thread_signal)
-        self.worker_thread.start()
+        # 下单
+        run_threading_order(thread_num, get_resource_path("accounts.txt"), net_url)
 
 
     # 登录账号
     # 登录账号
     def on_login_button_click(self):
     def on_login_button_click(self):
@@ -312,10 +291,6 @@ class MainWindow(QMainWindow, Ui_menu):
             # 例如,可以使用 `which redis-server` 命令
             # 例如,可以使用 `which redis-server` 命令
             print("当前操作系统不支持自动安装 Redis")
             print("当前操作系统不支持自动安装 Redis")
 
 
-    # 处理线程信号
-    def on_worker_thread_signal(self, message):
-        QMessageBox.information(self, "下单结果", message)
-
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
     app = QApplication(sys.argv)
     app = QApplication(sys.argv)

+ 319 - 288
tools/utils.py

@@ -1,302 +1,333 @@
-import ctypes
-import platform
-import subprocess
-import sys
+import datetime
+import json
 import os
 import os
+import random
+import sched
 import threading
 import threading
 import time
 import time
-from datetime import datetime
+import urllib
+import urllib.request
+from random import Random
+
+import requests
+import yaml
+
+from tools import loggerKit, redis_client
+
+
+# 随机生成token
+def get_token():
+    length_r = 32
+    token = ''
+    chars = '01'
+    length = len(chars) - 1
+    random = Random()
+    for i in range(length_r):
+        token += chars[random.randint(0, length)]
+    return token
+
+
+# 随机获取user_agent
+def get_random_browser():
+    user_agent = [
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/82.0.4085.133 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36 Edg/88.0.705.81",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36 Edg/86.0.622.69",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36 Edg/85.0.564.63",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.63",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 Edg/83.0.478.45",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/82.0.4086.0 Safari/537.36 Edg/82.0.459.1",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 Edg/81.0.416.72",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36 Edg/80.0.361.62",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36 Edg/79.0.309.71",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36 Edg/78.0.276.19",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Edg/77.0.235.27",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36 Edg/76.0.182.6",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 Edg/75.0.139.20",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36 Edg/74.1.96.24",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 Edg/73.0.139.7",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36 Edg/72.0.130.14",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 Edg/71.0.194.0",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edg/70.0.3538.102",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/10.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/9.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/8.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/7.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/6.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/5.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/4.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/3.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/2.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/1.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/0.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/99.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/98.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/97.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/96.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/95.1.2 Safari/605.1.15",
+        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
+    ]
+
+    return random.choice(user_agent)
+
+
+def get_proxy_ip(page, page_size):
+    response = requests.get(
+        f"https://proxy.webshare.io/api/v2/proxy/list/?mode=direct&page={page}&page_size={page_size}",
+        # headers={"Authorization": "Token pmdz7f3wdrwhwp88zwxmgtvn9dsusk0557vd16sp"}
+        headers={"Authorization": "Token 0pl6i8wbtukg4sdnf3b61wwzhi0h95pze47w5h3p"}
+    )
+
+    if response.status_code == 200:
+        content = json.loads(response.text)
+        # print(content["results"])
+        random_proxy = random.choice(content["results"])
+        print(random_proxy)
+        if random_proxy['valid']:
+            username = random_proxy['username']
+            password = random_proxy['password']
+            proxy_address_ip = random_proxy['proxy_address']
+            port = random_proxy['port']
+            # print(proxy_address_ip, port)
+            proxy = f'{username}:{password}@{proxy_address_ip}:{port}'
+
+            return proxy
+
+    else:
+        return None, None
+
+
+"""
+每天预先半小时存储好(早上8点半定时执行)
+"""
+
+
+def save_proxy_ip(page, page_size):
+    response = requests.get(
+        f"https://proxy.webshare.io/api/v2/proxy/list/?mode=direct&page={page}&page_size={page_size}",
+        headers={"Authorization": "Token 0pl6i8wbtukg4sdnf3b61wwzhi0h95pze47w5h3p"}
+    )
+
+    if response.status_code == 200:
+        data = json.loads(response.text)
+        # print(content['results'])
+        # total = page * page_size
+        print(f"代理总数:{data['count']}, 下一页:{data['next']}, 上一页:{data['previous']}")
+        i = page * page_size - 1
+        for r_proxy in data['results']:
+            if r_proxy['valid']:
+                username = r_proxy['username']
+                password = r_proxy['password']
+                proxy_address_ip = r_proxy['proxy_address']
+                port = r_proxy['port']
+                proxy = f'{username}:{password}@{proxy_address_ip}:{port}'
+
+                # 连接Redis并存储代理IP
+                redis_client.set(f'proxy_{str(i)}', proxy)
+                i = i - 1
+
+
+def save_all_proxy_ip(page_size, total_page):
+    for t in range(1, total_page):
+        loggerKit.info(f't:{t}')
+
+        url = f"https://proxy.webshare.io/api/v2/proxy/list/?mode=direct&page={t}&page_size={page_size}"
+        headers = {
+            "Authorization": "Token 0pl6i8wbtukg4sdnf3b61wwzhi0h95pze47w5h3p"
+        }
+
+        # 添加country查询参数来获取新加坡的IP
+        parameters = {
+            "country": "SG"
+        }
+        response = requests.get(url, headers=headers, params=parameters)
+        if response.status_code == 200:
+            data = json.loads(response.text)
+            loggerKit.info(f"代理总数:{data['count']}, 下一页:{data['next']}, 上一页:{data['previous']}")
+            i = t * page_size - 1
+            for r_proxy in data['results']:
+                if r_proxy['valid']:
+                    username = r_proxy['username']
+                    password = r_proxy['password']
+                    proxy_address_ip = r_proxy['proxy_address']
+                    port = r_proxy['port']
+                    proxy = f'{username}:{password}@{proxy_address_ip}:{port}'
+
+                    # 连接Redis并存储代理IP
+                    redis_client.set(f'proxy_{str(i)}', proxy)
+                    i = i - 1
+
+
+"""
+读取指定proxy_list文件
+"""
+
+
+def save_all_proxy_ip_v2():
+    i = 0
+    with open('proxy_list.txt', 'r') as proxies:
+        lines = [line.strip() for line in proxies]
+        for single_proxy in lines:
+            print(f'proxy:{single_proxy}')
+            # 存入redis
+            redis_client.set(f'proxy_{str(i)}', single_proxy, 24 * 60 * 60)
+            i = i + 1
+
+
+"""
+读取指定proxy_list文件
+"""
+
+
+def save_all_proxy_ip_v3(proxy_file_path):
+    i = 0
+    with open(proxy_file_path, 'r') as proxies:
+        lines = [line.strip() for line in proxies]
+        for single_proxy in lines:
+            print(f'proxy:{single_proxy}')
+            # 存入redis
+            redis_client.set(f'proxy_{str(i)}', single_proxy, 24 * 60 * 60)
+            i = i + 1
 
 
-from PyQt5.QtCore import Qt, QUrl, QDateTime
-from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QFileDialog, QMessageBox, QDateTimeEdit, QPushButton
-from PyQt5.QtGui import QDesktopServices
 
 
-from app import login_account, run_threading_order, run_daily_job, run_manual_job, cancel_manual_job, stop_order_job, \
-    write_ticket_info
-from litter_helper import Ui_menu  # 确保这个导入路径是正确的
-from tools.utils import save_all_proxy_ip_v3
+def get_proxy_poc():
+    response = requests.get(
+        "https://proxy.webshare.io/api/v2/proxy/list/?page=1&page_size=10",
+        headers={"Authorization": "Token 0pl6i8wbtukg4sdnf3b61wwzhi0h95pze47w5h3p"}
+    )
 
 
-import winreg
+    if response.status_code == 200:
+        data = json.loads(response.text)
+        print(f"{json.loads(data)}")
 
 
-from pathlib import Path
 
 
-# 定义 Redis 安装程序路径
-REDIS_INSTALLER_PATH = "Redis-x64-5.0.14.1.msi"  # 替换为实际的安装程序路径
+def get_random_proxy_at_redis(total):
+    random_index = random.randint(0, total - 1)
+    # 连接Redis并获取代理IP
+    single_proxy = redis_client.get(f'proxy_{str(random_index)}')
+
+    return single_proxy, random_index
 
 
 
 
-class ClickableLabel(QLabel):
-    def __init__(self, parent=None, file_path=None):
-        super().__init__(parent)
+def process_account(account_number):
+    print(f"Processing account {account_number}")
+
+
+def task_running(num_account):
+    threads = []
+    for account_number in range(num_account):
+        thread = threading.Thread(target=process_account, args=(account_number,))
+        threads.append(thread)
+        thread.start()
+
+    for thread in threads:
+        thread.join()
+
+
+class Singleton(type):
+    _instances = {}
+
+    def __call__(cls, *args, **kwargs):
+        if cls not in cls._instances:
+            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
+        return cls._instances[cls]
+
+
+class FileWriter(metaclass=Singleton):
+
+    def __init__(self, file_path):
+        if not isinstance(file_path, str):
+            raise TypeError("file_path should be a string")
         self.file_path = file_path
         self.file_path = file_path
+        if not os.path.exists(self.file_path):
+            with open(self.file_path, 'a') as f:
+                print(f'File {self.file_path} created successfully!')
 
 
-    def mousePressEvent(self, event):
-        if event.button() == Qt.LeftButton:
-            self.emit_click_event()
-
-    def emit_click_event(self):
-        if self.file_path:
-            self.parent().on_label_click(self.file_path)
-
-
-def get_resource_path(relative_path):
-    """获取资源文件的绝对路径"""
-    if getattr(sys, 'frozen', False):  # 是否为PyInstaller打包的exe文件
-        # 返回exe文件所在的绝对路径
-        base_path = os.path.dirname(sys.executable)
-    else:  # 在开发环境下运行
-        # 返回脚本文件所在的绝对路径
-        base_path = os.path.dirname(__file__)
-    return os.path.join(base_path, relative_path)
-
-
-def get_dir_path(relative_path):
-    """获取资源文件路径"""
-    base_path = getattr(sys, '_MEIPASS', str(Path(__file__).parent.absolute()))
-    return Path(base_path, relative_path)
-
-
-# 停止定时任务
-def on_stop_time_button_click():
-    print(f"停止定时任务: {time.time()}")
-    cancel_manual_job()
-
-
-# 写入文件
-def on_write_file_button_click():
-    print(f"写入文件:{time.time()}")
-    write_ticket_info("abcd", "1234556")
-
-
-class MainWindow(QMainWindow, Ui_menu):
-    def __init__(self, param1, param2):
-        super().__init__()
-        self.setupUi(self)
-
-        # 使用传递的参数
-        self.param1 = param1
-        self.param2 = param2
-
-        # 设置标签的文本为传递的参数
-        # self.label.setText(f"参数1: {self.param1}, 参数2: {self.param2}")
-        self.concurrencyLineEdit.setText("1")
-        self.urlLineEdit.setText("https://t.livepocket.jp/e/l3im7")
-
-        # 登录账号
-        self.loginPushButton.clicked.connect(self.on_login_button_click)
-
-        # 开始下单
-        self.startPushButton.clicked.connect(self.on_start_button_click)
-
-        # 停止下单
-        self.stopOrderPushButton.clicked.connect(self.on_stop_button_click)
-
-        # 定时开始
-        self.startTimePushButton.clicked.connect(self.on_start_time_button_click)
-
-        # 停止定时任务
-        self.stopTimePushButton.clicked.connect(on_stop_time_button_click)
-
-        # 写入文件
-        # self.writeFilePushButton.clicked.connect(on_write_file_button_click)
-
-        # 编辑账号
-        # 获取 QLabel 控件并替换为 ClickableLabel
-        self.accountsLabel = self.findChild(QLabel, "accountsLabel")
-        if self.accountsLabel:
-            # 替换为 ClickableLabel
-            self.clickableAccountsLabel = ClickableLabel(self, file_path=get_resource_path("accounts.txt"))
-            self.clickableAccountsLabel.setObjectName("accountsLabel")
-            self.clickableAccountsLabel.setText("编辑账号")
-            self.clickableAccountsLabel.setGeometry(self.accountsLabel.geometry())
-            self.clickableAccountsLabel.show()
-            self.accountsLabel.deleteLater()  # 删除原来的 QLabel 控件
-
-        # 编辑IP代理池
-        # 获取 QLabel 控件并替换为 ClickableLabel
-        self.ipPoolLabel = self.findChild(QLabel, "ipPoolLabel")
-        if self.ipPoolLabel:
-            # 替换为 ClickableLabel
-            self.clickableIpPoolLabel = ClickableLabel(self, file_path=get_resource_path("proxy_list.txt"))
-            self.clickableIpPoolLabel.setObjectName("ipPoolLabel")
-            self.clickableIpPoolLabel.setText("编辑代理池")
-            self.clickableIpPoolLabel.setGeometry(self.ipPoolLabel.geometry())
-            self.clickableIpPoolLabel.show()
-            self.ipPoolLabel.deleteLater()  # 删除原来的 QLabel 控件
-
-        # 获取 QDateTimeEdit 控件并设置显示格式
-        self.startDateTimeEdit = self.findChild(QDateTimeEdit, "startDateTimeEdit")
-        if self.startDateTimeEdit:
-            self.startDateTimeEdit.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
-            # 设置当前时间
-            self.startDateTimeEdit.setDateTime(QDateTime.currentDateTime())
-
-        # 获取 QDateTimeEdit 控件并设置显示格式
-        self.endDateTimeEdit = self.findChild(QDateTimeEdit, "endDateTimeEdit")
-        if self.endDateTimeEdit:
-            self.endDateTimeEdit.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
-            # 设置当前时间
-            self.endDateTimeEdit.setDateTime(QDateTime.currentDateTime())
-
-        # 连接 watchPushButton 点击事件到槽函数
-        self.watchPushButton = self.findChild(QPushButton, "watchPushButton")
-        if self.watchPushButton:
-            self.watchPushButton.clicked.connect(self.on_watch_button_click)
-
-        # 检查 Redis 是否安装
-        self.check_redis_installation()
-
-    def on_label_click(self, file_path):
-        if os.path.exists(file_path):
-            try:
-                QDesktopServices.openUrl(QUrl.fromLocalFile(file_path))
-            except Exception as e:
-                QMessageBox.critical(self, "Error", f"无法打开文件: {e}")
-        else:
-            QMessageBox.critical(self, "Error", f"文件不存在: {file_path}")
-
-    def on_start_button_click(self):
-        print(f"开始下单!")
-        # 在按钮点击时执行的操作
-        # print(f"按钮被点击了!参数1: {self.param1}, 参数2: {self.param2}")
-
-        # 获取 QDateTimeEdit 控件的值
-        if self.startDateTimeEdit:
-            date_time_value = self.startDateTimeEdit.dateTime()
-            # print(f"选中的日期和时间: {date_time_value.toString('yyyy-MM-dd HH:mm:ss')}")
-
-        # 获取 QDateTimeEdit 控件的值
-        if self.endDateTimeEdit:
-            date_time_value = self.endDateTimeEdit.dateTime()
-            # print(f"选中的日期和时间: {date_time_value.toString('yyyy-MM-dd HH:mm:ss')}")
-
-        # 获取并发数
-        thread_num = 1
-        if self.concurrencyLineEdit:
-            # print(f"并发数为: {self.concurrencyLineEdit.text()}")
-            thread_num = self.concurrencyLineEdit.text()
-
-        # url
-        net_url = None
-        if self.urlLineEdit:
-            net_url = self.urlLineEdit.text()
-
-        # 下单
-        run_threading_order(thread_num, get_resource_path("accounts.txt"), net_url)
-
-    # 登录账号
-    def on_login_button_click(self):
-        print(f"登录账号! {self.urlLineEdit.text()}")
-
-        thread_num = 1
-        if self.concurrencyLineEdit.text():
-            thread_num = self.concurrencyLineEdit.text()
-
-        pocket_url = None
-        if self.urlLineEdit.text():
-            pocket_url = self.urlLineEdit.text()
-            save_all_proxy_ip_v3(get_resource_path("proxy_list.txt"))
-            login_account(thread_num, get_resource_path("accounts.txt"), pocket_url)
-        else:
-            QMessageBox.warning(self, '警告', '请输入URL')
-            return
-
-    # 定时开始
-    def on_start_time_button_click(self):
-        print(f"定时开始:{time.time()}")
-
-        net_url = None
-        if self.urlLineEdit:
-            net_url = self.urlLineEdit.text()
-
-            start_time = self.startDateTimeEdit.text()
-            print(f"start_time:{start_time}")
-
-            # 使用datetime模块解析时间字符串
-            dt = datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S')
-
-            # 提取出时、分、秒
-            hour = dt.hour
-            minute = dt.minute
-            second = dt.second
-
-            print(f"Hour: {hour}, Minute: {minute}, Second: {second}")
-
-            # 获取并发数
-            thread_num = self.concurrencyLineEdit.text()
-
-            # 创建一个新的线程来运行 run_manual_job 函数
-            thread = threading.Thread(target=run_manual_job, args=(hour, minute, thread_num, net_url))
-            thread.start()
-        else:
-            QMessageBox.warning(self, '警告', '请输入URL')
-            return
-
-    # 终止下单
-    def on_stop_button_click(self):
-        print(f"终止下单! 目标网址: {self.urlLineEdit.text()}")
-        stop_order_job()
-
-    def edit_accounts(self):
-        # 编辑账号
-        print(f"编辑账号: {self.urlLineEdit.text()}")
-
-    # 查看结果
-    def on_watch_button_click(self):
-        # 获取项目当前路径
-        current_path = sys.path[0]
-        # 拼接文件夹路径
-        folder_path = get_dir_path("results")  # 假设文件夹名为 "results"
-
-        # 判断文件夹是否存在,不存在则创建
-        if not folder_path.exists():
-            try:
-                folder_path.mkdir(parents=True, exist_ok=True)
-                print(f"文件夹 {folder_path} 已创建")
-            except Exception as e:
-                QMessageBox.critical(self, "Error", f"无法创建文件夹: {e}")
-                return
-
-        # 打开文件夹
-        folder_path = get_resource_path("results")  # 假设文件夹名为 "results"
+    def write_to_file(self, content):
         try:
         try:
-            # 使用 QDesktopServices.openUrl 打开文件夹
-            QDesktopServices.openUrl(QUrl.fromLocalFile(folder_path))
+            with open(self.file_path, 'a') as file:
+                file.write(content)
         except Exception as e:
         except Exception as e:
-            QMessageBox.critical(self, "Error", f"无法打开文件夹: {e}")
-
-    # 检查 Redis 是否安装
-    def check_redis_installation(self):
-        # 检查操作系统
-        system = platform.system()
-
-        if system == "Windows":
-            # 检查 Redis 服务是否正在运行
-            try:
-                key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Services\Redis")
-                winreg.CloseKey(key)
-                print("Redis 服务已安装并正在运行")
-                return
-            except FileNotFoundError as ex:
-                print(f"Redis 服务未安装或未运行")
-
-            # 如果 Redis 服务未安装,则启动安装程序
-            if REDIS_INSTALLER_PATH:
-                try:
-                    subprocess.run([REDIS_INSTALLER_PATH], shell=True)
-                    print("Redis 安装程序已启动")
-                except Exception as e:
-                    QMessageBox.critical(self, "Error", f"无法启动 Redis 安装程序: {e}")
-        else:
-            # 在其他操作系统上,可以使用不同的方法检查 Redis 是否安装
-            # 例如,可以使用 `which redis-server` 命令
-            print("当前操作系统不支持自动安装 Redis")
-
-
-if __name__ == "__main__":
-    app = QApplication(sys.argv)
-
-    # 创建窗口并传递参数
-    window = MainWindow("Hello", "World")
-    window.show()
-
-    sys.exit(app.exec_())
+            print(f"An error occurred: {e}")
+
+
+def run_daily_task(hour, minute, page_size, total):
+    # 获取当前日期和时间
+    now = datetime.datetime.now()
+    # 计算下次运行时间
+    run_time = datetime.datetime(now.year, now.month, now.day, hour, minute)
+    if run_time < now:
+        # 如果运行时间小于当前时间,则在明天的相应时间运行任务
+        run_time = run_time + datetime.timedelta(days=1)
+    # 计算等待时间
+    wait_time = (run_time - now).total_seconds()
+    # 创建定时器对象
+    scheduler = sched.scheduler(time.time, time.sleep)
+    # 添加定时任务
+    scheduler.enter(wait_time, 1, save_all_proxy_ip, (page_size, total))
+    # 启动定时器
+    scheduler.run()
+
+
+def get_external_ip():
+    # 获取公网出口IP地址
+    url = "https://api.ipify.org/?format=json"  # 定义查询 API 的 URL
+    try:
+        response = urllib.request.urlopen(url)  # 向查询 API 发送请求并获取响应
+        data = response.read()  # 读取响应中的数据(字节流)
+        data = data.decode("utf-8")  # 将响应数据从字节流转换为字符串
+        data = json.loads(data)  # 将响应数据解析为 JSON 格式
+        public_ip = data["ip"]  # 从 JSON 数据中提取公网IP地址
+        loggerKit.info(f"公网出口IP地址:{public_ip}")
+        return public_ip
+    except Exception as ex:
+        err_msg = "无法获取公网出口IP地址"  # 查询失败时输出提示信息
+        loggerKit.error(f'err_msg: {err_msg}')
+
+
+def redis_del_poc():
+    redis_client.delete('proxy_370')