qrpa 1.0.50__tar.gz → 1.0.51__tar.gz

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.

Potentially problematic release.


This version of qrpa might be problematic. Click here for more details.

Files changed (36) hide show
  1. {qrpa-1.0.50 → qrpa-1.0.51}/PKG-INFO +1 -1
  2. {qrpa-1.0.50 → qrpa-1.0.51}/pyproject.toml +1 -1
  3. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/shein_lib.py +40 -191
  4. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/shein_ziniao.py +1 -1
  5. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa.egg-info/PKG-INFO +1 -1
  6. {qrpa-1.0.50 → qrpa-1.0.51}/README.md +0 -0
  7. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/RateLimitedSender.py +0 -0
  8. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/__init__.py +0 -0
  9. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/db_migrator.py +0 -0
  10. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/feishu_bot_app.py +0 -0
  11. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/feishu_client.py +0 -0
  12. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/feishu_logic.py +0 -0
  13. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/fun_base.py +0 -0
  14. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/fun_excel.py +0 -0
  15. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/fun_file.py +0 -0
  16. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/fun_web.py +0 -0
  17. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/fun_win.py +0 -0
  18. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/mysql_module/__init__.py +0 -0
  19. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/mysql_module/shein_return_order_model.py +0 -0
  20. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/shein_daily_report_model.py +0 -0
  21. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/shein_excel.py +0 -0
  22. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/shein_mysql.py +0 -0
  23. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/shein_sqlite.py +0 -0
  24. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/temu_chrome.py +0 -0
  25. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/temu_excel.py +0 -0
  26. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/temu_lib.py +0 -0
  27. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/time_utils.py +0 -0
  28. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/time_utils_example.py +0 -0
  29. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa/wxwork.py +0 -0
  30. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa.egg-info/SOURCES.txt +0 -0
  31. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa.egg-info/dependency_links.txt +0 -0
  32. {qrpa-1.0.50 → qrpa-1.0.51}/qrpa.egg-info/top_level.txt +0 -0
  33. {qrpa-1.0.50 → qrpa-1.0.51}/setup.cfg +0 -0
  34. {qrpa-1.0.50 → qrpa-1.0.51}/setup.py +0 -0
  35. {qrpa-1.0.50 → qrpa-1.0.51}/tests/test_db_migrator.py +0 -0
  36. {qrpa-1.0.50 → qrpa-1.0.51}/tests/test_wxwork.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qrpa
3
- Version: 1.0.50
3
+ Version: 1.0.51
4
4
  Summary: qsir's rpa library
5
5
  Author: QSir
6
6
  Author-email: QSir <1171725650@qq.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qrpa"
7
- version = "1.0.50"
7
+ version = "1.0.51"
8
8
  description = "qsir's rpa library"
9
9
  authors = [{ name = "QSir", email = "1171725650@qq.com" }]
10
10
  readme = "README.md"
@@ -8,7 +8,7 @@ from .shein_sqlite import insert_sales, get_last_week_sales, get_near_week_sales
8
8
 
9
9
  import math
10
10
  import time
11
- import json
11
+ import json, traceback
12
12
  from datetime import datetime
13
13
  from playwright.sync_api import Page
14
14
 
@@ -27,179 +27,8 @@ class SheinLib:
27
27
 
28
28
  self.deal_auth()
29
29
 
30
- def deal_auth(self):
31
- """处理登录鉴权流程"""
32
- web_page = self.web_page
33
-
34
- # 配置常量
35
- MAX_RETRIES = 5
36
- CAPTCHA_WAIT_INTERVAL = 5
37
- PAGE_LOAD_TIMEOUT = 5000
38
- SHORT_TIMEOUT = 1000
39
-
40
- # 页面元素选择器 - 集中管理
41
- selectors = {
42
- 'merchant_backend' : '//div[contains(text(),"商家后台")]',
43
- 'auth_confirm_btn' : '//div[@id="container" and @alita-name="gmpsso"]//button[@type="button" and @id]',
44
- 'captcha_text' : '//div[text()="验证码"]',
45
- 'username_input' : '//input[@name="username"]',
46
- 'login_btn' : '//button[contains(@class,"login_btn")]',
47
- 'product_management': '//span[contains(text(),"商品管理")]',
48
- 'auth_title' : '//h1[contains(text(),"鉴权")]'
49
- }
50
-
51
- # URL常量
52
- home_url = 'https://sso.geiwohuo.com/#/home'
53
- base_url = 'https://sso.geiwohuo.com'
54
-
55
- retries = 0
56
- wait_count = 0
57
- is_captcha_notification_sent = False
58
-
59
- log("开始鉴权处理", self.store_username, self.store_name)
60
-
61
- while retries < MAX_RETRIES:
62
- try:
63
- retries += 1
64
- log(f"鉴权处理第{retries}次尝试", self.store_username, self.store_name)
65
-
66
- # 主循环:等待商家后台页面加载
67
- while True:
68
- try:
69
- # 检查商家后台是否已经可见
70
- if web_page.locator(selectors['merchant_backend']).nth(1).is_visible(timeout=SHORT_TIMEOUT):
71
- log('商家后台已可见,鉴权处理完成', self.store_username, self.store_name)
72
- return
73
- except:
74
- pass
75
-
76
- # 1. 处理鉴权确认弹窗
77
- try:
78
- auth_btn = web_page.locator(selectors['auth_confirm_btn']).nth(0)
79
- if auth_btn.is_visible(timeout=SHORT_TIMEOUT):
80
- log("检测到鉴权确认按钮,点击确定", self.store_username, self.store_name)
81
- auth_btn.click()
82
- web_page.wait_for_load_state("load")
83
- web_page.wait_for_timeout(SHORT_TIMEOUT)
84
- continue
85
- except:
86
- pass
87
-
88
- # 2. 处理验证码等待
89
- try:
90
- if web_page.locator(selectors['captcha_text']).is_visible(timeout=SHORT_TIMEOUT):
91
- wait_count += 1
92
- log(f'等待验证码输入: 第{wait_count}次', self.store_username, self.store_name)
93
-
94
- # 只发送一次验证码通知
95
- if not is_captcha_notification_sent:
96
- try:
97
- img_path = full_screen_shot(web_page, self.config)
98
- wx_bot = WxWorkBot(self.config.wxwork_bot_exception)
99
- wx_bot.send_img(img_path)
100
- wx_bot.send_text(f'{self.store_username},{self.store_name} 需要登录验证码')
101
- is_captcha_notification_sent = True
102
- log("验证码通知已发送", self.store_username, self.store_name)
103
- except Exception as notify_error:
104
- log(f"发送验证码通知失败: {notify_error}", self.store_username, self.store_name)
105
-
106
- time.sleep(CAPTCHA_WAIT_INTERVAL)
107
- continue
108
- except:
109
- pass
110
-
111
- # 3. 处理登录按钮点击
112
- try:
113
- if web_page.locator(selectors['username_input']).is_visible(timeout=SHORT_TIMEOUT):
114
- log("检测到用户名输入框,准备点击登录按钮", self.store_username, self.store_name)
115
- web_page.wait_for_timeout(PAGE_LOAD_TIMEOUT)
116
- web_page.locator(selectors['login_btn']).click()
117
- web_page.wait_for_load_state("load")
118
- web_page.wait_for_timeout(PAGE_LOAD_TIMEOUT)
119
- continue
120
- except:
121
- pass
122
-
123
- # 4. 检查商品管理菜单(成功标识)
124
- try:
125
- if web_page.locator(selectors['product_management']).nth(1).is_visible(timeout=SHORT_TIMEOUT):
126
- log('检测到商品管理菜单,鉴权处理成功', self.store_username, self.store_name)
127
- return
128
- except:
129
- pass
130
-
131
- # 5. 获取当前页面信息用于状态判断
132
- current_title = web_page.title()
133
- current_url = web_page.url
134
-
135
- log(f'当前页面状态: {current_title} | {current_url}', self.store_username, self.store_name)
136
-
137
- # 6. 处理已知的成功状态页面
138
- success_titles = ['SHEIN全球商家中心', '后台首页', '商家后台']
139
- if any(title in current_title for title in success_titles) and home_url in current_url:
140
- log(f'检测到目标页面: {current_title},跳出循环', self.store_username, self.store_name)
141
- break
142
-
143
- # 7. 处理需要重定向的页面
144
- if 'mrs.biz.sheincorp.cn' in current_url and '商家后台' in current_title:
145
- log('检测到旧后台地址,重定向到新地址', self.store_username, self.store_name)
146
- web_page.goto(home_url)
147
- web_page.wait_for_load_state("load")
148
- web_page.wait_for_timeout(3000)
149
- continue
150
-
151
- # 8. 处理鉴权页面
152
- try:
153
- if web_page.locator(selectors['auth_title']).is_visible(timeout=SHORT_TIMEOUT):
154
- log('检测到鉴权页面,刷新重试', self.store_username, self.store_name)
155
- web_page.reload()
156
- web_page.wait_for_load_state('load')
157
- web_page.wait_for_timeout(3000)
158
- continue
159
- except:
160
- pass
161
-
162
- # 9. 处理SHEIN主页
163
- if current_title == 'SHEIN':
164
- log('当前在SHEIN主页,跳转到商家后台', self.store_username, self.store_name)
165
- web_page.goto(home_url)
166
- web_page.wait_for_load_state("load")
167
- web_page.wait_for_timeout(3000)
168
- continue
169
-
170
- # 默认等待,然后继续下一轮检查
171
- web_page.wait_for_load_state("load")
172
- web_page.wait_for_timeout(SHORT_TIMEOUT)
173
-
174
- # 如果跳出了内层while循环,说明达到了某种成功状态
175
- log('内层循环结束,鉴权处理完成', self.store_username, self.store_name)
176
- return
177
-
178
- except Exception as e:
179
- error_msg = str(e)
180
- log(f"鉴权处理异常: {error_msg}, 第{retries}次重试", self.store_username, self.store_name)
181
-
182
- # 处理页面崩溃或特定认证错误
183
- if 'crashed' in error_msg.lower() or 'https://sso.geiwohuo.com//#/auth/SSLS' in web_page.url:
184
- log('检测到页面崩溃或认证错误,重新导航到基础URL', self.store_username, self.store_name)
185
- try:
186
- web_page.goto(base_url)
187
- web_page.wait_for_load_state('load')
188
- web_page.wait_for_timeout(3000)
189
- except Exception as nav_error:
190
- log(f'重新导航失败: {nav_error}', self.store_username, self.store_name)
191
-
192
- # 达到最大重试次数
193
- if retries >= MAX_RETRIES:
194
- log(f"达到最大重试次数{MAX_RETRIES},鉴权处理失败", self.store_username, self.store_name)
195
- break
196
-
197
- time.sleep(2) # 异常后等待2秒再重试
198
-
199
- log('鉴权处理结束', self.store_username, self.store_name)
200
-
201
30
  # 处理鉴权
202
- def deal_auth_old(self):
31
+ def deal_auth(self):
203
32
  web_page = self.web_page
204
33
 
205
34
  # 定义最大重试次数
@@ -218,10 +47,11 @@ class SheinLib:
218
47
  while not web_page.locator('//div[contains(text(),"商家后台")]').nth(1).is_visible():
219
48
 
220
49
  if web_page.locator('xpath=//div[@id="container" and @alita-name="gmpsso"]//button[@type="button" and @id]').nth(0).is_visible():
221
- log("鉴权确定按钮可见 点击'确定'按钮", self.store_username, self.store_name)
222
- web_page.locator('xpath=//div[@id="container" and @alita-name="gmpsso"]//button[@type="button" and @id]').nth(0).click()
223
- web_page.wait_for_load_state("load")
224
- web_page.wait_for_timeout(1000)
50
+ if 'https://sso.geiwohuo.com/#/home' not in web_page.url:
51
+ log("鉴权确定按钮可见 点击'确定'按钮", self.store_username, self.store_name)
52
+ web_page.locator('xpath=//div[@id="container" and @alita-name="gmpsso"]//button[@type="button" and @id]').nth(0).click()
53
+ web_page.wait_for_load_state("load")
54
+ web_page.wait_for_timeout(1000)
225
55
 
226
56
  while web_page.locator('//div[text()="验证码"]').is_visible():
227
57
  log(f'等待输入验证码: {wait_count}', self.store_username, self.store_name)
@@ -238,7 +68,7 @@ class SheinLib:
238
68
  web_page.wait_for_timeout(5000)
239
69
  log('点击"登录"', self.store_username, self.store_name)
240
70
  web_page.locator('//button[contains(@class,"login_btn")]').click()
241
- web_page.wait_for_load_state("load")
71
+
242
72
  log('再延时5秒', self.store_username, self.store_name)
243
73
  web_page.wait_for_timeout(5000)
244
74
 
@@ -252,14 +82,26 @@ class SheinLib:
252
82
 
253
83
  if 'SHEIN全球商家中心' in web_page.title() and 'https://sso.geiwohuo.com/#/home' in web_page.url:
254
84
  log('SHEIN全球商家中心 中断循环', self.store_username, self.store_name)
85
+ web_page.wait_for_load_state("load")
86
+ web_page.wait_for_timeout(1000)
87
+ web_page.wait_for_load_state("networkidle")
88
+ web_page.wait_for_timeout(1000)
255
89
  break
256
90
 
257
91
  if '后台首页' in web_page.title() and 'https://sso.geiwohuo.com/#/home' in web_page.url:
258
92
  log('后台首页 中断循环', self.store_username, self.store_name)
93
+ web_page.wait_for_load_state("load")
94
+ web_page.wait_for_timeout(1000)
95
+ web_page.wait_for_load_state("networkidle")
96
+ web_page.wait_for_timeout(1000)
259
97
  break
260
98
 
261
99
  if '商家后台' in web_page.title() and 'https://sso.geiwohuo.com/#/home' in web_page.url:
262
100
  log('后台首页 中断循环', self.store_username, self.store_name)
101
+ web_page.wait_for_load_state("load")
102
+ web_page.wait_for_timeout(1000)
103
+ web_page.wait_for_load_state("networkidle")
104
+ web_page.wait_for_timeout(1000)
263
105
  break
264
106
 
265
107
  if 'mrs.biz.sheincorp.cn' in web_page.url and '商家后台' in web_page.title():
@@ -280,12 +122,14 @@ class SheinLib:
280
122
  web_page.wait_for_load_state("load")
281
123
  web_page.wait_for_timeout(3000)
282
124
 
125
+ break
283
126
  except Exception as e:
284
127
  log(f"错误发生: {e}, 重试中...({self.store_username}, {self.store_name})")
128
+ log(traceback.format_exc())
285
129
  if 'crashed' in str(e) or 'https://sso.geiwohuo.com//#/auth/SSLS' in web_page.url:
286
130
  web_page.goto('https://sso.geiwohuo.com')
287
131
  web_page.wait_for_load_state('load')
288
- web_page.wait_for_timeout(3000)
132
+ web_page.wait_for_timeout(10000)
289
133
  retries += 1
290
134
  if retries >= MAX_RETRIES:
291
135
  log(f"达到最大重试次数,停止尝试({self.store_username}, {self.store_name})")
@@ -293,6 +137,9 @@ class SheinLib:
293
137
  time.sleep(2) # 错误时等待2秒后重试
294
138
 
295
139
  log('鉴权处理结束')
140
+ # web_page.wait_for_load_state("load")
141
+ # web_page.wait_for_load_state("networkidle")
142
+ web_page.wait_for_timeout(3000)
296
143
 
297
144
  # 获取质检报告pdf地址
298
145
  def get_qc_report_url(self, deliverCode, purchaseCode):
@@ -400,27 +247,29 @@ class SheinLib:
400
247
  has_valid_package = item.get('hasPackage') == 1
401
248
  is_valid_yesterday = TimeUtils.is_yesterday(item['completeTime'], None) if item.get('completeTime') else False
402
249
  returnOrderId = item['id']
403
- return_box_detail = self.get_return_order_box_detail(returnOrderId)
250
+ item['return_box_detail'] = []
404
251
  item['qc_report_url'] = ''
405
252
  item['report_url'] = ''
406
253
  item['store_username'] = self.store_username
407
254
  item['store_name'] = self.store_name
408
255
  item['store_manager'] = self.config.shein_store_manager.get(str(self.store_username).lower())
409
- if has_valid_package and len(return_box_detail) > 0:
256
+ if has_valid_package:
257
+ return_box_detail = self.get_return_order_box_detail(returnOrderId)
258
+ if len(return_box_detail) > 0:
410
259
 
411
- if int(item['returnScrapType']) == 1:
412
- purchaseCode = item['sellerOrderNo']
413
- delivery_code = item['sellerDeliveryNo']
414
- item['qc_report_url'] = self.get_qc_report_url(delivery_code, purchaseCode)
260
+ if int(item['returnScrapType']) == 1:
261
+ purchaseCode = item['sellerOrderNo']
262
+ delivery_code = item['sellerDeliveryNo']
263
+ item['qc_report_url'] = self.get_qc_report_url(delivery_code, purchaseCode)
415
264
 
416
- if int(item['returnScrapType']) == 2:
417
- item['report_url'] = self.get_inspect_report_url(returnOrderId)
265
+ if int(item['returnScrapType']) == 2:
266
+ item['report_url'] = self.get_inspect_report_url(returnOrderId)
418
267
 
419
- item['return_box_detail'] = return_box_detail
268
+ item['return_box_detail'] = return_box_detail
420
269
 
421
- all_list_item.append(item)
422
- if is_valid_yesterday:
423
- today_list_item.append(item)
270
+ all_list_item.append(item)
271
+ if is_valid_yesterday:
272
+ today_list_item.append(item)
424
273
 
425
274
  cache_file = f'{self.config.auto_dir}/shein/cache/shein_return_order_list_{TimeUtils.today_date()}.json'
426
275
  write_dict_to_file_ex(cache_file, {self.store_username: today_list_item}, [self.store_username])
@@ -412,7 +412,7 @@ class ZiniaoRunner:
412
412
  raise RuntimeError("店铺列表为空")
413
413
 
414
414
  # 多线程并发执行任务
415
- max_threads = 5 if (hostname().lower() == 'krrpa') else 3
415
+ max_threads = 1 if (hostname().lower() == 'krrpa') else 3
416
416
  log(f'当前启用线程数: {max_threads}')
417
417
  self.task_manager.run_with_thread_pool(browser_list, max_threads, run, task_key, just_store_username, is_skip_store)
418
418
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qrpa
3
- Version: 1.0.50
3
+ Version: 1.0.51
4
4
  Summary: qsir's rpa library
5
5
  Author: QSir
6
6
  Author-email: QSir <1171725650@qq.com>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes