yuehua-ziniao-webdriver 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,149 @@
1
+ """紫鸟浏览器自动化 Python SDK
2
+
3
+ 一个用于控制紫鸟浏览器的 Python 库,提供店铺管理、浏览器自动化等功能。
4
+
5
+ 基本使用:
6
+ >>> from yuehua_ziniao_webdriver import ZiniaoClient, ZiniaoConfig
7
+ >>>
8
+ >>> config = ZiniaoConfig(
9
+ ... client_path=r"D:\ziniao\ziniao.exe",
10
+ ... company="企业名",
11
+ ... username="用户名",
12
+ ... password="密码"
13
+ ... )
14
+ >>>
15
+ >>> with ZiniaoClient(config) as client:
16
+ ... # 通过名称打开店铺
17
+ ... session = client.open_store_by_name("我的店铺")
18
+ ... if session.check_ip():
19
+ ... tab = session.get_tab()
20
+ ... tab.get("https://example.com")
21
+ """
22
+
23
+ __version__ = "0.1.0"
24
+ __author__ = "Yuehua"
25
+ __email__ = "shengxi_2000@outlook.com"
26
+
27
+ # ============================================================================
28
+ # 核心类(推荐使用)
29
+ # ============================================================================
30
+
31
+ from .client import ZiniaoClient
32
+ from .config import ZiniaoConfig
33
+ from .browser import BrowserSession
34
+
35
+ # ============================================================================
36
+ # 异常类
37
+ # ============================================================================
38
+
39
+ from .exceptions import (
40
+ ZiniaoError,
41
+ ConfigurationError,
42
+ AuthenticationError,
43
+ ClientNotStartedError,
44
+ BrowserStartError,
45
+ ProcessError,
46
+ CommunicationError,
47
+ TimeoutError,
48
+ StoreError,
49
+ StoreNotFoundError,
50
+ MultipleStoresFoundError,
51
+ StoreOperationError,
52
+ IPCheckError,
53
+ CoreUpdateError,
54
+ UnsupportedVersionError,
55
+ )
56
+
57
+ # ============================================================================
58
+ # 类型定义
59
+ # ============================================================================
60
+
61
+ from .types import (
62
+ Store,
63
+ StoreInfo,
64
+ BrowserStartResult,
65
+ StoreOpenOptions,
66
+ VersionType,
67
+ PlatformType,
68
+ )
69
+
70
+ # ============================================================================
71
+ # 工具函数
72
+ # ============================================================================
73
+
74
+ from .utils import (
75
+ get_platform,
76
+ is_windows,
77
+ is_mac,
78
+ is_linux,
79
+ delete_cache,
80
+ get_cache_size,
81
+ format_bytes,
82
+ setup_logging,
83
+ )
84
+
85
+ # ============================================================================
86
+ # 向后兼容的低层 API(高级用户)
87
+ # ============================================================================
88
+
89
+ from .http_client import HttpClient
90
+ from .process import ProcessManager
91
+ from .store import StoreManager
92
+ from .browser import get_browser
93
+
94
+ # ============================================================================
95
+ # 导出列表
96
+ # ============================================================================
97
+
98
+ __all__ = [
99
+ # 版本信息
100
+ "__version__",
101
+ "__author__",
102
+ "__email__",
103
+
104
+ # 核心类
105
+ "ZiniaoClient",
106
+ "ZiniaoConfig",
107
+ "BrowserSession",
108
+
109
+ # 异常类
110
+ "ZiniaoError",
111
+ "ConfigurationError",
112
+ "AuthenticationError",
113
+ "ClientNotStartedError",
114
+ "BrowserStartError",
115
+ "ProcessError",
116
+ "CommunicationError",
117
+ "TimeoutError",
118
+ "StoreError",
119
+ "StoreNotFoundError",
120
+ "MultipleStoresFoundError",
121
+ "StoreOperationError",
122
+ "IPCheckError",
123
+ "CoreUpdateError",
124
+ "UnsupportedVersionError",
125
+
126
+ # 类型定义
127
+ "Store",
128
+ "StoreInfo",
129
+ "BrowserStartResult",
130
+ "StoreOpenOptions",
131
+ "VersionType",
132
+ "PlatformType",
133
+
134
+ # 工具函数
135
+ "get_platform",
136
+ "is_windows",
137
+ "is_mac",
138
+ "is_linux",
139
+ "delete_cache",
140
+ "get_cache_size",
141
+ "format_bytes",
142
+ "setup_logging",
143
+
144
+ # 低层 API
145
+ "HttpClient",
146
+ "ProcessManager",
147
+ "StoreManager",
148
+ "get_browser",
149
+ ]
@@ -0,0 +1,258 @@
1
+ """浏览器会话管理模块
2
+
3
+ 提供浏览器会话的管理和操作功能。
4
+ """
5
+
6
+ import time
7
+ import logging
8
+ from typing import Optional, Callable, Any
9
+
10
+ from DrissionPage import Chromium
11
+ from DrissionPage.common import By
12
+
13
+ from .exceptions import IPCheckError, ZiniaoError
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class BrowserSession:
19
+ """浏览器会话类
20
+
21
+ 封装 DrissionPage 的 Chromium 对象,提供便捷的操作接口。
22
+ """
23
+
24
+ def __init__(
25
+ self,
26
+ port: int,
27
+ store_id: str,
28
+ store_name: str,
29
+ ip_check_url: Optional[str] = None,
30
+ launcher_page: Optional[str] = None,
31
+ close_callback: Optional[Callable[[str], None]] = None
32
+ ) -> None:
33
+ """初始化浏览器会话
34
+
35
+ Args:
36
+ port: 浏览器调试端口
37
+ store_id: 店铺 ID/OAuth
38
+ store_name: 店铺名称
39
+ ip_check_url: IP 检测页面 URL(可选)
40
+ launcher_page: 启动页面 URL(可选)
41
+ close_callback: 关闭回调函数(可选)
42
+ """
43
+ self.port = port
44
+ self.store_id = store_id
45
+ self.store_name = store_name
46
+ self.ip_check_url = ip_check_url
47
+ self.launcher_page = launcher_page
48
+ self.close_callback = close_callback
49
+ self._browser: Optional[Chromium] = None
50
+ self._closed = False
51
+
52
+ logger.debug(
53
+ f"初始化浏览器会话:store={store_name}, "
54
+ f"port={port}, store_id={store_id}"
55
+ )
56
+
57
+ # 创建浏览器实例
58
+ try:
59
+ self._browser = Chromium(port)
60
+ logger.info(f"成功连接到浏览器:{store_name}")
61
+ except Exception as e:
62
+ error_msg = f"连接到浏览器失败:{e}"
63
+ logger.error(error_msg)
64
+ raise ZiniaoError(error_msg, {"port": port, "error": str(e)})
65
+
66
+ @property
67
+ def browser(self) -> Chromium:
68
+ """获取底层的 Chromium 浏览器对象
69
+
70
+ Returns:
71
+ Chromium: DrissionPage 浏览器对象
72
+
73
+ Raises:
74
+ ZiniaoError: 如果会话已关闭
75
+ """
76
+ if self._closed:
77
+ raise ZiniaoError("浏览器会话已关闭")
78
+
79
+ if self._browser is None:
80
+ raise ZiniaoError("浏览器对象未初始化")
81
+
82
+ return self._browser
83
+
84
+ def get_tab(self, index: int = -1):
85
+ """获取标签页
86
+
87
+ Args:
88
+ index: 标签页索引,-1 表示最新的标签页(默认)
89
+
90
+ Returns:
91
+ 标签页对象
92
+ """
93
+ if index == -1:
94
+ return self.browser.latest_tab
95
+ else:
96
+ tabs = self.browser.tabs
97
+ if 0 <= index < len(tabs):
98
+ return tabs[index]
99
+ else:
100
+ raise IndexError(f"标签页索引超出范围:{index}")
101
+
102
+ def check_ip(
103
+ self,
104
+ ip_check_url: Optional[str] = None,
105
+ timeout: int = 60
106
+ ) -> bool:
107
+ """检测 IP 是否可用
108
+
109
+ Args:
110
+ ip_check_url: IP 检测页面 URL,如果为 None 则使用初始化时的 URL
111
+ timeout: 超时时间(秒),默认 60
112
+
113
+ Returns:
114
+ bool: IP 可用返回 True,否则返回 False
115
+ """
116
+ # 确定使用的 URL
117
+ url = ip_check_url or self.ip_check_url
118
+
119
+ if not url:
120
+ logger.warning("IP 检测页面 URL 为空,跳过检测")
121
+ return True
122
+
123
+ try:
124
+ logger.info(f"开始 IP 检测:{self.store_name}")
125
+
126
+ tab = self.get_tab()
127
+ tab.get(url)
128
+
129
+ # 等待成功按钮出现
130
+ success_button = tab.ele(
131
+ (By.XPATH, '//button[contains(@class, "styles_btn--success")]'),
132
+ timeout=timeout
133
+ )
134
+
135
+ if success_button:
136
+ logger.info(f"IP 检测成功:{self.store_name}")
137
+ return True
138
+ else:
139
+ logger.warning(f"IP 检测超时:{self.store_name}")
140
+ return False
141
+
142
+ except Exception as e:
143
+ logger.error(f"IP 检测异常:{self.store_name}, 错误:{e}")
144
+ return False
145
+
146
+ def open_launcher_page(
147
+ self,
148
+ launcher_page: Optional[str] = None,
149
+ wait_time: int = 6
150
+ ) -> None:
151
+ """打开启动页面(店铺平台主页)
152
+
153
+ Args:
154
+ launcher_page: 启动页面 URL,如果为 None 则使用初始化时的 URL
155
+ wait_time: 打开后等待时间(秒),默认 6
156
+
157
+ Raises:
158
+ ZiniaoError: 如果启动页面 URL 为空
159
+ """
160
+ # 确定使用的 URL
161
+ url = launcher_page or self.launcher_page
162
+
163
+ if not url:
164
+ raise ZiniaoError(
165
+ "启动页面 URL 为空",
166
+ {"store_name": self.store_name}
167
+ )
168
+
169
+ try:
170
+ logger.info(f"打开启动页面:{self.store_name} -> {url}")
171
+
172
+ tab = self.get_tab()
173
+ tab.get(url)
174
+
175
+ time.sleep(wait_time)
176
+
177
+ logger.debug(f"启动页面已打开:{self.store_name}")
178
+
179
+ except Exception as e:
180
+ error_msg = f"打开启动页面失败:{e}"
181
+ logger.error(error_msg)
182
+ raise ZiniaoError(
183
+ error_msg,
184
+ {"store_name": self.store_name, "url": url, "error": str(e)}
185
+ )
186
+
187
+ def navigate(self, url: str, wait_time: float = 0) -> None:
188
+ """导航到指定 URL
189
+
190
+ Args:
191
+ url: 目标 URL
192
+ wait_time: 导航后等待时间(秒),默认 0
193
+ """
194
+ logger.debug(f"导航到:{url}")
195
+ tab = self.get_tab()
196
+ tab.get(url)
197
+
198
+ if wait_time > 0:
199
+ time.sleep(wait_time)
200
+
201
+ def close(self) -> None:
202
+ """关闭浏览器会话
203
+
204
+ 会调用初始化时传入的 close_callback 来关闭店铺。
205
+ """
206
+ if self._closed:
207
+ logger.debug(f"浏览器会话已关闭:{self.store_name}")
208
+ return
209
+
210
+ logger.info(f"关闭浏览器会话:{self.store_name}")
211
+
212
+ # 调用关闭回调
213
+ if self.close_callback:
214
+ try:
215
+ self.close_callback(self.store_id)
216
+ logger.debug(f"调用关闭回调成功:{self.store_name}")
217
+ except Exception as e:
218
+ logger.error(f"调用关闭回调失败:{self.store_name}, 错误:{e}")
219
+
220
+ self._closed = True
221
+ self._browser = None
222
+
223
+ def is_closed(self) -> bool:
224
+ """检查会话是否已关闭
225
+
226
+ Returns:
227
+ bool: 已关闭返回 True
228
+ """
229
+ return self._closed
230
+
231
+ def __enter__(self) -> "BrowserSession":
232
+ """上下文管理器入口"""
233
+ return self
234
+
235
+ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
236
+ """上下文管理器退出,自动关闭会话"""
237
+ self.close()
238
+
239
+ def __repr__(self) -> str:
240
+ return (
241
+ f"BrowserSession(store='{self.store_name}', "
242
+ f"port={self.port}, closed={self._closed})"
243
+ )
244
+
245
+
246
+ def get_browser(port: int) -> Chromium:
247
+ """获取 DrissionPage 浏览器对象(原始方式)
248
+
249
+ 这是一个便捷函数,用于向后兼容。
250
+
251
+ Args:
252
+ port: 浏览器调试端口
253
+
254
+ Returns:
255
+ Chromium: DrissionPage 浏览器对象
256
+ """
257
+ logger.debug(f"获取浏览器对象:port={port}")
258
+ return Chromium(port)