From 7151f6b5e05335f43661b1340bd0d94d0204467d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=93=AD=E5=9D=A4?= <10372463+ming-kun@user.noreply.gitee.com> Date: Wed, 8 Apr 2026 16:03:48 +0800 Subject: [PATCH] modified: amazon/__pycache__/approve.cpython-39.pyc modified: amazon/__pycache__/del_brand.cpython-39.pyc modified: amazon/__pycache__/main.cpython-39.pyc modified: amazon/approve.py new file: amazon/backend_api.py modified: amazon/del_brand.py modified: amazon/main.py modified: blueprints/main.py modified: main.py --- app/amazon/__pycache__/approve.cpython-39.pyc | Bin 20948 -> 23960 bytes .../__pycache__/del_brand.cpython-39.pyc | Bin 15117 -> 16832 bytes app/amazon/__pycache__/main.cpython-39.pyc | Bin 16455 -> 16348 bytes app/amazon/approve.py | 128 +++++++++++++++--- app/amazon/backend_api.py | 0 app/amazon/del_brand.py | 71 ++++++++-- app/amazon/main.py | 33 ++++- app/blueprints/main.py | 5 +- app/main.py | 39 +++++- 9 files changed, 231 insertions(+), 45 deletions(-) create mode 100644 app/amazon/backend_api.py diff --git a/app/amazon/__pycache__/approve.cpython-39.pyc b/app/amazon/__pycache__/approve.cpython-39.pyc index c2be601735097b1a73678b19b95282efa926c241..d43ad6eebf9f377bb450ae5f9543199412e10b16 100644 GIT binary patch delta 8685 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 YgZc_;E?-he3Y)#y;$M?~=I-|Y1Ng-0uK)l5 delta 5810 zcmb7IeQZ?Mm4ElWH{YKge_+qpX8g@yAl?KparkP&NApoaOaf(qAn<*FjTz(TF~r_C z46SJb1QUmwCT(M@<0cdmB@Kz&CMC4#A8A#ss?}EARZ};rR#9w>w5weyn`)~?+x?yU z9>$a)b#2X=_s+fdoO91P_x#SCZ@tg{`4tx46AJki{Jr#x-*%oDem-2u_C4RcCBISO zZtgjuaF5|1($Yb^d$|wqz9BUoGQ!+{P#t0BULN2<9^&CqEgj*Jbd*QaMMi)Z4Kbz| zK_fE6(lH}eC^n+wEM0=9Qlkh@Wq6u5t}uni(&a`4FCJp+lwDiX@xgK<)|D{w<-BB= zr7O2#$_VSlckhR~VpNT=fpVs#tC=!bZOk{SrJ7h*vQR_9wkg{c&eGL8s(U}Qzgv_R ztTbwk$|1&;gF2aP%;%-{xv$*j-#SZ+KbO76_KH{L{WPD}6(tLE zND5bT%wk+SsGH?n*`ioV7wb~F&RyI+tmf3LW~nex#dy1=aW2k>+f+p1^sMwUN4k=SPyBqIJsrC!hwy+EDA)=~$sCVZUS6?J z-AbnTpd{`n2|`IwDxvIrZ&pddR?>TUmQ!iZ#P+Jj;28KgK|aD_O2rYjE1e5raWLk738yV3C7Kn!uixg1*5H5IS@FNp(Hhs1bQvA9+hpLnSHoO<^X@RL`+b7EQyfBMtWYh&M= z9{b?a_uiZyeSP}W&#>~^@l)5vfASw!&dj_!G4sJQOO`B|_(Sqvn9E#;g%g)*E0|~D zQ-}9t544Hj)cv@rzYOf@H(!|=y?FJ5_pgor2rH-FeFx9Ueh;Yv3o^tr^+W7o5oq{# z_MrH4!;VE)FxK}^APVy`UBgF>vLGvAevQ7PER6RUi>ZDV6vrDIJuD2S%EX1nW1_C9 z6T*g@YM5WV)pSq(1&A?}G%8hEMg78YMhTEbf_p|?X`NRYF76v;+|L6iTxmD2Hav!h zhelN%<`Hnb7>{DSh{sOoX`kUT{6+vXibr)`!b`ym8X>F!58Sd*7miywxM4mYyabr? zKf>dqZl2(k5Eqb(J|cd#ymEnVx=Fs4 z={Y*-?aP|`vYm$vGX-ACWvl8WeO;ocwJDrKI`z?f#S>&<@lfl%-ajH;M%2Nyc((O( z<`!RDal}1%HwuzZMD8u!Ua<R)OQ{Qb5aE6-`+Q(CGaW4x1m)a-Au;0H9?pk8)pk zAQ!|+#%nD z-e75v)i|b6EzeZ*rY{^{V2`5=Skf|e;3LPfy|-AFvh`C@=k;yUC=F^q#H6Bb?U0`H zz)a2Z9Dz^3U3gQOy&31dS?p-5Vv8mQ+IBJbKJxED@$r3cu_1A0<%XI;Fc6CaJ%=~# zIb?iJXBLO->UYmiU4H4BxNLTd&sNr`W=t#5CCv|a36wKqEHGEB3_Oob=4 z{YKV2EPlNzQF4gHXGo;a$n+z&d$Pv4)veXN#5alW$?oYpxVw{^Sz`4QIU=4|onq%i zes$7)l7gNU=T|=>K3o0eB`?lSqQhez0qJmo-1v*)fj$r5)7L0E*9?16+iP?F!5@q3 zYijeBpBDpl|5ZjBa0VRk+U)_p%Oo!N0Ce+cq?2GTaGvpU%iYP&1D$L)=De1-5VBk- z>p?3B+*x7;dBs6ZK2Zk6Ef>XzWH=4YrA(RBxG`Y`W%xW4J?_nU5%kRndKl^WB7z=5 zIxd$}E3*+RWFt7QnoYoPA&La75?9tXuO~x8q@?$>gnyJNYqw5Q&Rz>*9*VVXwWFs_ zH0Bf-4}4PoG_u=#24phO(R1kVp3DH9Rr9Dgux@GTQ{Zo!40iOJrjg0+ zrjv{V{`R`V51z!x=X6?<({GHYBs%xkNd2Ay&LY!mzrlWWF97>5uwU%&ejVP?X+SN>YH97 zjYOJ=5F(jAkV#+9VIyO2u$7ok5D_#IIc)ZH0G4)l^z>)4=74#QxPikxec9cn(bwOd z74tTR?~2+O^94o4e2EqW9q;bWkbD1LJiak`pH#n+G_4>a1!JC619jXmX>NLliW|ym%_Zb6g9upjO7>!u#a| z`3ofPbt1C*k&Si6zD}uKt4*;*&!BD6fHe3d9BF zO(Hbrk>dQEq3BM_nPK7#mRqa~mmGNxy#*htiY%6yHUhwbPjNa3nCW!rJd(w=fGS}g zxF>6cy!aL60>=UwTwmy$E`Am(1T6@nD+)?mR4$H@VYk%c?_^5kNU=1z1SQRpDGL|% z1;-urYvH+~?vU&YbY5!Z$x&rDtQpe*6R18U48R;lU6${6FwT!FOrTsjsF+)`v}0U% zP`S5~seK>MF{na%E{;lVOV=#BQh#K*^D-6*+06v(ZiW|aQBa0iA!1*_;I2x?m05Bn z%J4pCH|bk;Q#HE{^^3QGqDzWZbF-5J30I!lC`a+lU6KhmgRmcU?M8;|`WX4KRPL?% zw#={-jdewFH=RGsav=$oT5mh5aY34{4LstQ{{Ro)NG>`n^tvsypz#Lo1ypP1bt$e< zLUq%PyarV3y)$xTfrQ?a6~&%)$`VJG4g({Oi3`!W+GoCbZk}0DzUW|{ZihRa;l*=@ zGfOdH3H+d&))$VKINZDDu9E!&p*xBX42U}YgB>n?;1ehMb`@yJ2J%iv?quwo$jl9l z)_Vmh^tg<2Ep2tv4LzGM{wzbIW0z6V1Er44@dN?wM%Ww2ZL< zvG373arV)B;C|HY^+X7f%~A22N88v_BDi^v`!q2g5q+Ciuw&wl&7ZjmMa>i9{9{|< z$LVo1k*^WiMC9v4#zm}sS+c}@j$Q~$3Ak)P>dfrxae!8Ix36&%T$w_=-Cn-qRXnDO zYy`X$u>6%Y34<3&LAdW|XSU0NdlbOFT$ zX6yFW`a7FMbKWQNL-F?Zq?_Dgz9xRRz1B^h{k1Covi)>uQ;L}f@S0*9Qbl4cU9t8p zyiMx7vm zgo=(r{{N4Aanu(JgdZ#ED$6T=v1!K|_FZvy$HF3WjAYS|F80qcZ;D^-cr4UtcU8^A zJ|`M?HnZnM`_8-8QFCSPC9<1{?0959xn!`#Ez#Z-_@9;E|U5mFAK^aP@-xyujG}LVWN3uyEw3`<^KRJiPCTY diff --git a/app/amazon/__pycache__/del_brand.cpython-39.pyc b/app/amazon/__pycache__/del_brand.cpython-39.pyc index 0bfbfd5e0132d822d968704f6142e04876613925..34d421208ad9d10e39249c24006283b24427220f 100644 GIT binary patch delta 5183 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 diff --git a/app/amazon/approve.py b/app/amazon/approve.py index dc9d839..5efc458 100644 --- a/app/amazon/approve.py +++ b/app/amazon/approve.py @@ -7,6 +7,12 @@ from config import runing_task, runing_shop from datetime import datetime from amazon.del_brand import AmamzonBase, kill_process +# 导入 webview 用于前端通知 +try: + import webview +except ImportError: + webview = None + class AmzoneApprove(AmamzonBase): def SwitchPage(self): @@ -190,8 +196,8 @@ class AmzoneApprove(AmamzonBase): num = 0 while 1: - if num > 3: #测试 - return + # if num > 3: #测试 + # return # 等待加载完成 load_ele = self.tab.eles("xpath://div[contains(@class,'Loader-module__loader')]",timeout=5) if len(load_ele) > 0: @@ -202,14 +208,17 @@ class AmzoneApprove(AmamzonBase): page_pamel = self.tab.eles('xpath://kat-pagination',timeout=5) if len(page_pamel) > 0: current_page = page_pamel[0].sr('xpath:.//ul[@class="pages"]//li[@aria-current="true"]').text - print(f"开始处理,当前页码: {current_page}") + print(f"【current_page】开始处理,当前页码: {current_page}") - sku_ls = self.tab.eles("xpath://div[@data-sku]",timeout=3) + sku_ls = self.tab.eles("xpath://div[@data-sku]",timeout=10) print(f"获取到 {len(sku_ls)}") - for sku_ele in sku_ls[0:2]: + # for sku_ele in sku_ls[0:2]: + for sku_ele in sku_ls: # solve_problem = sku_ele.eles('xpath:.//kat-link[@label="解决商品信息问题"]') - solve_problem = sku_ele.eles('xpath:.//kat-link[@label="解决商品信息问题"]|.//kat-link[@label="修复被禁止显示的商品"]|//kat-link[@label="解决商品移除风险"]') + solve_problem = sku_ele.eles('xpath:.//kat-link[@label="解决商品信息问题"]|.//kat-link[@label="修复被禁止显示的商品"]|.//kat-link[@label="解决商品移除风险"]') if len(solve_problem) == 0: + print(f"{asin},没有处理入口,不处理") + yield (asin,"没有处理入口,不处理") continue asin = sku_ele.ele('xpath:.//div[contains(@class,"JanusSplitBox-module__container")]//div[contains(@class,"JanusSplitBox-module__panel--") and contains(string(.),"ASIN")]/..//div[last()]').text print(f"ASIN {asin} 存在问题,正在点击解决...") @@ -235,9 +244,9 @@ class AmzoneApprove(AmamzonBase): # 解决商品信息违规问题 按钮 kat_box_ls = action_panel.eles('xpath:.//kat-box[@variant="white"]',timeout=5) - if len(kat_box_ls) == 0: - print(f"ASIN {asin} 的操作面板中未找到选项,跳过...") - continue + # if len(kat_box_ls) == 0: + # print(f"ASIN {asin} 的操作面板中未找到选项,跳过...") + # continue print(f"ASIN {asin}需要处理的有:{len(kat_box_ls)}个问题.") # 解决商品信息违规问题 按钮,有多少个都要处理 for i in range(len(kat_box_ls)): @@ -284,7 +293,7 @@ class AmzoneApprove(AmamzonBase): kat_box_ls = action_panel.eles('xpath:.//kat-box[@variant="white"]', timeout=5) # 修复商品信息 - repair_product = action_panel.eles('xpath://kat-button[@class="action-button"]',timeout=5) + repair_product = action_panel.eles('xpath:.//kat-button[@class="action-button"]',timeout=5) if len(repair_product) > 0: print(f"ASIN {asin} 存在修复商品信息按钮,正在点击...") self.clear_tab() @@ -316,7 +325,7 @@ class AmzoneApprove(AmamzonBase): break next_page_btn.click() num += 1 - print(f"正在翻页,已翻 {num} 页...") + # print(f"正在翻页,已翻 {num} 页...") class ApproveTask: @@ -330,6 +339,75 @@ class ApproveTask: "UK": "英国" } + @staticmethod + def show_notification(message: str, message_type: str = "error"): + """显示 pywebview 顶层通知(5秒后自动消失) + + Args: + message: 通知消息 + message_type: 消息类型 (success/warning/error/info) + """ + if webview and webview.windows: + try: + # 转义单引号,防止 JavaScript 语法错误 + safe_message = message.replace("'", "\\'").replace('"', '\\"').replace('\n', '\\n') + + # 设置通知样式颜色 + color_map = { + 'success': '#67C23A', + 'warning': '#E6A23C', + 'error': '#F56C6C', + 'info': '#909399' + } + bg_color = color_map.get(message_type, '#F56C6C') + + # 构建前端通知的 JavaScript 代码 - 创建原生 HTML 通知 + js_code = f""" + (function() {{ + // 移除已存在的通知 + var existingNotif = document.getElementById('pywebview-notification'); + if (existingNotif) {{ + existingNotif.remove(); + }} + + // 创建通知容器 + var notif = document.createElement('div'); + notif.id = 'pywebview-notification'; + notif.style.cssText = 'position: fixed; top: 20px; left: 50%; transform: translateX(-50%); ' + + 'background: {bg_color}; color: white; padding: 12px 20px; border-radius: 4px; ' + + 'box-shadow: 0 2px 12px rgba(0,0,0,0.3); z-index: 99999; font-size: 14px; ' + + 'max-width: 600px; word-wrap: break-word; display: flex; align-items: center; gap: 10px;'; + + // 添加消息内容 + var msgSpan = document.createElement('span'); + msgSpan.textContent = '{safe_message}'; + notif.appendChild(msgSpan); + + // 添加关闭按钮 + var closeBtn = document.createElement('span'); + closeBtn.innerHTML = '×'; + closeBtn.style.cssText = 'cursor: pointer; font-size: 18px; font-weight: bold; margin-left: 10px;'; + closeBtn.onclick = function() {{ notif.remove(); }}; + notif.appendChild(closeBtn); + + // 添加到页面 + document.body.appendChild(notif); + + // 5秒后自动消失 + setTimeout(function() {{ + if (notif && notif.parentNode) {{ + notif.style.transition = 'opacity 0.3s'; + notif.style.opacity = '0'; + setTimeout(function() {{ notif.remove(); }}, 300); + }} + }}, 5000); + }})(); + """ + # 在第一个窗口中执行 JavaScript + webview.windows[0].evaluate_js(js_code) + except Exception as e: + print(f"显示通知失败: {str(e)}") + """ 处理流程: 1、解析任务json,提取对应的companyName 组组装user_info实例化 AmzoneApprove @@ -385,6 +463,8 @@ class ApproveTask: """ from datetime import datetime timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + if level == "ERROR": + self.show_notification(message, "error") print(f"[{timestamp}] [ApproveTask] [{level}] {message}") def process_task(self, task_data: dict): @@ -439,6 +519,7 @@ class ApproveTask: shop_name = shop_item.get("shopName", "未知店铺") self.log(f"[{idx}/{len(items)}] 开始处理店铺: {shop_name}") + self.show_notification(f"开始处理店铺: {shop_name}", "info") try: self.process_shop(shop_item, country_codes, task_id,risk_listing_filter) @@ -502,11 +583,11 @@ class ApproveTask: self.log(f"尝试打开店铺 {shop_name} (第 {retry + 1}/{max_retries} 次)") # 如果不是第一次尝试,先杀进程 - if retry > 0: - self.log("重试前先杀掉浏览器进程...") - kill_process("v6") - kill_process("v5") - time.sleep(2) + # if retry > 0: + # self.log("重试前先杀掉浏览器进程...") + # kill_process("v6") + # kill_process("v5") + # time.sleep(2) # 组装用户信息并创建驱动 user_info = { @@ -522,7 +603,8 @@ class ApproveTask: else: self.log(f"打开店铺失败: {browser}", "WARNING") driver = None - + # 判断是否需要登录 + except Exception as e: import traceback self.log(f"打开店铺异常: {str(e)}", "ERROR") @@ -535,7 +617,8 @@ class ApproveTask: # 检查是否成功打开 if not driver or not browser or browser == "店铺不存在": - self.log(f"店铺 {shop_name} 打开失败,已重试 {max_retries} 次,跳过该店铺", "ERROR") + error_msg = f"店铺 {shop_name} 打开失败,已重试 {max_retries} 次,跳过该店铺" + self.log(error_msg, "ERROR") # 从执行列表中移除 if shop_name in runing_shop: del runing_shop[shop_name] @@ -589,7 +672,9 @@ class ApproveTask: # 转换国家代码为中文名称 country_name = self.country_info.get(country_code, country_code) - self.log(f"开始处理国家: {country_name} ({country_code})") + info_mes = f"开始处理国家: {country_name} ({country_code})" + self.log(info_mes) + self.show_notification(info_mes, "info") # 更新当前处理的国家 if task_id in runing_task: @@ -630,7 +715,8 @@ class ApproveTask: # 如果切换失败,直接返回 if not switch_success: - self.log(f"切换到国家 {country_name} 失败,已重试 {max_retries} 次,跳过该国家", "ERROR") + error_message = f"切换到国家 {country_name} 失败,已重试 {max_retries} 次,跳过该国家" + self.log(error_message, "ERROR") if task_id in runing_task: runing_task[task_id]["processed_countries"] += 1 return @@ -819,3 +905,5 @@ if __name__ == '__main__': print(f"ASIN {asin} 的处理结果: {status}") print("已完成操作") + # for i in range(0): + # print(i) \ No newline at end of file diff --git a/app/amazon/backend_api.py b/app/amazon/backend_api.py new file mode 100644 index 0000000..e69de29 diff --git a/app/amazon/del_brand.py b/app/amazon/del_brand.py index 301062c..0ff25f6 100644 --- a/app/amazon/del_brand.py +++ b/app/amazon/del_brand.py @@ -10,6 +10,7 @@ import os from typing import Literal from DrissionPage import Chromium from DrissionPage.common import By +from DrissionPage._pages.chromium_tab import ChromiumTab def kill_process(version: Literal["v5", "v6"]): @@ -33,7 +34,7 @@ class ZiniaoDriver: self.socket_port = socket_port self.client_path = None self.browser = None - self.tab = None + self.tab: ChromiumTab = None self.store_id = None def get_zinaio_exe(self, protocol_name: str = "superbrowser"): @@ -136,11 +137,11 @@ class ZiniaoDriver: print(r) return r.get("browserList") elif str(r.get("statusCode")) == "-10003": - print(f"login Err {json.dumps(r, ensure_ascii=False)}") - exit() + print(f"【get_browser_list】登录失败 {json.dumps(r, ensure_ascii=False)}") + # exit() else: - print(f"Fail {json.dumps(r, ensure_ascii=False)} ") - exit() + print(f"【get_browser_list】失败 {json.dumps(r, ensure_ascii=False)} ") + # exit() def open_store(self, store_info, isWebDriverReadOnlyMode=0, isprivacy=0, isHeadless=0, cookieTypeSave=0, jsInfo=""): @@ -188,11 +189,11 @@ class ZiniaoDriver: if str(r.get("statusCode")) == "0": return r elif str(r.get("statusCode")) == "-10003": - print(f"login Err {json.dumps(r, ensure_ascii=False)}") - exit() + raise RuntimeError(f"【open_store】登录失败 {json.dumps(r, ensure_ascii=False)}") + # exit() else: - print(f"Fail {json.dumps(r, ensure_ascii=False)} ") - exit() + raise RuntimeError(f"【open_store】失败 {json.dumps(r, ensure_ascii=False)} ") + # exit() def get_browser(self, port) -> Chromium: """ @@ -209,6 +210,17 @@ class ZiniaoDriver: def start_client(self): """启动紫鸟客户端""" + + # 检查端口是否已经启动 + try: + url = f'http://127.0.0.1:{self.socket_port}' + response = requests.get(url, timeout=2) + print(f"端口 {self.socket_port} 已经启动,跳过启动客户端操作") + return + except (requests.exceptions.ConnectionError, requests.exceptions.Timeout): + # 端口未启动,继续执行启动操作 + print(f"端口 {self.socket_port} 未启动,开始启动客户端") + self.client_path = self.get_zinaio_exe("superbrowserv6").strip('"') print(self.client_path) cmd = [self.client_path, '--run_type=web_driver', '--ipc_type=http', @@ -261,7 +273,8 @@ class ZiniaoDriver: print("ip检测页地址为空,请升级紫鸟浏览器到最新版") print(f"=====关闭店铺:{shop_name}=====") self.close_store(self.store_id) - exit() + # exit() + raise RuntimeError("没有IP检测地址,为了店铺安全不打开店铺") ip_usable = self.open_ip_check(self.browser, ip_check_url) if ip_usable: print("ip检测通过,打开店铺平台主页") @@ -298,11 +311,11 @@ class ZiniaoDriver: if str(r.get("statusCode")) == "0": return r elif str(r.get("statusCode")) == "-10003": - print(f"login Err {json.dumps(r, ensure_ascii=False)}") - exit() + raise RuntimeError(f"【close_store】登录失败 {json.dumps(r, ensure_ascii=False)}") + # exit() else: - print(f"Fail {json.dumps(r, ensure_ascii=False)} ") - exit() + raise RuntimeError(f"【close_store】失败: {json.dumps(r, ensure_ascii=False)} ") + # exit() def open_launcher_page(self, launcher_page: str, browser: Chromium = None): """ @@ -436,8 +449,38 @@ class AmamzonBase(ZiniaoDriver): print(f"切换国家时发生异常:{traceback.format_exc()}") return False + def need_login(self): + """ + 判断是否需要登录,部分国家可能需要登录后才能切换国家 + 处理流程: + """ + need_login_ele = self.tab.eles('xpath://h1[@class="a-spacing-small"]',timeout=5) + if len(need_login_ele) >0: + print("检测到需要登录元素") + return True + return False + + def login(self,password,username=""): + try: + pwd_input = self.tab.ele('xpath://input[@type="password"]',timeout=10) + pwd_input.input(password) + submit_btn = self.tab.ele('xpath://input[@id="signInSubmit"]',timeout=10) + submit_btn.click() + self.tab.wait.doc_loaded() + opt_code_input = self.tab.ele('xpath://input[@name="otpCode"]',timeout=10) + opt_code_input.wait.displayed(timeout=10,raise_err=False) + for _ in range(30): + if opt_code_input.value is not None and opt_code_input.value.strip() != "": + print("检测到验证码输入完成") + submit_btn = self.tab.ele('xpath://input[@id="auth-signin-button"]',timeout=10) + submit_btn.click() + self.tab.wait.doc_loaded() + return True + except Exception as e: + print("登录过程中发生异常:" + traceback.format_exc()) + return False class AmazoneDriver(AmamzonBase): """亚马逊专用驱动类,继承自ZiniaoDriver""" diff --git a/app/amazon/main.py b/app/amazon/main.py index 5314d3b..af45cf2 100644 --- a/app/amazon/main.py +++ b/app/amazon/main.py @@ -78,7 +78,7 @@ class TaskMonitor: except Exception as e: # 静默处理队列为空的超时,只记录真正的异常 - if "Empty" not in str(e): + if str(e) and "Empty" not in str(e): self.log(f"任务监控异常: {str(e)}", "ERROR") # 队列为空时不需要额外等待,直接继续循环 @@ -210,11 +210,11 @@ class TaskMonitor: self.log(f"尝试打开店铺 {shop_name} (第 {retry + 1}/{max_retries} 次)") # 如果不是第一次尝试,先杀进程 - if retry > 0: - self.log("重试前先杀掉浏览器进程...") - kill_process("v6") - kill_process("v5") - time.sleep(2) + # if retry > 0: + # self.log("重试前先杀掉浏览器进程...") + # kill_process("v6") + # kill_process("v5") + # time.sleep(2) # 创建驱动并打开店铺 user_info = { @@ -230,6 +230,27 @@ class TaskMonitor: else: self.log(f"打开店铺失败: {browser}", "WARNING") driver = None + + # 判断是否需要登录 + # need_login = driver.need_login() + # if need_login: + # self.log(f"店铺 {shop_name} 需要登录,正在登录...") + # password = "" + + # login_success = driver.login(password) + # if login_success: + # self.log(f"店铺 {shop_name} 登录成功,正在重新打开店铺...") + # browser = driver.open_shop(shop_name) + # if browser and browser != "店铺不存在": + # self.log(f"成功打开店铺 {shop_name} 登录后") + # break + # else: + # self.log(f"登录后打开店铺失败: {browser}", "WARNING") + # driver = None + # else: + # self.log(f"店铺 {shop_name} 登录失败", "WARNING") + # driver = None + except Exception as e: self.log(f"打开店铺异常: {str(e)}", "ERROR") diff --git a/app/blueprints/main.py b/app/blueprints/main.py index 82e5ce5..619f126 100644 --- a/app/blueprints/main.py +++ b/app/blueprints/main.py @@ -110,7 +110,10 @@ def proxy(path): if key.lower() in ['host', 'content-length', 'connection']: continue headers[key] = value - ignore_url = [f"{JAVA_API_BASE}/api/delete-brand/tasks/batch",f"{JAVA_API_BASE}/api/delete-brand/history"] + ignore_url = [f"{JAVA_API_BASE}/api/delete-brand/tasks/batch", + f"{JAVA_API_BASE}/api/delete-brand/history", + f"{JAVA_API_BASE}/api/product-risk-resolve/tasks/batch", + ] if target_url not in ignore_url: try: print("=============================") diff --git a/app/main.py b/app/main.py index 3bfc7d0..7a76502 100644 --- a/app/main.py +++ b/app/main.py @@ -11,7 +11,7 @@ from amazon.main import TaskMonitor os.makedirs(cache_path,exist_ok=True) if not debug: today = datetime.datetime.now().strftime("%Y_%m_%d") - sys.stdout = open(os.path.join(cache_path,f'{today}.log'), 'a',buffering=1) + sys.stdout = open(os.path.join(cache_path,f'{today}.log'), 'a',buffering=1,encoding='utf-8') sys.stderr = sys.stdout import webview @@ -20,6 +20,9 @@ import time import requests import subprocess +from amazon.del_brand import kill_process + + with open("version.txt","w",encoding="utf-8") as file: file.write(json.dumps({"version":version})) @@ -54,8 +57,15 @@ class WindowAPI: window.events.restored += lambda _: setattr(self, '_is_maximized', False) def close(self): - sys.exit(1) - self._window.destroy() + try: + kill_process('v6') + except Exception as e: + print(f"【退出前】关闭紫鸟浏览器进程异常: {str(e)}") + try: + self._window.destroy() + except: + pass + os._exit(0) # 强制退出整个进程,包括所有线程 def minimize(self): self._window.minimize() @@ -358,6 +368,23 @@ def start_task_monitor(): print(f"[{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 任务监控线程异常退出: {traceback.format_exc()}") +def on_window_closing(): + """窗口关闭事件处理器,执行与 close() 方法相同的清理逻辑""" + # 先关闭窗口,避免看起来卡着 + try: + if webview.windows: + webview.windows[0].destroy() + except: + pass + + # 然后执行清理逻辑 + try: + kill_process('v6') + except Exception as e: + print(f"【退出前】关闭紫鸟浏览器进程异常: {str(e)}") + os._exit(0) # 强制退出整个进程,包括所有线程 + + def main(): if not os.path.exists(cache_path): os.makedirs(cache_path,exist_ok=True) @@ -384,11 +411,15 @@ def main(): frameless=False, easy_drag=True ) + + # 为窗口关闭事件添加处理器 + window.events.closing += on_window_closing + api = WindowAPI(window) window.expose(api.close, api.minimize, api.maximize, api.toggle_maximize, generate_images, api.save_image, api.save_image_to_folder, api.select_folder, api.select_brand_xlsx_files, api.select_brand_folder, api.save_file_from_url, api.save_template_xlsx,api.save_template_zip,api.upload_file_to_java,api.open_external_url,api.enqueue_json,api.get_detail_del,api.save_file_from_url_new) webview.start( - debug=True, + debug=False, storage_path=cache_path, private_mode=False )