import sys from stringprep import in_table_c11 from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QPushButton, QTabWidget, \ QLabel, QLineEdit, QTextEdit, QFormLayout, QMessageBox, QTreeWidget, QTreeWidgetItem, QDialog, \ QVBoxLayout as QDialogVBoxLayout, QLineEdit as QDialogLineEdit, QDialogButtonBox, QCheckBox, QComboBox from PyQt5.QtCore import Qt import requests as req import time, random, numpy as np import threading import asyncio import json from PyQt5.QtWidgets import QFileDialog from PyQt5.QtCore import pyqtSignal, QObject, pyqtSlot import sqlite3 from CollectibleDialog import CollectibleDialog from AppearanceDialog import AppearanceDialog from TypeDialog import TypeDialog from QualityDialog import QualityDialog from CategoryDialog import CategoryDialog from SelectLogDialog import SelectLogDialog from InitDB import InitDB from BUFFAPI import BUFFAPI from BUFFXP import BUFFXP from datetime import datetime from apscheduler.schedulers.blocking import BlockingScheduler import datetime import time from apscheduler.schedulers.background import BackgroundScheduler import logging from logging.handlers import TimedRotatingFileHandler from datetime import datetime, timedelta import os # 禁用 requests 的日志 logging.getLogger("requests").setLevel(logging.CRITICAL) # 禁用 urllib3 的日志(requests 依赖 urllib3) logging.getLogger("urllib3").setLevel(logging.CRITICAL) # class CustomTimedRotatingFileHandler(TimedRotatingFileHandler): # def doRollover(self): # # 获取当前时间 # current_time = datetime.now() - timedelta(days=1) # # 获取当前日期 # current_date = current_time.strftime('%Y-%m-%d') # # 获取当前日志文件名 # base_filename = os.path.splitext(self.baseFilename)[0] # extension = os.path.splitext(self.baseFilename)[1] # # 构建新的日志文件名 # new_filename = f"{base_filename}_{current_date}{extension}" # # 如果当前日志文件存在,则重命名 # if os.path.exists(self.baseFilename): # os.rename(self.baseFilename, new_filename) # # 调用父类的doRollover方法 # super().doRollover() def detail_namer(default_name): # 计算前一天的时间 current_time = datetime.now() - timedelta(days=1) current_date = current_time.strftime('%Y-%m-%d') log_file = f'详细日志log/详细日志.{current_date}.txt' # 默认情况下,轮转后的文件名会添加日期后缀,这里去掉后缀 return os.path.join(os.path.dirname(default_name), os.path.basename(log_file)) def xp_namer(default_name): # 计算前一天的时间 current_time = datetime.now() - timedelta(days=1) current_date = current_time.strftime('%Y-%m-%d') log_file = f'选品日志log/选品日志.{current_date}.txt' # 默认情况下,轮转后的文件名会添加日期后缀,这里去掉后缀 return os.path.join(os.path.dirname(default_name), os.path.basename(log_file)) def sh_namer(default_name): # 计算前一天的时间 current_time = datetime.now() - timedelta(days=1) current_date = current_time.strftime('%Y-%m-%d') log_file = f'扫货日志log/扫货日志.{current_date}.txt' # 默认情况下,轮转后的文件名会添加日期后缀,这里去掉后缀 return os.path.join(os.path.dirname(default_name), os.path.basename(log_file)) def gm_namer(default_name): # 计算前一天的时间 current_time = datetime.now() - timedelta(days=1) current_date = current_time.strftime('%Y-%m-%d') log_file = f'购买日志log/购买日志.{current_date}.txt' # 默认情况下,轮转后的文件名会添加日期后缀,这里去掉后缀 return os.path.join(os.path.dirname(default_name), os.path.basename(log_file)) class MainWindow(QMainWindow): # 定义一个信号,用于传递日志信息 log_added = pyqtSignal(str, str, str, str, str, str, str, str) def namer(default_name,file_path,file_name): # 计算前一天的时间 current_time = datetime.now() - timedelta(days=1) current_date = current_time.strftime('%Y-%m-%d') log_file = f'{file_path}/{file_name}.{current_date}.txt' # 默认情况下,轮转后的文件名会添加日期后缀,这里去掉后缀 return os.path.join(os.path.dirname(default_name), os.path.basename(log_file)) def __init__(self): super().__init__() # 设置一个选品已启动的标志 self.xp_started = False # 设置一个选品停止的flag self.stop_selecting_flag = False # 向BUFF选品日志列表中写内容的槽函数 self.log_added.connect(self._add_select_log) # 连接信号到槽函数 # 初始化数据库 InitDB.init_db() self.xp_goodsurl = 'https://buff.163.com/api/market/goods' self.xp_getPaintwearChoicesUrl = 'https://buff.163.com/api/market/goods/info?goods_id=' self.xp_getPriceUrl = 'https://buff.163.com/api/market/goods/sell_order?game=csgo&page_num=1&sort_by=price.asc&goods_id=' self.xp_my_headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", "Host": "buff.163.com", "Referer": "https://buff.163.com/market/?game=csgo", "X-Requested-With": "XMLHttpRequest" } # todo 为了测试 page_size = 1 #self.sh_getToBuyUrl = 'https://buff.163.com/api/market/goods/sell_order?game=csgo&allow_epay=1&allow_tradable_cooldown=1&page_num=1&page_size=1&sort_by=price.asc&goods_id=' self.sh_buyGoodsUrl = 'https://buff.163.com/api/market/goods/buy' self.sh_getToBuyUrl = 'https://buff.163.com/api/market/goods/sell_order?game=csgo&allow_epay=1&allow_tradable_cooldown=1&page_num=1&page_size=95&sort_by=price.asc&goods_id=' self.sh_fbjUrl= 'https://buff.163.com/api/market/bill_order/ask_seller_to_send_offer' self.sh_my_headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", "Host": "buff.163.com", "Referer": "https://buff.163.com/market/?game=csgo", "X-Requested-With": "XMLHttpRequest" } # 配置日志记录器 self.logger_cmd = logging.getLogger('logger_cmd') self.logger_cmd.setLevel(logging.DEBUG) # 配置控制台处理器和格式器 self.console_handler = logging.StreamHandler() self.console_handler.setLevel(logging.DEBUG) self.console_formatter = logging.Formatter('[%(asctime)s] %(message)s') self.console_handler.setFormatter(self.console_formatter) # 将处理器添加到记录器中 self.logger_cmd.addHandler(self.console_handler) self.logger_cmd.propagate = False # 创建一个选品logger self.detail_logger = logging.getLogger('detailLogger') self.detail_logger.setLevel(logging.DEBUG) # 设置日志级别 # 创建一个handler,用于写入文件,并根据时间自动轮换日志文件 detail_handler = TimedRotatingFileHandler('详细日志log/详细日志.txt', when='midnight', interval=1, backupCount=30,encoding='utf-8') detail_handler.setFormatter(logging.Formatter('%(asctime)s - %(message)s')) detail_handler.namer = detail_namer # 添加handler到logger self.detail_logger.addHandler(detail_handler) self.detail_logger.propagate = False # 创建一个选品logger self.xp_logger = logging.getLogger('xpLogger') self.xp_logger.setLevel(logging.DEBUG) # 设置日志级别 # 创建一个handler,用于写入文件,并根据时间自动轮换日志文件 xp_handler = TimedRotatingFileHandler('选品日志log/选品日志.txt', when='midnight', interval=1, backupCount=30,encoding='utf-8') xp_handler.setFormatter(logging.Formatter('%(asctime)s - %(message)s')) xp_handler.namer = xp_namer # 添加handler到logger self.xp_logger.addHandler(xp_handler) self.xp_logger.propagate = False # 创建扫货logger self.sh_logger = logging.getLogger('shLogger') self.sh_logger.setLevel(logging.DEBUG) # 设置日志级别 # 创建一个handler,用于写入文件,并根据时间自动轮换日志文件 sh_handler = TimedRotatingFileHandler('扫货日志log/扫货日志.txt', when='midnight', interval=1, backupCount=30,encoding='utf-8') sh_handler.setFormatter(logging.Formatter('%(asctime)s - %(message)s')) sh_handler.namer = sh_namer # 添加handler到logger self.sh_logger.addHandler(sh_handler) self.sh_logger.propagate = False # 创建购买logger self.gm_logger = logging.getLogger('gmLogger') self.gm_logger.setLevel(logging.DEBUG) # 设置日志级别 # 创建一个handler,用于写入文件,并根据时间自动轮换日志文件 gm_handler = TimedRotatingFileHandler('购买日志log/购买日志.txt', when='midnight', interval=1, backupCount=30,encoding='utf-8') gm_handler.setFormatter(logging.Formatter('%(asctime)s - %(message)s')) gm_handler.namer = gm_namer # 添加handler到logger self.gm_logger.addHandler(gm_handler) self.gm_logger.propagate = False # 初始化 phone_edit_map # self.setup_phone_edit_map() # 设置窗口标题和大小 self.setWindowTitle("BUFF选品扫货") self.setGeometry(100, 100, 200, 200) # 创建一个垂直布局 layout = QVBoxLayout() layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保垂直布局内容靠左对齐 # 创建一个水平布局来放置按钮 button_layout = QHBoxLayout() button_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保水平布局内容靠左对齐 # 创建两个按钮 self.button1 = QPushButton("选品") # 增加停止选品和停止扫货按钮 self.stop_select_button = QPushButton("停止选品") button_layout.addWidget(self.button1) button_layout.addWidget(self.stop_select_button) # 连接按钮的点击事件 self.button1.clicked.connect(self.show_selected_phone_number) self.stop_select_button.clicked.connect(self.stop_selecting) # 新增连接停止选品按钮的点击事件 self.button_sh = QPushButton("扫货") button_layout.addWidget(self.button_sh) self.button_sh.clicked.connect(self.beginSH) self.button_stop_sh = QPushButton("停止扫货") button_layout.addWidget(self.button_stop_sh) self.button_stop_sh.clicked.connect(self.stopSH) # 将水平布局添加到垂直布局中 layout.addLayout(button_layout) # 创建一个Tab容器 self.tab_widget = QTabWidget() # 向Tab容器中添加10个标签页 for i in range(1, 11): # 修改循环范围以添加第11个标签页 tab = QWidget() tab_layout = QVBoxLayout() tab_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保标签页布局内容靠左对齐 if i == 1: form_layout = self.create_account_info_form("选品") tab_layout.addLayout(form_layout) elif i == 2: tree_layout = self.create_category_info_form() tab_layout.addLayout(tree_layout) elif i == 3: quality_layout = self.create_quality_info_form() tab_layout.addLayout(quality_layout) elif i == 4: type_layout = self.create_type_info_form() tab_layout.addLayout(type_layout) elif i == 5: appearance_layout = self.create_appearance_info_form() tab_layout.addLayout(appearance_layout) elif i == 6: collectible_layout = self.create_collectible_info_form() tab_layout.addLayout(collectible_layout) elif i == 7: config_layout = self.create_config_info_form("选品") tab_layout.addLayout(config_layout) elif i == 8: select_log_layout = self.create_select_log_info_form() # 添加BUFF选品日志标签页 tab_layout.addLayout(select_log_layout) elif i == 9: shzhtab_layout = self.setup_shzhtab() tab_layout.addLayout(shzhtab_layout) elif i == 10: shpztab_layout = self.setup_shpztab() tab_layout.addLayout(shpztab_layout) else: label = QLabel(f"这是标签页 {i}") tab_layout.addWidget(label) tab.setLayout(tab_layout) if i == 1: self.tab_widget.addTab(tab, "选品账号") elif i == 2: self.tab_widget.addTab(tab, "品类") elif i == 3: self.tab_widget.addTab(tab, "品质") elif i == 4: self.tab_widget.addTab(tab, "TYPE") elif i == 5: self.tab_widget.addTab(tab, "外观") elif i == 6: self.tab_widget.addTab(tab, "收藏品") elif i == 7: self.tab_widget.addTab(tab, "选品配置") elif i == 8: self.tab_widget.addTab(tab, "选品日志") elif i == 9: self.tab_widget.addTab(tab, "扫货账号") elif i == 10: self.tab_widget.addTab(tab, "扫货配置") # 将Tab容器添加到布局中 layout.addWidget(self.tab_widget) # 创建一个中心部件,并将布局设置为中心部件的布局 container = QWidget() container.setLayout(layout) # 将中心部件设置为主窗口的中心部件 self.setCentralWidget(container) # 自动开启选品 # 获取定时时间 cron_time = self.cron_time_label_edit.text() scheduler = BackgroundScheduler() # 设置每天早上9点执行任务(使用cron表达式) #cron_time 的格式为10:11,11:12,12:13 #遍历cron_time,先要判断cron_time是否为空 if cron_time: cron_times = cron_time.split(',') for cron_time_item in cron_times: if cron_time_item: #如果cron_time_item中没有:则pass if ':' in cron_time_item: self.detail_logger.debug(f'启动选品每天{cron_time_item}定时任务...') scheduler.add_job(self.show_selected_phone_number, 'cron', hour=int(cron_time_item.split(':')[0]), minute=int(cron_time_item.split(':')[1]), second=0) #scheduler.add_job(self.show_selected_phone_number, 'cron', hour=int(cron_time), minute=8, second=30) try: # print(f'启动选品每天{cron_time}定时任务...') scheduler.start() except (KeyboardInterrupt, SystemExit): self.detail_logger.debug('已取消选品每天{cron_time}定时任务') # 选品按钮绑定的方法 def show_selected_phone_number(self): if self.xp_started : self.detail_logger.debug('选品已开启,本次尝试自动关闭') return # 查询检索选品入参 if not BUFFXP.checkBuffXPParams(self): self.detail_logger.debug('选品入参异常,请重新调整后再选品') return try: thread_searchGoods = threading.Thread(target=self.firstSelectGoods) thread_searchGoods.start() except Exception as e: self.detail_logger.debug(f"选品进程异常: {e}") # 创建一个方法,将数据库中select_logs数据保存到本地的xpback文件中,文件名称XPRZ_YYYYMMDDHHMMDD.json # 选品逻辑 def firstSelectGoods(self): self.xp_started = True self.logger_cmd.debug('开始选品') self.detail_logger.debug('开始选品') # 先停扫货,设置扫货停止标志为True,选品之前先暂停扫货 self.logger_cmd.debug(f'暂停扫货进程') self.detail_logger.debug(f'暂停扫货进程....') self.stop_shopping_flag = True time.sleep(float(self.shpz_pause_time_edit.text())) self.logger_cmd.debug(f'扫货进程暂停完成,开启选品') self.detail_logger.debug(f'扫货进程暂停完成,开启选品') # 设置选品停止标志为False self.stop_selecting_flag = False # 扫货、停止扫货和选品按钮 按钮不可点击 self.button_sh.setEnabled(False) self.button_stop_sh.setEnabled(False) self.button1.setEnabled(False) # 将已选品的记录保存到文件中,用于后续的选品记录,然后情况选品记录的表 # 保存选品日志到本地文件 SelectLogDialog.export_selected_logs_tolocal(self) # 删除所有选品日志信息 SelectLogDialog.delete_all_select_logs(self) # 删除所有的日志的记录self.select_log_tree_widget self.select_log_tree_widget.clear() # 已经选品的数量 self.searchedGoodsNum = 0 # 已经选品成功的数量 self.search_success_count = 0 # 获取商品选取API的入参list BUFFXP.get_goods_param_list(self) # 设定暂停起始时间 self.last_xp_request_time = 0 try: xiesi_tag = 0 # 无限循环 改成 只循环两次 while xiesi_tag < 2: xiesi_tag += 1 # 待判断的商品列表 self.need_check_goods_list = [] # 选品cookie的状态池子 self.cookie_status = {} # self.cookie_text 中有多个cookie的值,用换行分开的 self.cookie_text_list = self.cookie_text.split('\n') #判断退出条件 if self.stop_selecting_flag: self.detail_logger.debug('停止选品') self.logger_cmd.debug('停止选品') return # 判断是否达到了成功的数量限制,如果达到,则跳出循环 if self.stop_condition == '按照成功数量': self.detail_logger.debug(f'按照成功数量,设定的成功数量为:{self.success_count},当前检索已成功的数量为:{self.search_success_count}') if int(self.success_count) <= int(self.search_success_count): return else: # 按照选品数量来判断是否要停止 self.detail_logger.debug(f'按照选品数量,设定的选品数量为:{self.scan_count},当前检索的选品数量为:{self.searchedGoodsNum}') if int(self.scan_count) <= int(self.searchedGoodsNum): return # 从1开始遍历到self.max_page for page in range(1, int(self.max_page)+1): try: #判断退出条件 if self.stop_selecting_flag: self.detail_logger.debug('停止选品') self.logger_cmd.debug('停止选品') return self.detail_logger.debug(f"开始请求第{page}/{self.max_page}页商品数据") # 开始时间为当前时间 # 暂停时间 if page != 1: self.detail_logger.debug(f"暂停 {float(self.pause_time):.2f} seconds 再进行检索商品数据..") time.sleep(float(self.pause_time)) # 检索数据是否循环的条件 self.search_goods_stop_flag = True # 404异常次数 self.search_goods_404_times = 0 # 请求商品数据,如果返回的code为'System Error',则继续用当前的cookie请求,连续3次,则跳出循环。如果返回的code为'Captcha Validate Required',则用下一个cookie请求,cookie连续的3次被标记为超时,则此cookie标志为无效,当所有的cookie都标记为无效时,退出程序 temp_cookie_i = 0 temp_cookie_length = len(self.cookie_text_list) while self.search_goods_stop_flag: # 判断退出条件 if self.stop_selecting_flag: self.detail_logger.debug('停止选品') self.logger_cmd.debug('停止选品') return # 遍历self.cookie_status中元素,self.cookie_text为主键的值,如果次数为3,则删除self.cookie_text中这个cookie for key, value in self.cookie_status.items(): if value >= int(self.needed_msg_check_try_times): # self.cookie_text_list 存在 key if key in self.cookie_text_list: # 删除self.cookie_text_list中key对应的值 self.cookie_text_list.remove(key) self.detail_logger.debug(f"cookie: {key},超时异常的次数{value},删除") # 当self.cookie_text_list长度为0时,则退出程序 if len(self.cookie_text_list) == 0: self.detail_logger.debug('所有cookie都不可用,退出程序') return # 更新选品cookie ,每一次请求轮流取其中一个 self.temp_cookie_text = self.cookie_text_list[(page+temp_cookie_i-1) % len(self.cookie_text_list)] self.xp_my_headers.update({ 'Cookie': self.temp_cookie_text }) self.search_goods_param_list['page_num'] = page self.logger_cmd.debug(f'正在使用{self.temp_cookie_text}') self.logger_cmd.debug(f'请求第{page}/{self.max_page}页商品数据') search_goods_res = req.get(url=self.xp_goodsurl, headers=self.xp_my_headers,params=self.search_goods_param_list) self.detail_logger.debug(f"遍历商品接口请求返回报文中的CODE:{search_goods_res.json()['code']} ,遍历商品接口请求返回报文:{search_goods_res.text.strip()[:50]}") # 返回成功,则跳出循环 if search_goods_res.json()['code'] == 'OK': # 重置404异常次数 self.search_goods_404_times = 0 # 请求成功了,退出循环 self.search_goods_stop_flag = False # 将这个cookie对应的短信验证的次数清0 self.cookie_status[self.temp_cookie_text] = 0 # 将遍历结果的商品数据记录保存 data = search_goods_res.json()['data'] self.need_check_goods_list.extend(data['items']) break # 返回404异常,继续用这个cookie请求,超过了次数则退出 elif search_goods_res.json()['code'] == 'System Error' : # 404异常次数加1 self.search_goods_404_times += 1 # 将这个cookie对应的短信验证的次数清0 self.cookie_status[self.temp_cookie_text] = 0 if self.search_goods_404_times >= temp_cookie_length: self.detail_logger.debug(f"有效的cookie都提示404异常,异常次数:{str(self.search_goods_404_times)}, 跳出循环继续下一个页面检索") break else: temp_cookie_i += 1 # 404异常时候,暂停一会再执行 self.logger_cmd.debug(f'访问频繁,等待{float(self.pause_time) + 30}秒') time.sleep(float(self.pause_time) + 30) continue # 返回需要短信验证 elif search_goods_res.json()['code'] == 'Captcha Validate Required' or search_goods_res.json()['code'] == 'Login Required' or search_goods_res.json()['code'] == 'Action Forbidden': if search_goods_res.json()['code'] == 'Login Required': self.logger_cmd.debug(f'需要登陆') # time.sleep(float(self.needed_msg_check_pause_time)) self.search_goods_404_times = 0 #判断self.cookie_status是否有key为self.temp_cookie_text if self.temp_cookie_text not in self.cookie_status: if search_goods_res.json()['code'] == 'Captcha Validate Required': self.logger_cmd.debug(f'需要短信验证,次数1,等待{float(self.needed_msg_check_pause_time)}秒!') self.cookie_status[self.temp_cookie_text] = 1 else: if search_goods_res.json()['code'] == 'Captcha Validate Required': self.logger_cmd.debug(f'需要短信验证,次数{int(self.cookie_status[self.temp_cookie_text]) + 1},等待{float(self.needed_msg_check_pause_time)}秒!') self.cookie_status[self.temp_cookie_text] = int(self.cookie_status[self.temp_cookie_text]) + 1 time.sleep(float(self.needed_msg_check_pause_time)) # 从self.cookie_text_list获取下一个cookie,因为此cookie需要从list中移除,所以自动就是下一个,如果没有从list中移除,需要+1 if self.cookie_status[self.temp_cookie_text] >= int(self.needed_msg_check_try_times): self.logger_cmd.debug(f'异常{int(self.needed_msg_check_try_times)}次,暂停!') temp_cookie_i += 0 else: temp_cookie_i += 1 else: # 其他异常的情况,直接跳出 # 重置404异常次数 self.search_goods_404_times = 0 # 请求成功了,退出循环 self.search_goods_stop_flag = False # 将这个cookie对应的短信验证的次数清0 self.cookie_status[self.temp_cookie_text] = 0 break except Exception as e: self.detail_logger.debug(f"检索商品数据异常: {e}") finally: pass # 根据id去重 # 使用字典去重 unique_goods_dict = {item['id']: item for item in self.need_check_goods_list} # 将字典转换回列表 self.need_check_goods_list = list(unique_goods_dict.values()) # 遍历self.xp_delete_ids,用#号分割后,将self.need_check_goods_list中存在的这些id去除 xp_delete_ids_set = set(self.xp_delete_ids.split('#')) self.need_check_goods_list = [item for item in self.need_check_goods_list if str(item['id']) not in xp_delete_ids_set] # 根据最低销售量,将不满足条件的商品剔除 check_sell_num = int(self.sell_num_label_edit.text()) self.need_check_goods_list = [item for item in self.need_check_goods_list if item['sell_num'] >= int(check_sell_num)] if len(self.need_check_goods_list) <=0: continue # 循环遍历商品,获取磨损度区间,获取最低价和获取磨损区间内的最低价 for g_i_i in range(len(self.need_check_goods_list)): try: #判断退出条件 if self.stop_selecting_flag: self.detail_logger.debug('停止选品') self.logger_cmd.debug('停止选品') return # 判断是否达到了成功的数量限制,如果达到,则跳出循环 if self.stop_condition == '按照成功数量': self.detail_logger.debug(f'按照成功数量,设定的成功数量为:{self.success_count},当前检索已成功的数量为:{self.search_success_count}') if int(self.success_count) <= int(self.search_success_count): return else: # 按照选品数量来判断是否要停止 self.detail_logger.debug(f'按照选品数量,设定的选品数量为:{self.scan_count},当前检索的选品数量为:{self.searchedGoodsNum}') if int(self.scan_count) <= int(self.searchedGoodsNum): return # 1、获取磨损信息 self.detail_logger.debug(f"开始获取商品id: {self.need_check_goods_list[g_i_i]['id']} 的磨损数据") # 暂停时间 self.detail_logger.debug(f"暂停 {float(self.pause_time):.2f} seconds 在进行..") time.sleep(float(self.pause_time)) # 检索数据是否停止的条件 self.search_goods_stop_flag = True # 404异常次数 self.search_goods_404_times = 0 # 请求商品数据,如果返回的code为'System Error',则继续用当前的cookie请求,连续3次,则跳出循环。如果返回的code为'Captcha Validate Required',则用下一个cookie请求,cookie连续的3次被标记为超时,则此cookie标志为无效,当所有的cookie都标记为无效时,退出程序 temp_cookie_i = 0 self.paintwear_choices = [] temp_cookie_length = len(self.cookie_text_list) while self.search_goods_stop_flag: # 判断退出条件 if self.stop_selecting_flag: self.detail_logger.debug('停止选品') self.logger_cmd.debug('停止选品') return # 遍历self.cookie_status中元素,self.cookie_text为主键的值,如果次数为3,则删除self.cookie_text中这个cookie self.detail_logger.debug(f"self.cookie_status:{self.cookie_status}") for key, value in self.cookie_status.items(): self.detail_logger.debug(f"key is {key}, value is {value} self.needed_msg_check_try_times is { int(self.needed_msg_check_try_times)}") if value >= int(self.needed_msg_check_try_times): if key in self.cookie_text_list: # 删除self.cookie_text_list中key对应的值 self.cookie_text_list.remove(key) self.detail_logger.debug(f"cookie: {key},超时异常的次数{value},删除") # 当self.cookie_text_list长度为0时,则退出程序 if len(self.cookie_text_list) == 0: self.detail_logger.debug('所有cookie都超时,退出程序') return # 更新选品cookie ,每一次请求轮流取其中一个 self.temp_cookie_text = self.cookie_text_list[(g_i_i+temp_cookie_i) % len(self.cookie_text_list)] self.xp_my_headers.update({ 'Cookie': self.temp_cookie_text }) self.xp_logger.debug(f'[选品]正在使用:{self.temp_cookie_text} 名称:{self.need_check_goods_list[g_i_i]["name"]},ID:{self.need_check_goods_list[g_i_i]["id"]} ') self.logger_cmd.debug(f'[选品]正在使用:{self.temp_cookie_text} 检索 名称:{self.need_check_goods_list[g_i_i]["name"]},ID:{self.need_check_goods_list[g_i_i]["id"]} ') goods_id = self.need_check_goods_list[g_i_i]['id'] paintware_res = req.get(url=self.xp_getPaintwearChoicesUrl + str(goods_id), headers=self.xp_my_headers) self.detail_logger.debug(f"获取商品id: {goods_id} 磨损区间请求返回报文中的CODE:{paintware_res.json()['code']} ,获取商品id: {goods_id} 磨损区间请求返回报文:{paintware_res.text.strip()[:50]}") # 返回成功,则跳出循环 if paintware_res.json()['code'] == 'OK': # 重置404异常次数 self.search_goods_404_times = 0 # 请求成功了,退出循环 self.search_goods_stop_flag = False # 将这个cookie对应的短信验证的次数清0 self.cookie_status[self.temp_cookie_text] = 0 # 将遍历结果的商品数据记录保存 data = paintware_res.json()['data'] self.paintwear_choices = data['paintwear_choices'] break # 返回404异常,继续用这个cookie请求,超过了次数则退出 elif paintware_res.json()['code'] == 'System Error': # 404异常次数加1 self.search_goods_404_times += 1 # 将这个cookie对应的短信验证的次数清0 self.cookie_status[self.temp_cookie_text] = 0 if self.search_goods_404_times >= temp_cookie_length: self.detail_logger.debug(f"有效的cookie都提示404异常,异常次数:{str(self.search_goods_404_times)}, 跳出循环继续下一个商品检索") break else: temp_cookie_i += 1 # 404异常时候,暂停一会再执行 self.logger_cmd.debug(f'访问频繁,等待{float(self.pause_time) + 30}秒') time.sleep(float(self.pause_time) + 30) continue # 返回需要短信验证 elif paintware_res.json()['code'] == 'Captcha Validate Required' or paintware_res.json()['code'] == 'Login Required' or paintware_res.json()['code'] == 'Action Forbidden' : if paintware_res.json()['code'] == 'Login Required': self.logger_cmd.debug(f'需要登陆') # time.sleep(float(self.needed_msg_check_pause_time)) self.search_goods_404_times = 0 #判断self.cookie_status是否有key为self.temp_cookie_text if self.temp_cookie_text not in self.cookie_status: if paintware_res.json()['code'] == 'Captcha Validate Required': self.logger_cmd.debug(f'需要短信验证,次数1,等待{float(self.needed_msg_check_pause_time)}秒!') self.cookie_status[self.temp_cookie_text] = 1 else: if paintware_res.json()['code'] == 'Captcha Validate Required': self.logger_cmd.debug(f'需要短信验证,次数{int(self.cookie_status[self.temp_cookie_text]) + 1},等待{float(self.needed_msg_check_pause_time)}秒!') self.cookie_status[self.temp_cookie_text] = int(self.cookie_status[self.temp_cookie_text]) + 1 time.sleep(float(self.needed_msg_check_pause_time)) # 从self.cookie_text_list获取下一个cookie,因为此cookie需要从list中移除,所以自动就是下一个,如果没有从list中移除,需要+1 if self.cookie_status[self.temp_cookie_text] >= int(self.needed_msg_check_try_times): self.logger_cmd.debug(f'异常{int(self.needed_msg_check_try_times)}次,暂停!') temp_cookie_i += 0 else: temp_cookie_i += 1 else: # 其他异常的情况,直接跳出 # 重置404异常次数 self.search_goods_404_times = 0 # 请求成功了,退出循环 self.search_goods_stop_flag = False # 将这个cookie对应的短信验证的次数清0 self.cookie_status[self.temp_cookie_text] = 0 break # 商品磨损区间长度小于等于0 ,continue if len(self.paintwear_choices) <= 0: continue # 1、先获取全磨损的最低价 170 self.detail_logger.debug(f"开始获取商品id: {self.need_check_goods_list[g_i_i]['id']} 的全磨损的最低价") # 暂停时间 self.detail_logger.debug(f"暂停 {float(self.pause_time):.2f} seconds 再进行全磨损的最低价请求..") time.sleep(float(self.pause_time)) # 检索数据是否停止的条件 self.search_goods_stop_flag = True # 404异常次数 self.search_goods_404_times = 0 # 请求商品数据,如果返回的code为'System Error',则继续用当前的cookie请求,连续3次,则跳出循环。如果返回的code为'Captcha Validate Required',则用下一个cookie请求,cookie连续的3次被标记为超时,则此cookie标志为无效,当所有的cookie都标记为无效时,退出程序 temp_cookie_i = 0 temp_cookie_length = len(self.cookie_text_list) while self.search_goods_stop_flag: # 判断退出条件 if self.stop_selecting_flag: self.detail_logger.debug('停止选品') self.logger_cmd.debug('停止选品') return # 遍历self.cookie_status中元素,self.cookie_text为主键的值,如果次数为3,则删除self.cookie_text中这个cookie for key, value in self.cookie_status.items(): if value >= int(self.needed_msg_check_try_times): if key in self.cookie_text_list: # 删除self.cookie_text_list中key对应的值 self.cookie_text_list.remove(key) self.detail_logger.debug(f"cookie: {key},超时异常的次数{value},删除") # 当self.cookie_text_list长度为0时,则退出程序 if len(self.cookie_text_list) == 0: self.detail_logger.debug('所有cookie都超时,退出程序') return # 更新选品cookie ,每一次请求轮流取其中一个 self.temp_cookie_text = self.cookie_text_list[(g_i_i+temp_cookie_i) % len(self.cookie_text_list)] self.xp_my_headers.update({ 'Cookie': self.temp_cookie_text }) goods_id = self.need_check_goods_list[g_i_i]['id'] self.goods_min_price = 0 url = self.xp_getPriceUrl + str(goods_id) paintware_minprice_res = req.get(url=url, headers=self.xp_my_headers) self.logger_cmd.debug(f'正在使用{self.temp_cookie_text}') # self.logger_cmd.debug(f"获取商品id{goods_id}全磨损区间最低价") self.detail_logger.debug(f"获取商品id: {goods_id} 全磨损区间最低价请求返回报文中的CODE:{paintware_minprice_res.json()['code']} ,获取商品id: {goods_id} 全磨损区间最低价请求返回报文:{paintware_minprice_res.text.strip()[:50]}") # 返回成功,则跳出循环 if paintware_minprice_res.json()['code'] == 'OK': # 重置404异常次数 self.search_goods_404_times = 0 # 请求成功了,退出循环 self.search_goods_stop_flag = False # 将这个cookie对应的短信验证的次数清0 self.cookie_status[self.temp_cookie_text] = 0 # 将遍历结果的商品数据记录保存 data = paintware_minprice_res.json()['data'] self.goods_min_price = data['items'][0]['price'] self.detail_logger.debug(f"获取商品id: {goods_id} 全磨损区间最低价:{self.goods_min_price}") self.logger_cmd.debug(f"获取商品id: {goods_id} 全磨损区间最低价:{self.goods_min_price}") break # 返回404异常,继续用这个cookie请求,超过了次数则退出 elif paintware_minprice_res.json()['code'] == 'System Error': # 404异常次数加1 self.search_goods_404_times += 1 # 将这个cookie对应的短信验证的次数清0 self.cookie_status[self.temp_cookie_text] = 0 if self.search_goods_404_times >= temp_cookie_length: self.detail_logger.debug(f"有效的cookie都提示404异常,异常次数:{str(self.search_goods_404_times)}, 跳出循环继续商品其他区间检索") break else: temp_cookie_i += 1 # 404异常时候,暂停一会再执行 self.logger_cmd.debug(f'访问频繁,等待{float(self.pause_time) + 30}秒') time.sleep(float(self.pause_time) + 30) continue # 返回需要短信验证 elif paintware_minprice_res.json()['code'] == 'Captcha Validate Required' or paintware_minprice_res.json()['code'] == 'Login Required' or paintware_minprice_res.json()['code'] == 'Action Forbidden' : if paintware_minprice_res.json()['code'] == 'Login Required': self.logger_cmd.debug(f'需要登陆') # time.sleep(float(self.needed_msg_check_pause_time)) self.search_goods_404_times = 0 #判断self.cookie_status是否有key为self.temp_cookie_text if self.temp_cookie_text not in self.cookie_status: if paintware_minprice_res.json()['code'] == 'Captcha Validate Required': self.logger_cmd.debug(f'需要短信验证,次数1,等待{float(self.needed_msg_check_pause_time)}秒!') self.cookie_status[self.temp_cookie_text] = 1 else: if paintware_minprice_res.json()['code'] == 'Captcha Validate Required': self.logger_cmd.debug(f'需要短信验证,次数{int(self.cookie_status[self.temp_cookie_text]) + 1},等待{float(self.needed_msg_check_pause_time)}秒!') self.cookie_status[self.temp_cookie_text] = int(self.cookie_status[self.temp_cookie_text]) + 1 time.sleep(float(self.needed_msg_check_pause_time)) # 从self.cookie_text_list获取下一个cookie,因为此cookie需要从list中移除,所以自动就是下一个,如果没有从list中移除,需要+1 if self.cookie_status[self.temp_cookie_text] >= int(self.needed_msg_check_try_times): self.logger_cmd.debug(f'异常{int(self.needed_msg_check_try_times)}次,暂停!') temp_cookie_i += 0 else: temp_cookie_i += 1 else: # 其他异常的情况,直接跳出 # 重置404异常次数 self.search_goods_404_times = 0 # 请求成功了,退出循环 self.search_goods_stop_flag = False # 将这个cookie对应的短信验证的次数清0 self.cookie_status[self.temp_cookie_text] = 0 break if float(self.goods_min_price) <=0 : continue # 遍历磨损区间,获取磨损区间最低价格 # 每个磨损区间的最低价 min_price_list = [] # 2、获取每个磨损区间的最低价 270 260 230 240 170 for i3 in range(len(self.paintwear_choices)): # 做终止判断是否点击了停止选品按钮 if self.stop_selecting_flag: self.detail_logger.debug('停止选品') self.logger_cmd.debug('停止选品') return # 1、先获取全磨损的最低价 170 self.detail_logger.debug(f"开始获取商品id: {self.need_check_goods_list[g_i_i]['id']} 的磨损区间磨损区间{self.paintwear_choices[i3][0]}--{self.paintwear_choices[i3][1]}的最低价") # 开始时间为当前时间 # 暂停时间 self.detail_logger.debug(f"暂停 {float(self.pause_time):.2f} seconds 再进行磨损区间磨损区间{self.paintwear_choices[i3][0]}--{self.paintwear_choices[i3][1]}的最低价请求..") time.sleep(float(self.pause_time)) # 检索数据是否停止的条件 self.search_goods_stop_flag = True # 404异常次数 self.search_goods_404_times = 0 # 请求商品数据,如果返回的code为'System Error',则继续用当前的cookie请求,连续3次,则跳出循环。如果返回的code为'Captcha Validate Required',则用下一个cookie请求,cookie连续的3次被标记为超时,则此cookie标志为无效,当所有的cookie都标记为无效时,退出程序 temp_cookie_i = 0 temp_cookie_length = len(self.cookie_text_list) min_price_list.append( { 'min_wear': self.paintwear_choices[i3][0], 'max_wear': self.paintwear_choices[i3][1], 'min_price': float(0) } ) while self.search_goods_stop_flag: # 判断退出条件 if self.stop_selecting_flag: self.detail_logger.debug('停止选品') return # 遍历self.cookie_status中元素,self.cookie_text为主键的值,如果次数为3,则删除self.cookie_text中这个cookie for key, value in self.cookie_status.items(): if value >= int(self.needed_msg_check_try_times): if key in self.cookie_text_list: # 删除self.cookie_text_list中key对应的值 self.cookie_text_list.remove(key) self.detail_logger.debug(f"cookie: {key},超时异常的次数{value},删除") # 当self.cookie_text_list长度为0时,则退出程序 if len(self.cookie_text_list) == 0: self.detail_logger.debug('所有cookie都超时,退出程序') return # 更新选品cookie ,每一次请求轮流取其中一个 self.temp_cookie_text = self.cookie_text_list[(g_i_i+temp_cookie_i) % len(self.cookie_text_list)] self.xp_my_headers.update({ 'Cookie': self.temp_cookie_text }) goods_id = self.need_check_goods_list[g_i_i]['id'] url = self.xp_getPriceUrl + str(goods_id) # min_paint_wear 不为空 if self.paintwear_choices[i3][0] != '': self.detail_logger.debug('min_paint_wear 最低磨损值 不为空') url += '&min_paintwear=' + str(self.paintwear_choices[i3][0]) # max_paint_wear 不为空 if self.paintwear_choices[i3][1] != '': self.detail_logger.debug('max_paint_wear 最高磨损值 不为空') url += '&max_paintwear=' + str(self.paintwear_choices[i3][1]) paintware_minprice_res = req.get(url=url, headers=self.xp_my_headers) self.logger_cmd.debug(f'正在使用{self.temp_cookie_text}') # self.logger_cmd.debug(f"获取商品id{goods_id}磨损区间{self.paintwear_choices[i3][0]}--{self.paintwear_choices[i3][1]}最低价") self.detail_logger.debug(f"获取商品id: {goods_id} 磨损区间{self.paintwear_choices[i3][0]}--{self.paintwear_choices[i3][1]}最低价请求返回报文中的CODE:{paintware_minprice_res.json()['code']} ,获取商品id: {goods_id} 磨损区间{self.paintwear_choices[i3][0]}--{self.paintwear_choices[i3][1]}最低价请求返回报文:{paintware_minprice_res.text.strip()[:50]}") # 返回成功,则跳出循环 if paintware_minprice_res.json()['code'] == 'OK': # 重置404异常次数 self.search_goods_404_times = 0 # 请求成功了,退出循环 self.search_goods_stop_flag = False # 将这个cookie对应的短信验证的次数清0 self.cookie_status[self.temp_cookie_text] = 0 # 将遍历结果的商品数据记录保存 data = paintware_minprice_res.json()['data'] self.detail_logger.debug(f"获取商品id: {goods_id} 磨损区间{self.paintwear_choices[i3][0]}--{self.paintwear_choices[i3][1]}最低价:{float(data['items'][0]['price'])}") self.logger_cmd.debug(f"获取商品id: {goods_id} 磨损区间{self.paintwear_choices[i3][0]}--{self.paintwear_choices[i3][1]}最低价:{float(data['items'][0]['price'])}") # 遍历min_price_list,如果min_wear的值为self.paintwear_choices[i3][0],max_wear的值为self.paintwear_choices[i3][1],则将min_price的值更新为float(data['items'][0]['price']) for ii2 in range(len(min_price_list)): if min_price_list[ii2]['min_wear'] == self.paintwear_choices[i3][0] and min_price_list[ii2]['max_wear'] == self.paintwear_choices[i3][1]: min_price_list[ii2]['min_price'] = float(data['items'][0]['price']) break # # todo # min_price_list.append( # { # 'min_wear': self.paintwear_choices[i3][0], # 'max_wear': self.paintwear_choices[i3][1], # 'min_price': float(data['items'][0]['price']) # }) break # 返回404异常,继续用这个cookie请求,超过了次数则退出 elif paintware_minprice_res.json()['code'] == 'System Error': # 404异常次数加1 self.search_goods_404_times += 1 # 将这个cookie对应的短信验证的次数清0 self.cookie_status[self.temp_cookie_text] = 0 if self.search_goods_404_times >= temp_cookie_length: self.detail_logger.debug(f"有效的cookie都提示404异常,异常次数:{str(self.search_goods_404_times)}, 跳出循环继续商品其他区间检索") break else: temp_cookie_i += 1 # 404异常时候,暂停一会再执行 self.logger_cmd.debug(f'访问频繁,等待{float(self.pause_time) + 30}秒') time.sleep(float(self.pause_time) + 30) continue # 返回需要短信验证 elif paintware_minprice_res.json()['code'] == 'Captcha Validate Required' or paintware_minprice_res.json()['code'] == 'Login Required' or paintware_minprice_res.json()['code'] == 'Action Forbidden': if paintware_minprice_res.json()['code'] == 'Login Required': self.logger_cmd.debug(f'需要登陆') # time.sleep(float(self.needed_msg_check_pause_time)) self.search_goods_404_times = 0 #判断self.cookie_status是否有key为self.temp_cookie_text if self.temp_cookie_text not in self.cookie_status: if paintware_minprice_res.json()['code'] == 'Captcha Validate Required': self.logger_cmd.debug(f'需要短信验证,次数1,等待{float(self.needed_msg_check_pause_time)}秒!') self.cookie_status[self.temp_cookie_text] = 1 else: if paintware_minprice_res.json()['code'] == 'Captcha Validate Required': self.logger_cmd.debug(f'需要短信验证,次数{int(self.cookie_status[self.temp_cookie_text]) + 1},等待{float(self.needed_msg_check_pause_time)}秒!') self.cookie_status[self.temp_cookie_text] = int(self.cookie_status[self.temp_cookie_text]) + 1 time.sleep(float(self.needed_msg_check_pause_time)) # 从self.cookie_text_list获取下一个cookie,因为此cookie需要从list中移除,所以自动就是下一个,如果没有从list中移除,需要+1 if self.cookie_status[self.temp_cookie_text] >= int(self.needed_msg_check_try_times): self.logger_cmd.debug(f'异常{int(self.needed_msg_check_try_times)}次,暂停!') temp_cookie_i += 0 else: temp_cookie_i += 1 else: # 其他异常的情况,直接跳出 # 重置404异常次数 self.search_goods_404_times = 0 # 请求成功了,退出循环 self.search_goods_stop_flag = False # 将这个cookie对应的短信验证的次数清0 self.cookie_status[self.temp_cookie_text] = 0 break # 计算 self.detail_logger.debug(f"获取商品id:{self.need_check_goods_list[g_i_i]['id']} 磨损区间及最低价信息: {min_price_list}") # 区间内容有价格为0,则跳过该商品,跳到下一个商品 break_flag = False for i2 in range(len(min_price_list)): if min_price_list[i2]['min_price'] == 0: self.detail_logger.debug(f"获取商品id:{self.need_check_goods_list[g_i_i]['id']} 磨损区间及最低价信息中,有价格是0,跳过该商品") break_flag = True if break_flag: self.detail_logger.debug(f"商品id:{self.need_check_goods_list[g_i_i]['id']} 筛选不满足条件,继续下次循环") continue # 退出条件判断实时判断是否需要退出 # 3、全区间的最低价 170 * (1+10%),10%是设定的 = 187元 pd_price = round(round( float(self.goods_min_price) * (100 + float(self.ref_price_adjust)) / 100, 2) + 0.01,2) # 4、将5个磨损区间的最低价跟187比对,只留高于这个187价格的区间 # 遍历 min_price_list for i1 in range(len(min_price_list)): if min_price_list[i1]['min_price'] < pd_price: # min_price_list 删除i1及以后的元素 min_price_list = min_price_list[:i1] break # 5、根据阶梯来确定磨损区间 # 遍历 min_price_list,判断元素中的min_price是否小于上一个元素的min_price, for i2 in range(len(min_price_list) - 1): if min_price_list[i2]['min_price'] < min_price_list[i2 + 1]['min_price']: # min_price_list 删除i2及以后的元素 min_price_list = min_price_list[:i2 + 1] break # 6、170*(1+0.02)= 173.4 购买溢价 gm_price = round(round(float(self.goods_min_price) * (100 + float(self.sweep_price_adjust)) / 100, 2)+ 0.01,2) # min_price_list 为空则继续下次循环 if len(min_price_list) <= 0: self.detail_logger.debug(f"商品id:{self.need_check_goods_list[g_i_i]['id']} 筛选不满足条件,继续下次循环") continue # 向BUFF选品日志标签页中添加一条数据 timestamp = time.time() local_time = time.localtime(timestamp) formatted_time = time.strftime('%Y-%m-%d %H:%M:%S', local_time) self.detail_logger.debug(f"商品id:{self.need_check_goods_list[g_i_i]['id']} 筛选成功, 及价格区间min_price_list:{min_price_list}") # 向BUFF选品日志标签页中增加记录 发出信号而不是直接调用 add_select_log self.log_added.emit(str(self.need_check_goods_list[g_i_i]['id']), str(self.need_check_goods_list[g_i_i]["name"]), str(min_price_list[0]['min_wear']), str(min_price_list[-1]['max_wear']), str(self.goods_min_price), str(gm_price), str(pd_price), str(formatted_time)) conn = sqlite3.connect('buff.db') cursor = conn.cursor() cursor.execute(''' INSERT INTO select_logs (item_id, item_name, min_wear, max_wear, min_full_wear_price, sweep_price, judge_price, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ''', (self.need_check_goods_list[g_i_i]["id"], self.need_check_goods_list[g_i_i]["name"], min_price_list[0]['min_wear'], min_price_list[-1]['max_wear'], self.goods_min_price , gm_price, pd_price, formatted_time)) # 提交更改并关闭连接 conn.commit() conn.close() # 检索成功数量+1 self.search_success_count += 1 if self.temp_cookie_text in self.cookie_status: temp_checked_times = self.cookie_status[self.temp_cookie_text] else: temp_checked_times = 0 self.xp_logger.debug(f'[已选]正在使用:{self.temp_cookie_text} (已标记{temp_checked_times}次) . 名称:{self.need_check_goods_list[g_i_i]["name"]},ID:{self.need_check_goods_list[g_i_i]["id"]} ,购买底价:{gm_price} , 区间:{min_price_list[0]["min_wear"]}-{min_price_list[-1]["max_wear"]} ') self.logger_cmd.debug(f'选品成功。名称:{self.need_check_goods_list[g_i_i]["name"]},ID:{self.need_check_goods_list[g_i_i]["id"]} ,购买底价:{gm_price} , 区间:{min_price_list[0]["min_wear"]}-{min_price_list[-1]["max_wear"]} ') except Exception as e: self.detail_logger.debug(f"商品id: {self.need_check_goods_list[g_i_i]['id']}判断异常: {e}") finally: self.searchedGoodsNum += 1 pass except Exception as e: self.detail_logger.debug(f"选品接口请求异常: {e}") finally: self.button_sh.setEnabled(True) self.button_stop_sh.setEnabled(True) self.button1.setEnabled(True) self.detail_logger.debug('停止选品') self.logger_cmd.debug('停止选品') self.xp_started = False # todo 开启扫货 self.beginSH() pass # 停止选品 def stop_selecting(self): # 设置选品停止标志为True self.stop_selecting_flag = True self.xp_started = False self.logger_cmd.debug('人工停止选品') QMessageBox.information(self, "停止选品", "选品操作已终止") # 扫货时候关闭选品 选品时候关闭扫货 todo def beginSH(self): self.logger_cmd.debug('开始扫货') self.detail_logger.debug('开始扫货') self.sh_logger.debug('开始扫货') # todo 先暂停选品 self.logger_cmd.debug('暂停选品中') self.detail_logger.debug(f'暂停选品中') self.sh_logger.debug(f'暂停选品中') # 设置扫货停止标志为True self.stop_selecting_flag = True self.xp_started = False time.sleep( float(self.pause_time_edit.text()) ) # self.button1 self.stop_select_button 按钮不可点击 self.button1.setEnabled(False) self.stop_select_button.setEnabled(False) self.button_sh.setEnabled(False) self.stop_shopping_flag = False # 必填条件,没有则跳出 # self.sh_phone_number = self.sh_phone_edit.text() # QMessageBox.information(self, "扫货手机号码", f"扫货手机号码: {self.sh_phone_number}") # # 判断phone_number是否为空,为空则跳出方法 # if not self.sh_phone_number: # QMessageBox.information(self, "扫货手机号码", "扫货手机号码不能为空") # return # 判断扫货cookie是否为空,为空则退出方法 self.sh_cookie_text = self.sh_cookie_edit.toPlainText() self.detail_logger.debug(f"扫货Cookie: {self.sh_cookie_text}") if not self.sh_cookie_text: self.detail_logger.debug("扫货Cookie不能为空") self.sh_logger.debug("扫货Cookie不能为空") return # 判断扫货xcsrftoken是否为空,为空则退出方法 # self.sh_xcsrftoken_text = self.sh_xcsrftoken_edit.toPlainText() # self.detail_logger.debug(f"扫货xcsrftoken: {self.sh_xcsrftoken_text}") # if not self.sh_xcsrftoken_text: # self.detail_logger.debug("扫货xcsrftoken不能为空") # return try: # 获取扫货线程self.shpz_thread_count_edit的值 self.shpz_thread_count = int(self.shpz_thread_count_edit.text()) if self.shpz_thread_count > 0 : self.detail_logger.debug(f'开启{self.shpz_thread_count}个扫货线程') self.sh_logger.debug(f'开启{self.shpz_thread_count}个扫货线程') self.logger_cmd.debug(f'开启{self.shpz_thread_count}个扫货线程') j = 0 while j < self.shpz_thread_count: j = j + 1 self.detail_logger.debug(f'开启扫货线程 - {j}') thread_BUFFSH = threading.Thread(target=self.BUFFSH,args=(j,)) thread_BUFFSH.start() self.detail_logger.debug(f'开启扫货线程 - {j}完成') self.sh_logger.debug(f'开启扫货线程 - {j}完成') self.logger_cmd.debug(f'开启扫货线程 - {j}完成') except Exception as e: # self.button1 self.stop_select_button 按钮不可点击 self.button1.setEnabled(True) self.stop_select_button.setEnabled(True) self.button_sh.setEnabled(True) self.detail_logger.debug(f"扫货进程开启Error: {e}") def BUFFSH(self, thread_num): try: while True: try: # logger.debug(f'扫货线程 - {thread_num}') if self.stop_shopping_flag: self.detail_logger.debug(f'扫货线程 - {thread_num} 人工停止扫货') self.sh_logger.debug(f'扫货线程 - {thread_num} 人工停止扫货') self.logger_cmd.debug(f'扫货线程 - {thread_num} 人工停止扫货') return # 获取BUFF选品日志标签页列表中的数据 sh_start_time = 0 # 间隔扫货 for i1 in range(self.select_log_tree_widget.topLevelItemCount()): if self.stop_shopping_flag: self.detail_logger.debug(f'扫货线程 - {thread_num} 人工停止扫货') self.sh_logger.debug(f'扫货线程 - {thread_num} 人工停止扫货') self.logger_cmd.debug(f'扫货线程 - {thread_num} 人工停止扫货') return #假设为10条数据,三个进程,第1,4,7由第一个进程处理 第2,5,8由第二个进程处理 if i1 % self.shpz_thread_count == thread_num - 1: item = self.select_log_tree_widget.topLevelItem(i1) if self.stop_shopping_flag: self.detail_logger.debug(f'扫货线程 - {thread_num} 人工停止扫货') self.sh_logger.debug(f'扫货线程 - {thread_num} 人工停止扫货') self.logger_cmd.debug(f'扫货线程 - {thread_num} 人工停止扫货') return self.sh_logger.debug(f'扫货线程-{thread_num} 名称:{item.text(2)},ID:{item.text(1)} ,购买底价:{item.text(6)} , 区间:{item.text(3)}-{item.text(4)} ') goods_id = item.text(1) goods_min_wear = item.text(3) goods_max_wear = item.text(4) goods_buy_price = item.text(6) # 请求BUFF 商品信息列表,获取可以购买的商品 time.sleep(float(self.shpz_pause_time_edit.text())) self.logger_cmd.debug(f'扫货线程{thread_num} 名称:{item.text(2)},ID:{item.text(1)} ,购买底价:{item.text(6)} , 区间:{item.text(3)}-{item.text(4)} ') self.detail_logger.debug(f'扫货线程-{thread_num} 扫货暂停{float(self.shpz_pause_time_edit.text())}秒') # current_time = time.time() # time_since_last_request = current_time - sh_start_time # if time_since_last_request < float(self.shpz_pause_time_edit.text()): # wait_time = float(self.shpz_pause_time_edit.text()) - time_since_last_request # self.detail_logger.debug(f"暂停 {wait_time:.2f} seconds before making the next request.") # time.sleep(wait_time) # logger.debug(f'扫货线程 - {thread_num} 扫货商品id:{goods_id} 磨损区间:{goods_min_wear}-{goods_max_wear} 购买价格:{goods_buy_price}') goods_items_list = self.getGoodsInfo(goods_id, goods_min_wear, goods_max_wear, goods_buy_price ,thread_num) self.detail_logger.debug(f'扫货线程 - {thread_num} goods_items_list:{goods_items_list}') if goods_items_list == 'stop': self.detail_logger.debug(f'扫货线程 - {thread_num} 停止扫货') self.sh_logger.debug(f'扫货线程 - {thread_num} 停止扫货') self.logger_cmd.debug(f'扫货线程{thread_num} 停止扫货') return self.logger_cmd.debug(f'扫货线程{thread_num} 名称:{item.text(2)},ID:{item.text(1)} ,购买底价:{item.text(6)} , 区间:{item.text(3)}-{item.text(4)}, 共获取到{len(goods_items_list)}个商品可购买 ') for goods_item in goods_items_list: if self.stop_shopping_flag: self.detail_logger.debug(f'扫货线程 - {thread_num} 人工停止扫货') self.sh_logger.debug(f'扫货线程 - {thread_num} 人工停止扫货') self.logger_cmd.debug(f'扫货线程{thread_num} 人工停止扫货') return # post请求购买接口 try: self.detail_logger.debug(f"扫货线程 - {thread_num} 商品ID: {goods_item['goods_id']} 订单id: {goods_item['id']} 购买价格: {goods_item['price']}") self.logger_cmd.debug(f"扫货线程{thread_num} 购买 商品ID: {goods_item['goods_id']} 订单id: {goods_item['id']} 购买价格: {goods_item['price']}") api_data ={ "game": "csgo", "goods_id": goods_item['goods_id'], "sell_order_id": goods_item['id'], "price": goods_item['price'], "pay_method": 1, "allow_tradable_cooldown": 0, "token": "", "cdkey_id": "", "hide_non_epay": False } api_header = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", "Host": "buff.163.com", "X-Requested-With": "XMLHttpRequest", 'Referer': f"https://buff.163.com/goods/{goods_item['goods_id']}?from=market", 'Cookie': self.sh_cookie_text, 'x-csrftoken': self.sh_xcsrftoken_text} # todo res = req.post(self.sh_buyGoodsUrl, headers=api_header, data=api_data) self.detail_logger.debug(f"扫货线程 - {thread_num} 商品ID: {goods_item['goods_id']} 订单id: {goods_item['id']} 购买价格: {goods_item['price']} api_header: {api_header} post-url请求 {self.sh_buyGoodsUrl} 返回报文: {res.text.strip()}") self.detail_logger.debug(f'扫货线程 - {thread_num} 购买接口请求返回报文中的CODE:{res.json()["code"]}') if res.json()['code'] == 'Captcha Validate Required' or res.json()['code'] == 'Login Required' or res.json()['code'] == 'Action Forbidden': self.detail_logger.debug(f'扫货线程 - {thread_num} 购买接口请求返回报文code为Captcha Validate Required 或者 Login Required 或者 Action Forbidden,暂停{self.shpz_need_check_time_edit.text()}秒后重试') retry_count = 0 while retry_count < int(self.shpz_need_try_time_edit.text()): self.detail_logger.debug(f'扫货线程 - {thread_num} 购买接口请求返回报文code为Captcha Validate Required,第{retry_count + 1}次重试') time.sleep(float(self.shpz_need_check_time_edit.text())) res = req.post(self.sh_buyGoodsUrl, headers=api_header, data=api_data) # data = api1_res.json()['data'] if res.json()['code'] == 'System Error': # self.logger_cmd.debug(f"扫货线程{thread_num} 访问频繁") continue if res.json()['code'] == 'OK': self.logger_cmd.debug(f"扫货线程{thread_num} 购买成功 商品ID: {goods_item['goods_id']} 订单id: {goods_item['id']} 购买价格: {goods_item['price']}") break if res.json()['code'] == 'Captcha Validate Required' or res.json()['code'] == 'Login Required' or res.json()['code'] == 'Action Forbidden': retry_count += 1 if res.json()['code'] == 'Captcha Validate Required': self.logger_cmd.debug(f'扫货线程{thread_num} 需要短信验证,次数{retry_count},等待{float(self.shpz_need_check_time_edit.text())}秒!') if res.json()['code'] == 'Login Required': self.logger_cmd.debug(f'扫货线程{thread_num} 需要登陆,次数{retry_count},等待{float(self.shpz_need_check_time_edit.text())}秒!') if res.json()['code'] == 'Captcha Validate Required' or res.json()['code'] == 'Login Required' or res.json()['code'] == 'Action Forbidden': self.detail_logger.debug(f'扫货线程 - {thread_num} 选品获取商品信息接口请求返回报文code仍然为Captcha Validate Required 或者 Login Required 或者 Action Forbidden,跳出循环') self.logger_cmd.debug(f'扫货线程{thread_num} 异常{int(self.shpz_need_try_time_edit.text())}次,暂停!') return elif res.json()['code'] != 'OK': # 如果data中的code不等于OK,则跳出循环 self.detail_logger.debug(f'扫货线程 - {thread_num} 选品接口请求返回报文: {res.text.strip()[:50]}') self.detail_logger.debug(f'扫货线程 - {thread_num} 选品接口请求返回报文code不等于OK,跳出循环') continue if res.json()['code'] == 'OK': self.detail_logger.debug(f"扫货线程 - {thread_num} ,商品ID: {goods_item['goods_id']} 订单id: {goods_item['id']} 购买价格: {goods_item['price']} 购买成功") self.gm_logger.debug(f"名称:{item.text(2)},ID:{goods_item['goods_id']} ,购买底价:{item.text(6)} , 区间:{item.text(3)}-{item.text(4)} 购买价格:{goods_item['price']}") except Exception as e: self.detail_logger.debug(f"扫货线程 - {thread_num} 商品ID: {goods_item['goods_id']} 订单id: {goods_item['id']} 购买价格: {goods_item['price']} 购买商品信息接口请求--失败: {e}") finally: sh_start_time = time.time() # # 结束时间为当前时间 # end_time = time.time() # # 从start_time到end_time 必须修改pause_time秒 # if float(end_time - start_time) < float(self.pause_time_edit.text()): # time.sleep(float(self.pause_time_edit.text()) - (end_time - start_time) + random.randint(0, 5)) except Exception as e: self.detail_logger.debug(f'扫货线程 - {thread_num} 购买商品信息接口请求--失败:{e}') finally: pass finally: self.button1.setEnabled(True) self.stop_select_button.setEnabled(True) self.button_sh.setEnabled(True) self.sh_logger.debug(f'扫货线程 - {thread_num} 停止扫货') self.detail_logger.debug(f'扫货线程 - {thread_num} 停止扫货') self.logger_cmd.debug(f'扫货线程{thread_num} 停止扫货') def getGoodsInfo(self, goods_id, goods_min_wear, goods_max_wear, goods_buy_price,thread_num): # # 获取当前时间戳 # timestamp = time.time() # # 将时间戳转换为datetime对象 # dt_object = datetime.fromtimestamp(timestamp) self.detail_logger.debug(f"扫货线程 - {thread_num} 获取商品id: {goods_id} 的在磨损区间{goods_min_wear}-{goods_max_wear}是否有低于{goods_buy_price}的商品信息") self.logger_cmd.debug(f"扫货线程{thread_num} 获取商品id: {goods_id} 的在磨损区间{goods_min_wear}-{goods_max_wear}是否有低于{goods_buy_price}的商品信息") # 开始时间为当前时间 goods_id_list = [] start_time = time.time() self.sh_my_headers.update({ 'Cookie': self.sh_cookie_text }) try: # todo 为了测试,先去除磨损区间 api_url = f'{self.sh_getToBuyUrl}{goods_id}&min_price=0&max_price={goods_buy_price}&min_paintwear={goods_min_wear}&max_paintwear={goods_max_wear}' #api_url = f'{self.sh_getToBuyUrl}{goods_id}&min_price=0&max_price={goods_buy_price}' self.detail_logger.debug(f'扫货线程 - {thread_num} api_url = {api_url}') api2_res = req.get(api_url, headers=self.sh_my_headers) # logger.debug(f'获取商品id:{goods_id}的在磨损区间{goods_min_wear}-{goods_max_wear}是否有低于{goods_buy_price}的商品信息的返回报文: {api2_res.text.strip()}') if api2_res.json()['code'] == 'Captcha Validate Required' or api2_res.json()['code'] == 'Login Required' or api2_res.json()['code'] == 'Action Forbidden': self.detail_logger.debug(f'扫货线程 - {thread_num} 获取商品id: {goods_id} 的在磨损区间{goods_min_wear}-{goods_max_wear}是否有低于{goods_buy_price}的商品信息的返回报文code为Captcha Validate Required 或者 Login Required 或者 Action Forbidden ,暂停{self.shpz_need_check_time_edit.text()}秒后重试') retry_count = 0 while retry_count < int(self.shpz_need_try_time_edit.text()): self.detail_logger.debug(f'扫货线程 - {thread_num} 获取商品id: {goods_id} 的在磨损区间{goods_min_wear}-{goods_max_wear}是否有低于{goods_buy_price}的商品信息请求返回报文code为Captcha Validate Required,第{retry_count + 1}次重试') time.sleep(float(self.shpz_need_check_time_edit.text())) api2_res = req.get(api_url, headers=self.sh_my_headers) # data = api1_res.json()['data'] if api2_res.json()['code'] == 'System Error': # time.sleep(30) # self.logger_cmd.debug(f'扫货线程{thread_num} 返回码:System Error 访问频繁 ') continue if api2_res.json()['code'] == 'OK': break if api2_res.json()['code'] == 'Captcha Validate Required' or api2_res.json()['code'] == 'Login Required' or api2_res.json()['code'] == 'Action Forbidden': retry_count += 1 if api2_res.json()['code'] == 'Captcha Validate Required': self.logger_cmd.debug(f'扫货线程{thread_num} 需要短信验证,次数{retry_count},等待{float(self.shpz_need_check_time_edit.text())}秒!') if api2_res.json()['code'] == 'Login Required': self.logger_cmd.debug(f'扫货线程{thread_num} 需要登陆,次数{retry_count},等待{float(self.shpz_need_check_time_edit.text())}秒!') if api2_res.json()['code'] == 'Captcha Validate Required' or api2_res.json()['code'] == 'Login Required' or api2_res.json()['code'] == 'Action Forbidden': self.detail_logger.debug(f'扫货线程 - {thread_num} 获取商品id: {goods_id} 的在磨损区间{goods_min_wear}-{goods_max_wear}是否有低于{goods_buy_price}的商品信息请求返回报文code仍然为Captcha Validate Required 或者 Login Required 或者 Action Forbidden,跳出循环') goods_id_list = 'stop' self.logger_cmd.debug(f'扫货线程{thread_num} 异常{int(self.shpz_need_try_time_edit.text())}次,暂停!') return 'stop' elif api2_res.json()['code'] != 'OK': # self.logger_cmd.debug(f'扫货线程{thread_num} 请求异常 ') self.detail_logger.debug(f'扫货线程 - {thread_num} 获取商品id: {goods_id} 的在磨损区间{goods_min_wear}-{goods_max_wear}是否有低于{goods_buy_price}的商品信息请求返回报文: {api2_res.text.strip()}') self.detail_logger.debug(f'扫货线程 - {thread_num} 获取商品id: {goods_id} 的在磨损区间{goods_min_wear}-{goods_max_wear}是否有低于{goods_buy_price}的商品信息接口请求返回报文code不等于OK,跳出循环') return goods_id_list if api2_res.json()['code'] == 'OK': data = api2_res.json()['data'] goods_id_list = data['items'] # 获取响应的header信息 headers = api2_res.headers self.detail_logger.debug(f'headers: {headers}') # 打印header信息 for header, value in headers.items(): # 获取set-cookie中 csrf_token的值 if header == 'set-cookie': cookies_list = value.split(', ') # print(f'cookies_list: {cookies_list}') for cookie in cookies_list: if 'csrf_token' in cookie: csrf_token = cookie.split('=')[1].split(';')[0] self.sh_xcsrftoken_text = csrf_token self.detail_logger.debug(f"扫货线程 - {thread_num} 获取商品id: {goods_id} 的在磨损区间{goods_min_wear}-{goods_max_wear}是否有低于{goods_buy_price}的商品信息: {goods_id_list}") except Exception as e: self.detail_logger.debug(f'扫货线程 - {thread_num} 获取商品id: {goods_id} 的在磨损区间{goods_min_wear}-{goods_max_wear}是否有低于{goods_buy_price}的商品信息接口请求--失败:{e}') finally: # # # 结束时间为当前时间 # end_time = time.time() # # 从start_time到end_time 必须修改pause_time秒 # if float(end_time - start_time) < float(self.pause_time_edit.text()): # time.sleep(float(self.pause_time_edit.text()) - (end_time - start_time) ) return goods_id_list def stopSH(self): # 在这里添加停止扫货的逻辑 # 设置扫货停止标志为True self.stop_shopping_flag = True QMessageBox.information(self, "停止扫货", "扫货操作已终止") # 选品账号信息tab页加载 def create_account_info_form(self, prefix): form_layout = QFormLayout() # 从sqlite中accounts获取信息,降数据库中得到值填到输入框中 # 从数据库中获取默认值 conn = sqlite3.connect('buff.db') c = conn.cursor() c.execute("SELECT phone_number, email, email_alias, cookie FROM accounts LIMIT 1") default_values = c.fetchone() conn.close() # 设置默认值 # phone_default = default_values[0] if default_values else "17756576757" # email_default = default_values[1] if default_values else "704541015@qq.com" # code_default = default_values[2] if default_values else "0012312" cookie_default = default_values[3] if default_values else "" # 创建输入框及其标签 # phone_label = QLabel(f"{prefix}手机号码") # phone_edit = QLineEdit() # phone_edit.setFixedWidth(300) # 设置固定宽度为500像素 # phone_edit.setText(phone_default) # 设置选品手机号码默认值 # form_layout.addRow(phone_label, phone_edit) # email_label = QLabel(f"{prefix}邮箱号") # email_edit = QLineEdit() # email_edit.setFixedWidth(300) # 设置固定宽度为500像素 # email_edit.setText(email_default) # 设置选品邮箱号默认值 # form_layout.addRow(email_label, email_edit) # email_alias_label = QLabel(f"{prefix}邮箱特殊代码") # email_alias_edit = QLineEdit() # email_alias_edit.setFixedWidth(300) # 设置固定宽度为500像素 # email_alias_edit.setText(code_default) # 设置选品邮箱特殊代码默认值 # form_layout.addRow(email_alias_label, email_alias_edit) cookie_label = QLabel(f"{prefix}cookie") self.xp_cookie_edit = QTextEdit() # 使用QTextEdit代替QLineEdit self.xp_cookie_edit.setFixedWidth(400) # 设置固定宽度为500像素 self.xp_cookie_edit.setText(cookie_default) # 设置选品cookie默认值 form_layout.addRow(cookie_label, self.xp_cookie_edit) # 保存输入框的引用以便后续访问 # self.phone_edit_map[prefix] = phone_edit # self.email_edit_map[prefix] = email_edit # self.email_alias_edit_map[prefix] = email_alias_edit # 添加保存按钮 save_button = QPushButton("保存") save_button.clicked.connect(self.save_account_info) save_button.setFixedSize(100, 50) # 设置固定宽度为500像素 # 创建一个水平布局来放置保存按钮 button_layout = QHBoxLayout() button_layout.setContentsMargins(10, 0, 0, 0) button_layout.addWidget(save_button, alignment=Qt.AlignmentFlag.AlignLeft) # 将垂直布局添加到表单布局中 form_layout.addRow(button_layout) form_layout.setContentsMargins(10, 0, 0, 0) return form_layout # 选品账号信息保存按钮功能 def save_account_info(self): # phone_number = self.phone_edit_map["选品"].text() # # 获取选品邮箱号 # email = self.email_edit_map["选品"].text() # email_alias = self.email_alias_edit_map["选品"].text() cookie = self.xp_cookie_edit.toPlainText() # if not phone_number or not email or not email_alias or not cookie: if not cookie: QMessageBox.warning(self, "保存账号信息", "所有字段都必须填写") return try: conn = sqlite3.connect('buff.db') cursor = conn.cursor() cursor.execute('delete from accounts ') cursor.execute(''' INSERT INTO accounts (phone_number, email, email_alias, cookie) VALUES (?, ?, ?, ?) ''', ('1','1','1', cookie)) conn.commit() conn.close() QMessageBox.information(self, "保存账号信息", "账号信息已成功保存") except Exception as e: QMessageBox.critical(self, "保存账号信息", f"保存账号信息时发生错误: {e}") # 品类信息tab页加载 def create_category_info_form(self): layout = QVBoxLayout() layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保布局内容靠左对齐 # 创建树形控件 self.tree_widget = QTreeWidget() self.tree_widget.setHeaderLabels(["选择", "品类名称", "品类编码"]) self.tree_widget.setColumnCount(3) self.tree_widget.setSelectionMode(QTreeWidget.SelectionMode.ExtendedSelection) self.tree_widget.setRootIsDecorated(True) # 启用根节点的装饰 self.tree_widget.setAlternatingRowColors(True) # 设置交替行颜色 self.tree_widget.setStyleSheet("QTreeWidget::item { padding: 5px; }") # 设置项的内边距 # 启用复选框 self.tree_widget.setColumnWidth(0, 100) # 设置选择列的宽度 self.tree_widget.setColumnWidth(1, 100) # 设置品类名称列的宽度 self.tree_widget.setColumnWidth(2, 100) # 设置品类编码列的宽度 self.tree_widget.setHeaderItem(QTreeWidgetItem(["选择", "品类名称", "品类编码"])) # 设置表头 self.tree_widget.header().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft) # 设置表头对齐方式 # 添加默认的品类信息 conn = sqlite3.connect('buff.db') c = conn.cursor() c.execute("SELECT name,code,selected FROM categories ") rows = c.fetchall() for row in rows: item = QTreeWidgetItem(self.tree_widget) item.setText(1, row[0]) item.setText(2, row[1]) checkbox = QCheckBox() #row[2]为1 设置成True ,为0 设置成False checkbox.setChecked(True if row[2] == 1 else False) self.tree_widget.setItemWidget(item, 0, checkbox) conn.close() layout.addWidget(self.tree_widget) # 创建按钮布局 button_layout = QHBoxLayout() button_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保按钮布局内容靠左对齐 # 创建添加按钮 add_button = QPushButton("添加") add_button.clicked.connect(self.add_category) button_layout.addWidget(add_button) # 创建删除按钮 delete_button = QPushButton("删除") delete_button.clicked.connect(self.delete_category) button_layout.addWidget(delete_button) # 创建编辑按钮 edit_button = QPushButton("编辑") edit_button.clicked.connect(self.edit_category) button_layout.addWidget(edit_button) # 创建保存按钮 save_button = QPushButton("保存") save_button.clicked.connect(self.save_categories) button_layout.addWidget(save_button) layout.addLayout(button_layout) return layout # 新增品类信息 def add_category(self): CategoryDialog.add_category(self) # 删除品类信息 def delete_category(self): CategoryDialog.delete_category(self) # 编辑品类信息 def edit_category(self): CategoryDialog.edit_category(self) # 保存品类信息 def save_categories(self): CategoryDialog.save_categories(self) # 品质信息tab页加载 def create_quality_info_form(self): layout = QVBoxLayout() layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保布局内容靠左对齐 # 创建树形控件 self.quality_tree_widget = QTreeWidget() self.quality_tree_widget.setHeaderLabels(["选择", "品质编码", "品质名称"]) self.quality_tree_widget.setColumnCount(3) self.quality_tree_widget.setSelectionMode(QTreeWidget.SelectionMode.ExtendedSelection) self.quality_tree_widget.setRootIsDecorated(True) # 启用根节点的装饰 self.quality_tree_widget.setAlternatingRowColors(True) # 设置交替行颜色 self.quality_tree_widget.setStyleSheet("QTreeWidget::item { padding: 5px; }") # 设置项的内边距 # 启用复选框 self.quality_tree_widget.setColumnWidth(0, 100) # 设置选择列的宽度 self.quality_tree_widget.setColumnWidth(1, 100) # 设置品质编码列的宽度 self.quality_tree_widget.setColumnWidth(2, 100) # 设置品质名称列的宽度 self.quality_tree_widget.setHeaderItem(QTreeWidgetItem(["选择", "品质编码", "品质名称"])) # 设置表头 self.quality_tree_widget.header().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft) # 设置表头对齐方式 # 添加默认的品质信息 conn = sqlite3.connect('buff.db') c = conn.cursor() c.execute("SELECT name,code,selected FROM qualities ") rows = c.fetchall() for row in rows: item = QTreeWidgetItem(self.quality_tree_widget) item.setText(1, row[1]) item.setText(2, row[0]) checkbox = QCheckBox() #row[2]为1 设置成True ,为0 设置成False checkbox.setChecked(True if row[2] == 1 else False) self.quality_tree_widget.setItemWidget(item, 0, checkbox) conn.close() layout.addWidget(self.quality_tree_widget) # 创建按钮布局 button_layout = QHBoxLayout() button_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保按钮布局内容靠左对齐 # 创建添加按钮 add_button = QPushButton("添加") add_button.clicked.connect(self.add_quality) button_layout.addWidget(add_button) # 创建删除按钮 delete_button = QPushButton("删除") delete_button.clicked.connect(self.delete_quality) button_layout.addWidget(delete_button) # 创建编辑按钮 edit_button = QPushButton("编辑") edit_button.clicked.connect(self.edit_quality) button_layout.addWidget(edit_button) # 创建保存按钮 save_button = QPushButton("保存") save_button.clicked.connect(self.save_qualities) button_layout.addWidget(save_button) layout.addLayout(button_layout) return layout # 新增品质信息 def add_quality(self): QualityDialog.add_quality(self) # 删除品质信息 def delete_quality(self): QualityDialog.delete_quality(self) # 编辑品质信息 def edit_quality(self): QualityDialog.edit_quality(self) # 保存品质信息 def save_qualities(self): QualityDialog.save_qualities(self) # 加载类别信息tab页 def create_type_info_form(self): layout = QVBoxLayout() layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保布局内容靠左对齐 # 创建树形控件 self.type_tree_widget = QTreeWidget() self.type_tree_widget.setHeaderLabels(["选择", "type编码", "type名称"]) self.type_tree_widget.setColumnCount(3) self.type_tree_widget.setSelectionMode(QTreeWidget.SelectionMode.ExtendedSelection) self.type_tree_widget.setRootIsDecorated(True) # 启用根节点的装饰 self.type_tree_widget.setAlternatingRowColors(True) # 设置交替行颜色 self.type_tree_widget.setStyleSheet("QTreeWidget::item { padding: 5px; }") # 设置项的内边距 # 启用复选框 self.type_tree_widget.setColumnWidth(0, 100) # 设置选择列的宽度 self.type_tree_widget.setColumnWidth(1, 100) # 设置type编码列的宽度 self.type_tree_widget.setColumnWidth(2, 100) # 设置type名称列的宽度 self.type_tree_widget.setHeaderItem(QTreeWidgetItem(["选择", "type编码", "type名称"])) # 设置表头 self.type_tree_widget.header().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft) # 设置表头对齐方式 # 添加默认的type信息 conn = sqlite3.connect('buff.db') c = conn.cursor() c.execute("SELECT name,code,selected FROM types ") rows = c.fetchall() for row in rows: item = QTreeWidgetItem(self.type_tree_widget) item.setText(1, row[1]) item.setText(2, row[0]) checkbox = QCheckBox() #row[2]为1 设置成True ,为0 设置成False checkbox.setChecked(True if row[2] == 1 else False) self.type_tree_widget.setItemWidget(item, 0, checkbox) conn.close() layout.addWidget(self.type_tree_widget) # 创建按钮布局 button_layout = QHBoxLayout() button_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保按钮布局内容靠左对齐 # 创建添加按钮 add_button = QPushButton("添加") add_button.clicked.connect(self.add_type) button_layout.addWidget(add_button) # 创建删除按钮 delete_button = QPushButton("删除") delete_button.clicked.connect(self.delete_type) button_layout.addWidget(delete_button) # 创建编辑按钮 edit_button = QPushButton("编辑") edit_button.clicked.connect(self.edit_type) button_layout.addWidget(edit_button) # 创建保存按钮 save_button = QPushButton("保存") save_button.clicked.connect(self.save_types) button_layout.addWidget(save_button) layout.addLayout(button_layout) return layout # 新增类别信息 def add_type(self): TypeDialog.add_type(self) # 删除类别信息 def delete_type(self): TypeDialog.delete_type(self) # 编辑类别信息 def edit_type(self): TypeDialog.edit_type(self) # 保存类别信息 def save_types(self): TypeDialog.save_types(self) # 加载外观信息tab页 def create_appearance_info_form(self): layout = QVBoxLayout() layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保布局内容靠左对齐 # 创建树形控件 self.appearance_tree_widget = QTreeWidget() self.appearance_tree_widget.setHeaderLabels(["选择", "外观编码", "外观名称"]) self.appearance_tree_widget.setColumnCount(3) self.appearance_tree_widget.setSelectionMode(QTreeWidget.SelectionMode.ExtendedSelection) self.appearance_tree_widget.setRootIsDecorated(True) # 启用根节点的装饰 self.appearance_tree_widget.setAlternatingRowColors(True) # 设置交替行颜色 self.appearance_tree_widget.setStyleSheet("QTreeWidget::item { padding: 5px; }") # 设置项的内边距 # 启用复选框 self.appearance_tree_widget.setColumnWidth(0, 100) # 设置选择列的宽度 self.appearance_tree_widget.setColumnWidth(1, 100) # 设置外观编码列的宽度 self.appearance_tree_widget.setColumnWidth(2, 100) # 设置外观名称列的宽度 self.appearance_tree_widget.setHeaderItem(QTreeWidgetItem(["选择", "外观编码", "外观名称"])) # 设置表头 self.appearance_tree_widget.header().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft) # 设置表头对齐方式 # 添加默认的外观信息 conn = sqlite3.connect('buff.db') c = conn.cursor() c.execute("SELECT name,code,selected FROM appearances ") rows = c.fetchall() for row in rows: item = QTreeWidgetItem(self.appearance_tree_widget) item.setText(1, row[1]) item.setText(2, row[0]) checkbox = QCheckBox() #row[2]为1 设置成True ,为0 设置成False checkbox.setChecked(True if row[2] == 1 else False) self.appearance_tree_widget.setItemWidget(item, 0, checkbox) conn.close() layout.addWidget(self.appearance_tree_widget) # 创建按钮布局 button_layout = QHBoxLayout() button_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保按钮布局内容靠左对齐 # 创建添加按钮 add_button = QPushButton("添加") add_button.clicked.connect(self.add_appearance) button_layout.addWidget(add_button) # 创建删除按钮 delete_button = QPushButton("删除") delete_button.clicked.connect(self.delete_appearance) button_layout.addWidget(delete_button) # 创建编辑按钮 edit_button = QPushButton("编辑") edit_button.clicked.connect(self.edit_appearance) button_layout.addWidget(edit_button) # 创建保存按钮 save_button = QPushButton("保存") save_button.clicked.connect(self.save_appearances) button_layout.addWidget(save_button) layout.addLayout(button_layout) return layout # 新增外观信息 def add_appearance(self): AppearanceDialog.add_appearance(self) # 删除外观信息 def delete_appearance(self): AppearanceDialog.delete_appearance(self) # 编辑外观信息 def edit_appearance(self): AppearanceDialog.edit_appearance(self) # 保存外观信息 def save_appearances(self): AppearanceDialog.save_appearances(self) # 加载收藏品信息tab页 def create_collectible_info_form(self): layout = QVBoxLayout() layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保布局内容靠左对齐 # 创建树形控件 self.collectible_tree_widget = QTreeWidget() self.collectible_tree_widget.setHeaderLabels(["选择", "收藏品编码", "收藏品名称"]) self.collectible_tree_widget.setColumnCount(3) self.collectible_tree_widget.setSelectionMode(QTreeWidget.SelectionMode.ExtendedSelection) self.collectible_tree_widget.setRootIsDecorated(True) # 启用根节点的装饰 self.collectible_tree_widget.setAlternatingRowColors(True) # 设置交替行颜色 self.collectible_tree_widget.setStyleSheet("QTreeWidget::item { padding: 5px; }") # 设置项的内边距 # 启用复选框 self.collectible_tree_widget.setColumnWidth(0, 100) # 设置选择列的宽度 self.collectible_tree_widget.setColumnWidth(1, 100) # 设置收藏品编码列的宽度 self.collectible_tree_widget.setColumnWidth(2, 100) # 设置收藏品名称列的宽度 self.collectible_tree_widget.setHeaderItem(QTreeWidgetItem(["选择", "收藏品编码", "收藏品名称"])) # 设置表头 self.collectible_tree_widget.header().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft) # 设置表头对齐方式 # 添加默认的收藏品信息 conn = sqlite3.connect('buff.db') c = conn.cursor() c.execute("SELECT name,code,selected FROM collectibles ") rows = c.fetchall() for row in rows: item = QTreeWidgetItem(self.collectible_tree_widget) item.setText(1, row[1]) item.setText(2, row[0]) checkbox = QCheckBox() #row[2]为1 设置成True ,为0 设置成False checkbox.setChecked(True if row[2] == 1 else False) self.collectible_tree_widget.setItemWidget(item, 0, checkbox) conn.close() layout.addWidget(self.collectible_tree_widget) # 创建按钮布局 button_layout = QHBoxLayout() button_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保按钮布局内容靠左对齐 # 创建添加按钮 add_button = QPushButton("添加") add_button.clicked.connect(self.add_collectible) button_layout.addWidget(add_button) # 创建删除按钮 delete_button = QPushButton("删除") delete_button.clicked.connect(self.delete_collectible) button_layout.addWidget(delete_button) # 创建编辑按钮 edit_button = QPushButton("编辑") edit_button.clicked.connect(self.edit_collectible) button_layout.addWidget(edit_button) # 创建保存按钮 save_button = QPushButton("保存") save_button.clicked.connect(self.save_collectibles) button_layout.addWidget(save_button) layout.addLayout(button_layout) return layout # 新增收藏品 def add_collectible(self): CollectibleDialog.add_collectible(self) # 删除收藏品 def delete_collectible(self): CollectibleDialog.delete_collectible(self) # 编辑收藏品 def edit_collectible(self): CollectibleDialog.edit_collectible(self) # 保存收藏品 def save_collectibles(self): CollectibleDialog.save_collectibles(self) # 加载选品配置信息tab页 def create_config_info_form(self, prefix): form_layout = QFormLayout() form_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保表单布局内容靠左对齐 # 从数据库中获取默认值 conn = sqlite3.connect('buff.db') c = conn.cursor() c.execute( "SELECT min_price, max_price, sort_mode, stop_condition, " "success_count, scan_count, page_size, pause_time, max_pages, " "ref_price_adjust, sweep_price_adjust,needed_msg_check_pause_time ," "needed_msg_check_try_times,delete_ids,cron_time,sell_num FROM config LIMIT 1") default_values = c.fetchone() conn.close() # 创建选品最低价输入框及其标签 min_price_label = QLabel(f"{prefix}最低价") self.min_price_edit = QLineEdit() self.min_price_edit.setFixedWidth(300) # 设置固定宽度为500像素 # default_values 为None if default_values is not None: self.min_price_edit.setText(str(default_values[0])) form_layout.addRow(min_price_label, self.min_price_edit) # 创建选品最高价输入框及其标签 max_price_label = QLabel(f"{prefix}最高价") self.max_price_edit = QLineEdit() self.max_price_edit.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.max_price_edit.setText(str(default_values[1])) form_layout.addRow(max_price_label, self.max_price_edit) # 创建选品排序模式下拉选择框及其标签 sort_mode_label = QLabel(f"{prefix}排序模式") self.sort_mode_combo = QComboBox() self.sort_mode_combo.addItems(["默认", "价格升序", "价格降序", "在售数量升序"]) self.sort_mode_combo.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.sort_mode_combo.setCurrentText(default_values[2]) form_layout.addRow(sort_mode_label, self.sort_mode_combo) # 创建选品停止条件下拉选择框及其标签 stop_condition_label = QLabel(f"{prefix}停止条件") self.stop_condition_combo = QComboBox() self.stop_condition_combo.addItems(["按照成功数量", "按照扫描数量"]) self.stop_condition_combo.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.stop_condition_combo.setCurrentText(default_values[3]) form_layout.addRow(stop_condition_label, self.stop_condition_combo) # 创建成功数量配置输入框及其标签 success_count_label = QLabel(f"{prefix}成功数量配置") self.success_count_edit = QLineEdit() self.success_count_edit.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.success_count_edit.setText(str(default_values[4])) form_layout.addRow(success_count_label, self.success_count_edit) # 创建扫描商品数量配置输入框及其标签 scan_count_label = QLabel(f"{prefix}扫描商品数量") self.scan_count_edit = QLineEdit() self.scan_count_edit.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.scan_count_edit.setText(str(default_values[5])) form_layout.addRow(scan_count_label, self.scan_count_edit) # 创建选品接口每页请求数量配置输入框及其标签 page_size_label = QLabel(f"{prefix}接口每页请求数量") self.page_size_edit = QLineEdit() self.page_size_edit.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.page_size_edit.setText(str(default_values[6])) form_layout.addRow(page_size_label, self.page_size_edit) # 创建每次调用BUFF接口暂停时间配置输入框及其标签 pause_time_label = QLabel(f"{prefix}接口暂停时间(秒)") self.pause_time_edit = QLineEdit() self.pause_time_edit.setFixedWidth(300) # 设置固定宽度为500像素 # self.pause_time_edit.setText("10") # 设置默认值为10 if default_values is not None: self.pause_time_edit.setText(str(default_values[7])) form_layout.addRow(pause_time_label, self.pause_time_edit) # 创建选品接口最大请求多少页配置输入框及其标签 max_pages_label = QLabel(f"{prefix}接口最大请求多少页") self.max_pages_edit = QLineEdit() self.max_pages_edit.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.max_pages_edit.setText(str(default_values[8])) form_layout.addRow(max_pages_label, self.max_pages_edit) # 创建商品参考价调整系数输入框及其标签 ref_price_adjust_label = QLabel(f"{prefix}商品参考价调整系数%") self.ref_price_adjust_edit = QLineEdit() self.ref_price_adjust_edit.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.ref_price_adjust_edit.setText(str(default_values[9])) form_layout.addRow(ref_price_adjust_label, self.ref_price_adjust_edit) # 创建商品扫货价调整系数输入框及其标签 sweep_price_adjust_label = QLabel(f"{prefix}商品扫货价调整系数%") self.sweep_price_adjust_edit = QLineEdit() self.sweep_price_adjust_edit.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.sweep_price_adjust_edit.setText(str(default_values[10])) form_layout.addRow(sweep_price_adjust_label, self.sweep_price_adjust_edit) # 商品选品弹出需要短信验证时,下次请求暂停时长,默认为0 needed_msg_check_pause_time_label = QLabel(f"{prefix}API接口需短信验证时\n下次选品暂停时长(秒)") self.needed_msg_check_pause_time_edit = QLineEdit() self.needed_msg_check_pause_time_edit.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.needed_msg_check_pause_time_edit.setText(str(default_values[11])) form_layout.addRow(needed_msg_check_pause_time_label, self.needed_msg_check_pause_time_edit) #商品选品弹出需要短信验证时 尝试几次后仍异常,退出选品 needed_msg_check_try_times_label = QLabel(f"{prefix}API接口需短信验证时\n尝试几次后仍异常,退出选品(次)") self.needed_msg_check_try_times_edit = QLineEdit() self.needed_msg_check_try_times_edit.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.needed_msg_check_try_times_edit.setText(str(default_values[12])) form_layout.addRow(needed_msg_check_try_times_label, self.needed_msg_check_try_times_edit) # 需剔除的id列表 delete_ids_label = QLabel(f"需剔除的id列表(#号分割)") self.delete_ids_label_edit = QLineEdit() self.delete_ids_label_edit.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.delete_ids_label_edit.setText(str(default_values[13])) form_layout.addRow(delete_ids_label, self.delete_ids_label_edit) # 每天定时执行时间的配置 cron_time_label = QLabel(f"每天定时执行时间的配置(9代表9点)") self.cron_time_label_edit = QLineEdit() self.cron_time_label_edit.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.cron_time_label_edit.setText(str(default_values[14])) form_layout.addRow(cron_time_label, self.cron_time_label_edit) # 销售数量的配置 sell_num_label = QLabel(f"销售数量配置") self.sell_num_label_edit = QLineEdit() self.sell_num_label_edit.setFixedWidth(300) # 设置固定宽度为500像素 if default_values is not None: self.sell_num_label_edit.setText(str(default_values[15])) form_layout.addRow(sell_num_label, self.sell_num_label_edit) # 创建保存按钮 save_button = QPushButton("保存") save_button.clicked.connect(self.save_config) save_button.setFixedSize(100, 50) # 设置固定宽度为500像素 # 创建一个水平布局来放置保存按钮 button_layout = QHBoxLayout() button_layout.setContentsMargins(10, 0, 0, 0) button_layout.addWidget(save_button, alignment=Qt.AlignmentFlag.AlignLeft) # 将垂直布局添加到表单布局中 form_layout.addRow(button_layout) form_layout.setContentsMargins(10, 0, 0, 0) return form_layout # 保存选品配置信息 def save_config(self): # 连接到SQLite数据库 conn = sqlite3.connect('buff.db') cursor = conn.cursor() # 清空表中的数据 cursor.execute('DELETE FROM config') # 获取配置信息 min_price = self.min_price_edit.text() max_price = self.max_price_edit.text() sort_mode = self.sort_mode_combo.currentText() stop_condition = self.stop_condition_combo.currentText() success_count = self.success_count_edit.text() scan_count = self.scan_count_edit.text() page_size = self.page_size_edit.text() pause_time = self.pause_time_edit.text() max_pages = self.max_pages_edit.text() ref_price_adjust = self.ref_price_adjust_edit.text() sweep_price_adjust = self.sweep_price_adjust_edit.text() needed_msg_check_pause_time = self.needed_msg_check_pause_time_edit.text() needed_msg_check_try_times = self.needed_msg_check_try_times_edit.text() delete_ids = self.delete_ids_label_edit.text() cron_time = self.cron_time_label_edit.text() sell_num = self.sell_num_label_edit.text() # 插入数据到表中 cursor.execute(''' INSERT INTO config (min_price, max_price, sort_mode, stop_condition, success_count, scan_count, page_size, pause_time, max_pages, ref_price_adjust, sweep_price_adjust,needed_msg_check_pause_time,needed_msg_check_try_times,delete_ids,cron_time,sell_num) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?) ''', ( min_price, max_price, sort_mode, stop_condition, success_count, scan_count, page_size, pause_time, max_pages, ref_price_adjust, sweep_price_adjust,needed_msg_check_pause_time,needed_msg_check_try_times,delete_ids,cron_time,sell_num)) # 提交更改并关闭连接 conn.commit() conn.close() QMessageBox.information(self, "保存选品配置", "选品配置已成功保存") # 加载选品日志的tab框 def create_select_log_info_form(self): layout = QVBoxLayout() layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保布局内容靠左对齐 # 创建树形控件 self.select_log_tree_widget = QTreeWidget() self.select_log_tree_widget.setHeaderLabels( ["选择", "商品ID", "商品名称", "磨损最低值", "磨损最高值", "全磨损区间最低价", "扫货价", "判断价", "时间"]) self.select_log_tree_widget.setColumnCount(9) self.select_log_tree_widget.setSelectionMode(QTreeWidget.SelectionMode.ExtendedSelection) self.select_log_tree_widget.setRootIsDecorated(True) # 启用根节点的装饰 self.select_log_tree_widget.setAlternatingRowColors(True) # 设置交替行颜色 self.select_log_tree_widget.setStyleSheet("QTreeWidget::item { padding: 5px; }") # 设置项的内边距 # 启用复选框 self.select_log_tree_widget.setColumnWidth(0, 50) # 设置选择列的宽度 self.select_log_tree_widget.setColumnWidth(1, 50) # 设置商品ID列的宽度 self.select_log_tree_widget.setColumnWidth(2, 50) # 设置商品名称列的宽度 self.select_log_tree_widget.setColumnWidth(3, 50) # 设置磨损最低值列的宽度 self.select_log_tree_widget.setColumnWidth(4, 50) # 设置磨损最高值列的宽度 self.select_log_tree_widget.setColumnWidth(5, 50) # 设置全磨损区间最低价列的宽度 self.select_log_tree_widget.setColumnWidth(6, 50) # 设置扫货价列的宽度 self.select_log_tree_widget.setColumnWidth(7, 50) # 设置判断价列的宽度 self.select_log_tree_widget.setColumnWidth(8, 50) # 设置时间列的宽度 self.select_log_tree_widget.setHeaderItem(QTreeWidgetItem( ["序号", "商品ID", "商品名称", "磨损最低值", "磨损最高值", "全磨损区间最低价", "扫货价", "判断价", "时间"])) # 设置表头 self.select_log_tree_widget.header().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft) # 设置表头对齐方式 conn = sqlite3.connect('buff.db') c = conn.cursor() c.execute( "SELECT item_id, item_name, min_wear, max_wear, min_full_wear_price, sweep_price, judge_price, timestamp FROM select_logs ") rows = c.fetchall() item_i = 1 for row in rows: item = QTreeWidgetItem(self.select_log_tree_widget) item.setText(0, str(item_i)) item.setText(1, str(row[0])) item.setText(2, str(row[1])) item.setText(3, str(row[2])) item.setText(4, str(row[3])) item.setText(5, str(row[4])) item.setText(6, str(row[5])) item.setText(7, str(row[6])) item.setText(8, str(row[7])) item_i += 1 # checkbox = QCheckBox() # checkbox.setChecked(False) # self.select_log_tree_widget.setItemWidget(item, 0, checkbox) conn.close() layout.addWidget(self.select_log_tree_widget) # 创建按钮布局 button_layout = QHBoxLayout() button_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) # 确保按钮布局内容靠左对齐 # 创建添加按钮 add_button = QPushButton("添加") add_button.clicked.connect(self.show_add_select_log_dialog) button_layout.addWidget(add_button) # 创建删除按钮 delete_button = QPushButton("删除") delete_button.clicked.connect(self.delete_select_log) button_layout.addWidget(delete_button) # 创建编辑按钮 edit_button = QPushButton("编辑") edit_button.clicked.connect(self.edit_select_log) button_layout.addWidget(edit_button) # 创建导出按钮 export_button = QPushButton("导出") export_button.clicked.connect(self.export_selected_logs) button_layout.addWidget(export_button) # 创建导入按钮 import_button = QPushButton("导入") import_button.clicked.connect(self.import_selected_logs) button_layout.addWidget(import_button) # 创建保存按钮 save_button = QPushButton("保存") save_button.clicked.connect(self.save_select_logs) button_layout.addWidget(save_button) layout.addLayout(button_layout) return layout # 导入日志 def import_selected_logs(self): # 导入元素的逻辑 file_path, _ = QFileDialog.getOpenFileName(self, "导入商品数据", "", "JSON Files (*.json);;All Files (*)") if file_path: with open(file_path, 'r', encoding='utf-8') as f: items = json.load(f) for item_id, item_data in items.items(): item = QTreeWidgetItem() item.setText(0, "") # 商品选择 item.setText(1, item_data['商品ID']) item.setText(2, item_data['商品名称']) item.setText(3, item_data['磨损最低值']) item.setText(4, item_data['磨损最高值']) item.setText(5, item_data['全磨损区间最低价']) item.setText(6, item_data['扫货价']) item.setText(7, item_data['判断价']) item.setText(8, item_data['时间']) self.select_log_tree_widget.addTopLevelItem(item) SelectLogDialog.update_row_numbers(self) self.save_select_logs() QMessageBox.information(self, "成功", "数据已成功导入") # 导出日志 def export_selected_logs(self): SelectLogDialog.export_selected_logs(self) # 保存日志 def save_select_logs(self): SelectLogDialog.save_select_logs(self) # 编辑日志 def edit_select_log(self): SelectLogDialog.edit_select_log(self) # 删除日志 def delete_select_log(self): SelectLogDialog.delete_select_log(self) # 新增日志 def show_add_select_log_dialog(self): SelectLogDialog.show_add_select_log_dialog(self) # 加载扫货账号信息tab页 def setup_shzhtab(self): # 创建表单布局 form_layout = QFormLayout() # 从数据库中获取默认值 conn = sqlite3.connect('buff.db') c = conn.cursor() c.execute("SELECT phone, email, code, cookie,xcsrftoken FROM sh_account_info LIMIT 1") default_values = c.fetchone() conn.close() # 设置默认值 phone_default = default_values[0] if default_values else "17756576757" email_default = default_values[1] if default_values else "704541015@qq.com" code_default = default_values[2] if default_values else "0012312" cookie_default = default_values[3] if default_values else "" xcsrftoken_default = default_values[4] if default_values else "" # 添加输入字段 self.sh_phone_edit = QLineEdit(phone_default) self.sh_email_edit = QLineEdit(email_default) self.sh_code_edit = QLineEdit(code_default) self.sh_cookie_edit = QTextEdit(cookie_default) self.sh_xcsrftoken_edit = QTextEdit(xcsrftoken_default) # 设置输入字段的宽度 self.sh_phone_edit.setFixedWidth(300) self.sh_email_edit.setFixedWidth(300) self.sh_code_edit.setFixedWidth(300) self.sh_cookie_edit.setFixedWidth(300) self.sh_xcsrftoken_edit.setFixedWidth(300) form_layout.addRow("扫货手机号码", self.sh_phone_edit) form_layout.addRow("扫货邮箱号", self.sh_email_edit) form_layout.addRow("扫货邮箱特殊代码", self.sh_code_edit) form_layout.addRow("扫货cookie", self.sh_cookie_edit) form_layout.addRow("扫货xcsrftoken", self.sh_xcsrftoken_edit) # 创建主布局 main_layout = QVBoxLayout() main_layout.addLayout(form_layout) # 连接保存按钮信号和槽 self.sh_save_button = QPushButton("保存") self.sh_save_button.clicked.connect(self.save_sh_account_info) self.sh_save_button.setFixedSize(100, 50) # 创建一个水平布局来放置保存按钮 button_layout = QHBoxLayout() button_layout.setContentsMargins(10, 0, 0, 0) button_layout.addWidget(self.sh_save_button, alignment=Qt.AlignmentFlag.AlignLeft) # 将垂直布局添加到表单布局中 form_layout.addRow(button_layout) form_layout.setContentsMargins(10, 0, 0, 0) return main_layout # 保存扫货账号信息 def save_sh_account_info(self): import sqlite3 # 连接到SQLite数据库(如果数据库不存在,则会自动创建) conn = sqlite3.connect('buff.db') c = conn.cursor() c.execute('DELETE FROM sh_account_info') # 插入数据 c.execute("INSERT INTO sh_account_info (phone, email, code, cookie,xcsrftoken) VALUES (?, ?, ?, ?,?)", (self.sh_phone_edit.text(), self.sh_email_edit.text(), self.sh_code_edit.text(), self.sh_cookie_edit.toPlainText(), self.sh_xcsrftoken_edit.toPlainText())) # 提交更改并关闭连接 conn.commit() conn.close() QMessageBox.information(self, "成功", "扫货账号信息已保存") # 加载扫货配置tab页信息 def setup_shpztab(self): # 创建表单布局 form_layout = QFormLayout() # 添加输入字段 self.shpz_pause_time_edit = QLineEdit() self.shpz_pause_time_edit.setFixedWidth(150) form_layout.addRow("API接口请求暂停时间(秒)", self.shpz_pause_time_edit) # 添加扫货线程数输入字段 self.shpz_thread_count_edit = QLineEdit() self.shpz_thread_count_edit.setFixedWidth(150) form_layout.addRow("扫货线程数", self.shpz_thread_count_edit) # 添加扫货API接口需短信验证时,下次扫货暂停时长(秒) self.shpz_need_check_time_edit = QLineEdit() self.shpz_need_check_time_edit.setFixedWidth(150) form_layout.addRow("扫货API接口需短信验证时,\n 下次扫货暂停时长(秒)", self.shpz_need_check_time_edit) # 添加扫货API接口需短信验证时,尝试几次后仍异常,退出扫货(次) self.shpz_need_try_time_edit = QLineEdit() self.shpz_need_try_time_edit.setFixedWidth(150) form_layout.addRow("扫货API接口需短信验证时,\n 尝试几次后仍异常,退出扫货(次)", self.shpz_need_try_time_edit) # 创建主布局 main_layout = QVBoxLayout() main_layout.addLayout(form_layout) # 创建保存按钮 self.shpz_save_button = QPushButton("保存") self.shpz_save_button.clicked.connect(self.shpz_save_settings) self.shpz_save_button.setFixedSize(100, 50) # 创建一个水平布局来放置保存按钮 button_layout = QHBoxLayout() button_layout.setContentsMargins(10, 0, 0, 0) button_layout.addWidget(self.shpz_save_button, alignment=Qt.AlignmentFlag.AlignLeft) # 将垂直布局添加到表单布局中 form_layout.addRow(button_layout) form_layout.setContentsMargins(10, 0, 0, 0) # 添加pause_time_edit到主布局 main_layout.addWidget(self.shpz_pause_time_edit) main_layout.addWidget(self.shpz_thread_count_edit) main_layout.addWidget(self.shpz_need_check_time_edit) main_layout.addWidget(self.shpz_need_try_time_edit) # 加载默认值 self.load_shpz_settings_from_db() return main_layout # 保存扫货配置信息 def shpz_save_settings(self): import sqlite3 # 连接到SQLite数据库(如果数据库不存在,则会自动创建) conn = sqlite3.connect('buff.db') c = conn.cursor() c.execute('DELETE FROM shpz_settings') # 插入数据 c.execute("INSERT INTO shpz_settings (pause_time, thread_count,needed_msg_check_pause_time ,needed_msg_check_try_times ) VALUES (?, ?,?,?)", (float(self.shpz_pause_time_edit.text()), int(self.shpz_thread_count_edit.text()),int(self.shpz_need_check_time_edit.text()),int(self.shpz_need_try_time_edit.text()))) # 提交更改并关闭连接 conn.commit() conn.close() QMessageBox.information(self, "成功", "设置已保存") # 从数据库读取扫货配置信息 def load_shpz_settings_from_db(self): import sqlite3 # 连接到SQLite数据库 conn = sqlite3.connect('buff.db') c = conn.cursor() # 查询数据 c.execute("SELECT pause_time, thread_count,needed_msg_check_pause_time ,needed_msg_check_try_times FROM shpz_settings LIMIT 1") default_value = c.fetchone() # 设置默认值 pause_time_default = default_value[0] if default_value else "5" thread_count_default = default_value[1] if default_value else "1" # 默认扫货线程数为1 needed_msg_check_pause_time = default_value[2] if default_value else "1" # 默认扫货线程数为1 needed_msg_check_try_times = default_value[3] if default_value else "1" # 默认扫货线程数为1 # 设置输入字段的默认值 self.shpz_pause_time_edit.setText(str(pause_time_default)) self.shpz_thread_count_edit.setText(str(thread_count_default)) self.shpz_need_check_time_edit.setText(str(needed_msg_check_pause_time)) self.shpz_need_try_time_edit.setText(str(needed_msg_check_try_times)) # 关闭数据库连接 conn.close() # 向BUFF选品日志标签页的列表中写数据的槽函数 @pyqtSlot(str, str, str, str, str, str, str, str) def _add_select_log(self, item_id, item_name, min_wear, max_wear, min_full_wear_price, sweep_price, judge_price, timestamp): # 创建一个字典来存储记录的详细信息 record = { '商品ID': item_id, '商品名称': item_name, '磨损最低值': min_wear, '磨损最高值': max_wear, '全磨损区间最低价': min_full_wear_price, '扫货价': sweep_price, '判断价': judge_price, '时间': timestamp } row_count = self.select_log_tree_widget.topLevelItemCount() # 将新记录添加到树形控件中 item = QTreeWidgetItem(self.select_log_tree_widget) # item.setText(0, "") # 选择列为空 item.setText(0, str(row_count + 1)) # 设置序号 item.setText(1, record['商品ID']) item.setText(2, record['商品名称']) item.setText(3, str(record['磨损最低值'])) item.setText(4, str(record['磨损最高值'])) item.setText(5, str(record['全磨损区间最低价'])) item.setText(6, str(record['扫货价'])) item.setText(7, str(record['判断价'])) item.setText(8, record['时间']) # 创建复选框 # checkbox = QCheckBox() # checkbox.setChecked(False) # self.select_log_tree_widget.setItemWidget(item, 0, checkbox) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec()) # def setup_phone_edit_map(self): # self.phone_edit_map = {} # self.email_edit_map = {} # self.email_alias_edit_map = {} #代码备份 发送商家报价的代码 #res = req.post(self.buyGoodsUrl, headers=api_header, data=api_data) #logger.debug(f'post 请求 {self.buyGoodsUrl} 返回报文: {res.text.strip()}') #if res.json()['code'] == 'OK': # logger.debug(f'购买成功') # time.sleep(float(self.pause_time_edit.text())) # logger.debug(f'post 请求 {self.buyGoodsUrl} 返回报文code等于OK,商品id:{goods_id}的磨损区间{goods_min_wear}-{goods_max_wear}的商品信息:{goods_item}') # try: # bill_order_id = res.json()['data']['id'] # logger.debug(f'开始发报价 bill_order_id:{bill_order_id}') # # fbj_api_data=json.dumps({ # # "bill_orders": [ # # bill_order_id # # ], # # "game": "csgo" # # }) # # logger.debug(f'fbj_api_data: { fbj_api_data }') # # fbj_api_header = { # # "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", # # "Host": "buff.163.com", "X-Requested-With": "XMLHttpRequest", # # 'Referer': f"https://buff.163.com/market/buy_order/history?game=csgo", # # 'Cookie': self.cookie_text, # # "Content-Type":"application/json", # # 'x-csrftoken': "ImM2NTBjYmZhNjk2MGRjOWVkMTQxYjM5MTBjY2RhZjJjODRkNTBlMjUi.Z7WAmQ.yZ6n3Hcjv6eXHEElO1ZA95aqSEA" # # } # # todo 使用现有的工具,后续再开发 # #fbj_res = req.post(self.fbjUrl, headers=fbj_api_header, data=fbj_api_data) # #logger.debug(f'post 请求 发报价 返回报文: {fbj_res.text.strip()}') # #if fbj_res.json()['code'] == 'OK': # # logger.debug(f'报价成功') # #else: # # logger.debug(f'报价失败') # except Exception as e: # logger.debug(f'商品发报价信息接口请求--失败', e) # try: # self.detail_logger.debug('选品接口请求参数列表 search_goods_param_list 长度:', len(self.search_goods_param_list)) # # 遍历search_goods_param_list # while True: # #判断退出条件 # if self.stop_selecting_flag: # self.detail_logger.debug('停止选品') # return # # 判断选品停止条件来判断是否需要终止 # if self.stop_condition == '按照成功数量': # self.detail_logger.debug(f'按照成功数量,设定的成功数量为:{self.success_count},当前检索已成功的数量为:{self.search_success_count}') # if int(self.success_count) <= int(self.search_success_count): # return # else: # # 按照选品数量来判断是否要停止 # self.detail_logger.debug(f'按照选品数量,设定的选品数量为:{self.scan_count},当前检索的选品数量为:{self.searchedGoodsNum}') # if int(self.scan_count) <= int(self.searchedGoodsNum): # return # for i in range(len(self.search_goods_param_list)): # try: # if self.stop_selecting_flag: # self.detail_logger.debug('停止选品') # return # # 判断选品停止条件来判断是否需要终止 # if self.stop_condition == '按照成功数量': # self.detail_logger.debug(f'按照成功数量,设定的成功数量为:{self.success_count},当前检索已成功的数量为:{self.search_success_count}') # if int(self.success_count) <= int(self.search_success_count): # return # else: # # 按照选品数量来判断是否要停止 # self.detail_logger.debug(f'按照选品数量,设定的选品数量为:{self.scan_count},当前检索的选品数量为:{self.searchedGoodsNum}') # if int(self.scan_count) <= int(self.searchedGoodsNum): # return # pagenum = 1 # j = pagenum # first_flag = True # while int(j) <= int(pagenum): # datalist = [] # if self.stop_selecting_flag: # self.detail_logger.debug('停止选品') # return # # 判断选品停止条件来判断是否需要终止 # if self.stop_condition == '按照成功数量': # self.detail_logger.debug(f'按照成功数量,设定的成功数量为:{self.success_count},当前检索已成功的数量为:{self.search_success_count}') # if int(self.success_count) <= int(self.search_success_count): # return # else: # # 按照选品数量来判断是否要停止 # self.detail_logger.debug(f'按照选品数量,设定的选品数量为:{self.scan_count},当前检索的选品数量为:{self.searchedGoodsNum}') # if int(self.scan_count) <= int(self.searchedGoodsNum): # return # if not first_flag: # self.search_goods_param_list[i]['page_num'] = j # self.detail_logger.debug(f"第{j}/{pagenum}页,API请求参数为:{self.search_goods_param_list[i]}") # else: # self.search_goods_param_list[i]['page_num'] = 1 # self.detail_logger.debug(f"新查询条件第一次预请求,API请求参数为:{self.search_goods_param_list[i]}") # try: # # 开始时间为当前时间 # current_time = time.time() # time_since_last_request = current_time - self.last_xp_request_time # if time_since_last_request < float(self.pause_time): # wait_time = float(self.pause_time) - time_since_last_request # self.detail_logger.debug(f"暂停 {wait_time:.2f} seconds before making the next request.") # time.sleep(wait_time) # api1_res = req.get(url=self.xp_goodsurl, headers=self.xp_my_headers, # params=self.search_goods_param_list[i]) # self.detail_logger.debug('遍历商品接口请求返回报文:', api1_res.text.strip()[:50]) # self.detail_logger.debug('遍历商品接口请求返回报文中的CODE:', api1_res.json()['code']) # if api1_res.json()['code'] == 'Captcha Validate Required': # self.detail_logger.debug(f'选品接口请求返回报文code为Captcha Validate Required,暂停{self.needed_msg_check_pause_time}秒后重试') # retry_count = 0 # while retry_count < int(self.needed_msg_check_try_times): # self.detail_logger.debug(f'选品获取商品信息接口请求返回报文code为Captcha Validate Required,第{retry_count + 1}次重试') # time.sleep(int(self.needed_msg_check_pause_time)) # api1_res = req.get(url=self.xp_goodsurl, headers=self.xp_my_headers, # params=self.search_goods_param_list[i]) # # data = api1_res.json()['data'] # if api1_res.json()['code'] == 'System Error': # continue # if api1_res.json()['code'] == 'OK': # break # if api1_res.json()['code'] == 'Captcha Validate Required': # retry_count += 1 # if api1_res.json()['code'] == 'Captcha Validate Required': # self.detail_logger.debug('选品获取商品信息接口请求返回报文code仍然为Captcha Validate Required,跳出循环') # return # elif api1_res.json()['code'] != 'OK': # # 如果data中的code不等于OK,则跳出循环 # self.detail_logger.debug('选品接口请求返回报文:', api1_res.text.strip()[:50]) # self.detail_logger.debug('选品接口请求返回报文code不等于OK,跳出循环') # continue # data = api1_res.json()['data'] # datalist.extend(data['items']) # # 遍历datalist # for k in range(len(datalist)): # # 做终止判断是否点击了停止选品按钮 # if self.stop_selecting_flag: # self.detail_logger.debug('停止选品') # return # # 判断选品停止条件来判断是否需要终止 # if self.stop_condition == '按照成功数量': # self.detail_logger.debug(f'按照成功数量,设定的成功数量为:{self.success_count},当前检索已成功的数量为:{self.search_success_count}') # if int(self.success_count) < int(self.search_success_count): # return # else: # # 按照选品数量来判断是否要停止 # self.detail_logger.debug(f'按照选品数量,设定的选品数量为:{self.scan_count},当前检索的选品数量为:{self.searchedGoodsNum}') # if int(self.scan_count) < int(self.searchedGoodsNum): # return # self.detail_logger.debug(f'商品id:{str(datalist[k]["id"])}开始进行价格分析') # # 选品的数量+1 # self.searchedGoodsNum += 1 # # 1、获取磨损信息 # PaintwearChoicesReturn = BUFFAPI.getPaintwearChoices(self, datalist[k]["id"]) # # 多次出现需要验证短信的异常,停止选品进程 # if PaintwearChoicesReturn == 'stop_flag': # self.detail_logger.debug(f'获取商品id:{datalist[k]["id"]}磨损信息失败,跳出进程') # return # if len(self.paintwear_choices) <= 0: # self.detail_logger.debug(f'获取商品id:{datalist[k]["id"]}磨损信息失败,筛选不满足条件,继续下次循环') # continue # # 1、先获取全磨损的最低价 170 # PaintwearChoicesMinPriceReturn = BUFFAPI.getPaintwearChoicesMinPrice(self, datalist[k]["id"], '', '') # if PaintwearChoicesMinPriceReturn == 'stop_flag': # self.detail_logger.debug(f'获取商品id:{datalist[k]["id"]}全磨损最低价格连续出现短信验证异常,筛选不满足条件,退出进程') # return # min_price = float(PaintwearChoicesMinPriceReturn) # # min_price为0 则continue # if min_price == 0: # self.detail_logger.debug(f'获取商品id:{datalist[k]["id"]}全磨损的最低价为0,筛选不满足条件,继续下次循环') # continue # # 每个磨损区间的最低价 # min_price_list = [] # # 2、获取每个磨损区间的最低价 270 260 230 240 170 # break_flag = False # for i3 in range(len(self.paintwear_choices)): # # 做终止判断是否点击了停止选品按钮 # if self.stop_selecting_flag: # self.detail_logger.debug('停止选品') # return # PaintwearChoicesMinPriceReturn1 = BUFFAPI.getPaintwearChoicesMinPrice(self, datalist[k]["id"], # self.paintwear_choices[ # i3][0], # self.paintwear_choices[ # i3][1]) # if PaintwearChoicesMinPriceReturn1 == 'stop_flag': # self.detail_logger.debug(f'获取商品id:{datalist[k]["id"]}磨损区间最低价格连续出现短信验证异常,筛选不满足条件,退出进程') # return # min_price_list.append( # { # 'min_wear': self.paintwear_choices[i3][0], # 'max_wear': self.paintwear_choices[i3][1], # 'min_price': float(PaintwearChoicesMinPriceReturn1) # } # ) # self.detail_logger.debug(f'获取商品id:{datalist[k]["id"]}磨损区间及最低价信息:', min_price_list) # # todo 区间内容有价格为0,则跳过该商品,跳到下一个商品 # for i2 in range(len(min_price_list)): # if min_price_list[i2]['min_price'] == 0: # self.detail_logger.debug(f'获取商品id:{datalist[k]["id"]}磨损区间及最低价信息:', min_price_list) # self.detail_logger.debug( # f'获取商品id:{datalist[k]["id"]}磨损区间及最低价信息中,有价格是0,跳过该商品') # break_flag = True # if break_flag: # self.detail_logger.debug(f'商品id:{datalist[k]["id"]} 筛选不满足条件,继续下次循环') # continue # # 3、全区间的最低价 170 * (1+10%),10%是设定的 = 187元 # pd_price = round(min_price * (100 + self.ref_price_adjust) / 100, 4) # # 4、将5个磨损区间的最低价跟187比对,只留高于这个187价格的区间 # # 遍历 min_price_list # for i1 in range(len(min_price_list)): # if min_price_list[i1]['min_price'] < pd_price: # # min_price_list 删除i1及以后的元素 # min_price_list = min_price_list[:i1] # break # # 5、根据阶梯来确定磨损区间 # # 遍历 min_price_list,判断元素中的min_price是否小于上一个元素的min_price, # for i2 in range(len(min_price_list) - 1): # if min_price_list[i2]['min_price'] < min_price_list[i2 + 1]['min_price']: # # min_price_list 删除i2及以后的元素 # min_price_list = min_price_list[:i2 + 1] # break # # 6、170*(1+0.02)= 173.4 购买溢价 # gm_price = round(min_price * (100 + self.sweep_price_adjust) / 100, 4) # # min_price_list 为空则继续下次循环 # if len(min_price_list) <= 0: # self.detail_logger.debug(f'商品id:{datalist[k]["id"]} 筛选不满足条件,继续下次循环') # continue # # 向BUFF选品日志标签页中添加一条数据 # timestamp = time.time() # local_time = time.localtime(timestamp) # formatted_time = time.strftime('%Y-%m-%d %H:%M:%S', local_time) # self.detail_logger.debug(f'商品id:{datalist[k]["id"]} 筛选成功, 磨损及价格区间min_price_list:', # min_price_list) # # 向BUFF选品日志标签页中增加记录 发出信号而不是直接调用 add_select_log # self.log_added.emit(str(datalist[k]["id"]), str(datalist[k]["name"]), # str(min_price_list[0]['min_wear']), # str(min_price_list[-1]['max_wear']), str(min_price), str(gm_price), # str(pd_price), str(formatted_time)) # # conn = sqlite3.connect('buff.db') # cursor = conn.cursor() # cursor.execute(''' # INSERT INTO select_logs (item_id, item_name, min_wear, max_wear, min_full_wear_price, sweep_price, judge_price, timestamp) # VALUES (?, ?, ?, ?, ?, ?, ?, ?) # ''', (datalist[k]["id"], datalist[k]["name"], min_price_list[0]['min_wear'], min_price_list[-1]['max_wear'], min_price, gm_price, pd_price, formatted_time)) # # # 提交更改并关闭连接 # conn.commit() # conn.close() # # 检索成功数量+1 # self.search_success_count += 1 # if not first_flag: # j += 1 # if first_flag: # if int(data['total_page']) < int(self.max_page): # pagenum = data['total_page'] # else: # pagenum = self.max_page # j = 1 # first_flag = False # except Exception as e: # self.detail_logger.debug('选品接口1请求--失败', e) # j = 1 # pagenum = 0 # finally: # # self.last_goodsinfo_request_time = time.time() # 更新上次请求时间为当前时间 # pass # except Exception as e: # self.detail_logger.debug('选品接口2请求--失败', e) # except Exception as e: # self.detail_logger.debug('选品接口3请求--失败', e) # finally: # # 扫货self.button_sh 和停止扫货self.button_stop_sh按钮不可点击 # self.button_sh.setEnabled(True) # self.button_stop_sh.setEnabled(True) # self.detail_logger.debug('停止选品')