客户唤醒营销工具迭代,不再进行频繁的浏览器关闭
Showing
3 changed files
with
52 additions
and
13 deletions
| ... | @@ -30,16 +30,34 @@ from selenium.common.exceptions import TimeoutException, NoSuchElementException | ... | @@ -30,16 +30,34 @@ from selenium.common.exceptions import TimeoutException, NoSuchElementException |
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | class ChromeController: | 32 | class ChromeController: |
| 33 | """Chrome浏览器控制器""" | 33 | """Chrome浏览器控制器 - 单例模式,全局共享浏览器实例""" |
| 34 | |||
| 35 | _instance = None # 单例实例 | ||
| 36 | |||
| 37 | def __new__(cls): | ||
| 38 | """单例模式: 确保全局只有一个浏览器实例""" | ||
| 39 | if cls._instance is None: | ||
| 40 | cls._instance = super().__new__(cls) | ||
| 41 | return cls._instance | ||
| 34 | 42 | ||
| 35 | def __init__(self): | 43 | def __init__(self): |
| 44 | # 防止重复初始化 | ||
| 45 | if hasattr(self, '_initialized'): | ||
| 46 | return | ||
| 47 | |||
| 36 | self.driver = None | 48 | self.driver = None |
| 37 | self.wait = None | 49 | self.wait = None |
| 38 | self.network_logs = [] | 50 | self.network_logs = [] |
| 39 | self.is_running = False | 51 | self.is_running = False |
| 52 | self._initialized = True | ||
| 40 | 53 | ||
| 41 | def start_browser(self) -> bool: | 54 | def start_browser(self) -> bool: |
| 42 | """启动Chrome浏览器""" | 55 | """启动Chrome浏览器 - 如果已启动则跳过""" |
| 56 | # 如果浏览器已经运行,直接返回成功 | ||
| 57 | if self.is_running and self.driver: | ||
| 58 | print("Chrome浏览器已在运行,复用现有实例") | ||
| 59 | return True | ||
| 60 | |||
| 43 | try: | 61 | try: |
| 44 | if USING_UNDETECTED: | 62 | if USING_UNDETECTED: |
| 45 | # 使用undetected-chromedriver(推荐) | 63 | # 使用undetected-chromedriver(推荐) |
| ... | @@ -84,15 +102,23 @@ class ChromeController: | ... | @@ -84,15 +102,23 @@ class ChromeController: |
| 84 | return False | 102 | return False |
| 85 | 103 | ||
| 86 | def stop_browser(self): | 104 | def stop_browser(self): |
| 87 | """关闭浏览器""" | 105 | """关闭浏览器 - 仅在程序退出时调用""" |
| 88 | try: | 106 | try: |
| 89 | if self.driver: | 107 | if self.driver: |
| 90 | self.driver.quit() | 108 | self.driver.quit() |
| 109 | self.driver = None | ||
| 91 | self.is_running = False | 110 | self.is_running = False |
| 92 | print("Chrome浏览器已关闭") | 111 | print("Chrome浏览器已关闭") |
| 93 | except Exception as e: | 112 | except Exception as e: |
| 94 | print(f"关闭浏览器异常: {e}") | 113 | print(f"关闭浏览器异常: {e}") |
| 95 | 114 | ||
| 115 | def ensure_browser_running(self) -> bool: | ||
| 116 | """确保浏览器正在运行 - 供外部调用""" | ||
| 117 | if not self.is_running or not self.driver: | ||
| 118 | print("检测到浏览器未运行,正在启动...") | ||
| 119 | return self.start_browser() | ||
| 120 | return True | ||
| 121 | |||
| 96 | def navigate_to(self, url: str) -> bool: | 122 | def navigate_to(self, url: str) -> bool: |
| 97 | """导航到指定URL""" | 123 | """导航到指定URL""" |
| 98 | try: | 124 | try: | ... | ... |
| ... | @@ -46,7 +46,8 @@ class EtsyManager: | ... | @@ -46,7 +46,8 @@ class EtsyManager: |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | try: | 48 | try: |
| 49 | if not self.chrome.start_browser(): | 49 | # 确保浏览器运行 |
| 50 | if not self.chrome.ensure_browser_running(): | ||
| 50 | return result | 51 | return result |
| 51 | 52 | ||
| 52 | # 导航到消息页面 | 53 | # 导航到消息页面 |
| ... | @@ -83,15 +84,14 @@ class EtsyManager: | ... | @@ -83,15 +84,14 @@ class EtsyManager: |
| 83 | 84 | ||
| 84 | except Exception as e: | 85 | except Exception as e: |
| 85 | print(f"登录状态检查异常: {e}") | 86 | print(f"登录状态检查异常: {e}") |
| 86 | finally: | ||
| 87 | self.chrome.stop_browser() | ||
| 88 | 87 | ||
| 89 | return result | 88 | return result |
| 90 | 89 | ||
| 91 | def get_user_tags(self) -> Optional[Dict[str, int]]: | 90 | def get_user_tags(self) -> Optional[Dict[str, int]]: |
| 92 | """获取用户标签""" | 91 | """获取用户标签""" |
| 93 | try: | 92 | try: |
| 94 | if not self.chrome.start_browser(): | 93 | # 确保浏览器运行 |
| 94 | if not self.chrome.ensure_browser_running(): | ||
| 95 | return None | 95 | return None |
| 96 | 96 | ||
| 97 | if not self.chrome.navigate_to(self.PAGES["messages"]): | 97 | if not self.chrome.navigate_to(self.PAGES["messages"]): |
| ... | @@ -117,8 +117,6 @@ class EtsyManager: | ... | @@ -117,8 +117,6 @@ class EtsyManager: |
| 117 | 117 | ||
| 118 | except Exception as e: | 118 | except Exception as e: |
| 119 | print(f"获取用户标签异常: {e}") | 119 | print(f"获取用户标签异常: {e}") |
| 120 | finally: | ||
| 121 | self.chrome.stop_browser() | ||
| 122 | 120 | ||
| 123 | return None | 121 | return None |
| 124 | 122 | ||
| ... | @@ -130,7 +128,8 @@ class EtsyManager: | ... | @@ -130,7 +128,8 @@ class EtsyManager: |
| 130 | daily_limit = self.config.get("limits.daily_limit", 100) | 128 | daily_limit = self.config.get("limits.daily_limit", 100) |
| 131 | 129 | ||
| 132 | try: | 130 | try: |
| 133 | if not self.chrome.start_browser(): | 131 | # 确保浏览器运行 |
| 132 | if not self.chrome.ensure_browser_running(): | ||
| 134 | status_callback("浏览器启动失败") | 133 | status_callback("浏览器启动失败") |
| 135 | return | 134 | return |
| 136 | 135 | ||
| ... | @@ -175,7 +174,6 @@ class EtsyManager: | ... | @@ -175,7 +174,6 @@ class EtsyManager: |
| 175 | except Exception as e: | 174 | except Exception as e: |
| 176 | status_callback(f"对话营销异常: {e}") | 175 | status_callback(f"对话营销异常: {e}") |
| 177 | finally: | 176 | finally: |
| 178 | self.chrome.stop_browser() | ||
| 179 | self.is_marketing_active = False | 177 | self.is_marketing_active = False |
| 180 | 178 | ||
| 181 | def start_order_marketing(self, start_date: str, end_date: str, | 179 | def start_order_marketing(self, start_date: str, end_date: str, |
| ... | @@ -185,7 +183,8 @@ class EtsyManager: | ... | @@ -185,7 +183,8 @@ class EtsyManager: |
| 185 | sent_count = 0 | 183 | sent_count = 0 |
| 186 | 184 | ||
| 187 | try: | 185 | try: |
| 188 | if not self.chrome.start_browser(): | 186 | # 确保浏览器运行 |
| 187 | if not self.chrome.ensure_browser_running(): | ||
| 189 | status_callback("浏览器启动失败") | 188 | status_callback("浏览器启动失败") |
| 190 | return | 189 | return |
| 191 | 190 | ||
| ... | @@ -223,7 +222,6 @@ class EtsyManager: | ... | @@ -223,7 +222,6 @@ class EtsyManager: |
| 223 | except Exception as e: | 222 | except Exception as e: |
| 224 | status_callback(f"订单营销异常: {e}") | 223 | status_callback(f"订单营销异常: {e}") |
| 225 | finally: | 224 | finally: |
| 226 | self.chrome.stop_browser() | ||
| 227 | self.is_marketing_active = False | 225 | self.is_marketing_active = False |
| 228 | 226 | ||
| 229 | def stop_marketing(self): | 227 | def stop_marketing(self): | ... | ... |
| ... | @@ -29,6 +29,21 @@ class MainWindow: | ... | @@ -29,6 +29,21 @@ class MainWindow: |
| 29 | self.create_widgets() | 29 | self.create_widgets() |
| 30 | self.load_config_data() | 30 | self.load_config_data() |
| 31 | 31 | ||
| 32 | # 绑定窗口关闭事件 | ||
| 33 | self.root.protocol("WM_DELETE_WINDOW", self.on_closing) | ||
| 34 | |||
| 35 | def on_closing(self): | ||
| 36 | """窗口关闭事件处理""" | ||
| 37 | from ..etsy.chrome_controller import ChromeController | ||
| 38 | |||
| 39 | # 停止浏览器 | ||
| 40 | chrome = ChromeController() | ||
| 41 | if chrome.is_running: | ||
| 42 | chrome.stop_browser() | ||
| 43 | |||
| 44 | # 关闭窗口 | ||
| 45 | self.root.destroy() | ||
| 46 | |||
| 32 | def setup_window(self): | 47 | def setup_window(self): |
| 33 | """设置窗口属性""" | 48 | """设置窗口属性""" |
| 34 | self.root.title("Etsy客户营销工具 v1.0") | 49 | self.root.title("Etsy客户营销工具 v1.0") | ... | ... |
-
Please register or sign in to post a comment