qrpa 1.0.96__py3-none-any.whl → 1.0.98__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.

Potentially problematic release.


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

qrpa/fun_excel.py CHANGED
@@ -2149,6 +2149,7 @@ def add_formula_for_column(sheet, col_name, formula, start_row=2):
2149
2149
  # AutoFill 快速填充到所有行(start_row 到 last_row)
2150
2150
  sheet.range(f'{col_letter}{start_row}').api.AutoFill(
2151
2151
  sheet.range(f'{col_letter}{start_row}:{col_letter}{last_row}').api)
2152
+ sheet.range(f'{col_letter}:{col_letter}').autofit()
2152
2153
 
2153
2154
  def autofit_column(sheet, columns=None):
2154
2155
  if columns is None:
qrpa/fun_web.py CHANGED
@@ -10,12 +10,13 @@ import inspect
10
10
  def fetch(page: Page, url: str, params: Optional[Union[dict, list, str]] = None, headers: Optional[dict] = None, config:
11
11
  Optional[dict] = None) -> dict:
12
12
  """
13
- 发送 HTTP POST 请求,支持自定义 headers
13
+ 发送 HTTP POST 请求,支持自定义 headers 和重定向处理。
14
14
 
15
15
  :param page: Playwright 的 Page 对象
16
16
  :param url: 请求地址
17
17
  :param params: 请求参数(dict、list、str 或 None)
18
18
  :param headers: 自定义 headers 字典
19
+ :param config: 请求配置字典
19
20
  :return: 服务器返回的 JSON 响应(dict)
20
21
  """
21
22
  if params is not None and not isinstance(params, (dict, list, str)):
@@ -26,7 +27,7 @@ Optional[dict] = None) -> dict:
26
27
  try:
27
28
  page.wait_for_load_state('load')
28
29
  response = page.evaluate("""
29
- async ({ url, params, extraHeaders }) => {
30
+ async ({ url, params, extraHeaders, config }) => {
30
31
  try {
31
32
  const defaultHeaders = {
32
33
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
@@ -37,9 +38,15 @@ Optional[dict] = None) -> dict:
37
38
  const options = {
38
39
  method: 'POST',
39
40
  credentials: 'include',
41
+ redirect: 'follow', // 明确设置跟随重定向
40
42
  headers: headers
41
43
  };
42
44
 
45
+ // 应用额外配置
46
+ if (config) {
47
+ Object.assign(options, config);
48
+ }
49
+
43
50
  if (params !== null) {
44
51
  if (typeof params === 'string') {
45
52
  options.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
@@ -51,15 +58,40 @@ Optional[dict] = None) -> dict:
51
58
  }
52
59
 
53
60
  const response = await fetch(url, options);
61
+
62
+ // 处理重定向
63
+ if (response.redirected) {
64
+ console.log(`请求被重定向到: ${response.url}`);
65
+ }
66
+
54
67
  if (!response.ok) {
68
+ // 如果是重定向相关的状态码,尝试获取响应内容
69
+ if (response.status >= 300 && response.status < 400) {
70
+ const text = await response.text();
71
+ return {
72
+ "error": "redirect_error",
73
+ "message": `HTTP ${response.status} - ${response.statusText}`,
74
+ "redirect_url": response.url,
75
+ "response_text": text,
76
+ "status": response.status
77
+ };
78
+ }
55
79
  throw new Error(`HTTP ${response.status} - ${response.statusText}`);
56
80
  }
57
- return await response.json();
81
+
82
+ // 尝试解析 JSON,如果失败则返回文本内容
83
+ const contentType = response.headers.get('content-type');
84
+ if (contentType && contentType.includes('application/json')) {
85
+ return await response.json();
86
+ } else {
87
+ const text = await response.text();
88
+ return { "content": text, "content_type": contentType, "final_url": response.url };
89
+ }
58
90
  } catch (error) {
59
91
  return { "error": "fetch_failed", "message": error.message };
60
92
  }
61
93
  }
62
- """, {"url": url, "params": params, "extraHeaders": headers})
94
+ """, {"url": url, "params": params, "extraHeaders": headers, "config": config})
63
95
 
64
96
  return response
65
97
  except Exception as e:
@@ -148,7 +180,7 @@ def full_screen_shot(web_page: Page, config):
148
180
 
149
181
  def fetch_get(page: Page, url: str, headers: Optional[dict] = None, config: Optional[dict] = None) -> dict:
150
182
  """
151
- 发送 HTTP GET 请求,支持自定义 headers 和配置。
183
+ 发送 HTTP GET 请求,支持自定义 headers 和配置,支持重定向处理。
152
184
 
153
185
  :param page: Playwright 的 Page 对象
154
186
  :param url: 请求地址
@@ -173,17 +205,43 @@ def fetch_get(page: Page, url: str, headers: Optional[dict] = None, config: Opti
173
205
  const defaultConfig = {
174
206
  method: 'GET',
175
207
  credentials: 'include',
176
- mode: 'cors'
208
+ mode: 'cors',
209
+ redirect: 'follow' // 明确设置跟随重定向
177
210
  };
178
211
 
179
212
  const headers = Object.assign({}, defaultHeaders, extraHeaders || {});
180
213
  const options = Object.assign({}, defaultConfig, config || {}, { headers: headers });
181
214
 
182
215
  const response = await fetch(url, options);
216
+
217
+ // 处理重定向
218
+ if (response.redirected) {
219
+ console.log(`请求被重定向到: ${response.url}`);
220
+ }
221
+
183
222
  if (!response.ok) {
223
+ // 如果是重定向相关的状态码,尝试获取响应内容
224
+ if (response.status >= 300 && response.status < 400) {
225
+ const text = await response.text();
226
+ return {
227
+ "error": "redirect_error",
228
+ "message": `HTTP ${response.status} - ${response.statusText}`,
229
+ "redirect_url": response.url,
230
+ "response_text": text,
231
+ "status": response.status
232
+ };
233
+ }
184
234
  throw new Error(`HTTP ${response.status} - ${response.statusText}`);
185
235
  }
186
- return await response.json();
236
+
237
+ // 尝试解析 JSON,如果失败则返回文本内容
238
+ const contentType = response.headers.get('content-type');
239
+ if (contentType && contentType.includes('application/json')) {
240
+ return await response.json();
241
+ } else {
242
+ const text = await response.text();
243
+ return { "content": text, "content_type": contentType, "final_url": response.url };
244
+ }
187
245
  } catch (error) {
188
246
  return { "error": "fetch_failed", "message": error.message };
189
247
  }
qrpa/shein_excel.py CHANGED
@@ -195,7 +195,6 @@ class SheinExcel:
195
195
  dict = read_dict_from_file(cache_file)
196
196
  for store_username, shein_back_list in dict.items():
197
197
  for item in shein_back_list:
198
-
199
198
  store_name = dict_store.get(store_username)
200
199
 
201
200
  returnOrderId = item['id']
@@ -297,7 +296,6 @@ class SheinExcel:
297
296
  dict = read_dict_from_file(cache_file)
298
297
  for store_username, shein_back_list in dict.items():
299
298
  for item in shein_back_list:
300
-
301
299
  store_name = dict_store.get(store_username)
302
300
 
303
301
  returnOrderId = item['id']
@@ -393,7 +391,6 @@ class SheinExcel:
393
391
  dict = read_dict_from_file(cache_file)
394
392
  for store_username, shein_back_list in dict.items():
395
393
  for item in shein_back_list:
396
-
397
394
  store_name = dict_store.get(store_username)
398
395
 
399
396
  returnOrderId = item['id']
@@ -1209,9 +1206,9 @@ class SheinExcel:
1209
1206
  excel_path_month = str(self.config.excel_shein_finance_month_report).replace('#store_name#', store_name)
1210
1207
 
1211
1208
  month_data = [[
1212
- '平台SKU', '商家SKU', '属性集', '数量', '单价', '金额', '单价成本', '利润', '售出数量', '售出金额', '添加时间',
1209
+ '平台SKU', '商家SKU', '属性集', '数量', '单价', '金额', '单价成本', '利润', '售出数量', '售出金额', '售出成本', '添加时间',
1213
1210
  '业务单号', '单据号', '变动类型', '结算类型', 'SKC', '供方货号', '供应商名称', 'SKU图片',
1214
- ], ['合计', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']]
1211
+ ], ['合计', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']]
1215
1212
  log('len(ledger_list)', len(ledger_list))
1216
1213
  for month_item in ledger_list:
1217
1214
  row_item = []
@@ -1230,6 +1227,7 @@ class SheinExcel:
1230
1227
  month_item['quantity'] if month_item['cost_price'] and month_item['settleTypeName'] == '收入结算' else 0)
1231
1228
  row_item.append(
1232
1229
  month_item['amount'] if month_item['cost_price'] and month_item['settleTypeName'] == '收入结算' else 0)
1230
+ row_item.append('')
1233
1231
  row_item.append(month_item['addTime'])
1234
1232
  row_item.append(month_item['businessNo'])
1235
1233
  row_item.append(month_item['billNo'])
@@ -1250,10 +1248,11 @@ class SheinExcel:
1250
1248
  add_borders(sheet)
1251
1249
  format_to_money(sheet, ['单价', '金额', '利润'])
1252
1250
  format_to_datetime(sheet, ['时间'])
1253
- add_formula_for_column(sheet, '利润', '=IF(AND(ISNUMBER(G3),O3="收入结算"),F3-G3*D3,0)', 3)
1254
- add_formula_for_column(sheet, '售出数量', '=IF(AND(ISNUMBER(G3),O3="收入结算"),D3,0)', 3)
1255
- add_formula_for_column(sheet, '售出金额', '=IF(AND(ISNUMBER(G3),O3="收入结算"),F3,0)', 3)
1256
- add_sum_for_cell(sheet, ['数量', '金额', '利润', '售出数量', '售出金额'])
1251
+ add_formula_for_column(sheet, '利润', '=IF(AND(ISNUMBER(G3),P3="收入结算"),F3-G3*D3,0)', 3)
1252
+ add_formula_for_column(sheet, '售出数量', '=IF(AND(ISNUMBER(G3),P3="收入结算"),D3,0)', 3)
1253
+ add_formula_for_column(sheet, '售出金额', '=IF(AND(ISNUMBER(G3),P3="收入结算"),F3,0)', 3)
1254
+ add_formula_for_column(sheet, '售出成本', '=IF(AND(ISNUMBER(G3),P3="收入结算"),D3 * G3,0)', 3)
1255
+ add_sum_for_cell(sheet, ['数量', '金额', '利润', '售出数量', '售出金额', '售出成本'])
1257
1256
  column_to_left(sheet, ['平台SKU', '商家SKU', '属性集'])
1258
1257
  column_to_right(sheet, ['单价', '金额', '利润'])
1259
1258
  hidden_columns(sheet, ['SKU图片'])
@@ -1370,7 +1369,7 @@ class SheinExcel:
1370
1369
 
1371
1370
  write_dict_to_file_ex(f'{self.config.auto_dir}/shein/cache/sheet_{last_month}_补扣款列表.json', {store_username: replenish_data[:1] + replenish_data[2:]}, [store_username])
1372
1371
 
1373
- write_data(excel_path_month, sheet_name, replenish_data)
1372
+ write_data(excel_path_month, sheet_name, sort_by_column(replenish_data, 2, 2))
1374
1373
 
1375
1374
  app, wb, sheet = open_excel(excel_path_month, sheet_name)
1376
1375
  set_title_style(sheet, 2)
@@ -1540,19 +1539,28 @@ class SheinExcel:
1540
1539
 
1541
1540
  target_month = find_column_by_data(sheet, 2, last_month)
1542
1541
  sheet.range(f'{target_month}3').value = f"='{last_month}月销售明细'!I2"
1542
+
1543
1543
  sheet.range(f'{target_month}4').number_format = f"¥#,##0.00;¥-#,##0.00"
1544
1544
  sheet.range(f'{target_month}4').value = f"='{last_month}月销售明细'!J2"
1545
+
1546
+ sheet.range(f'A5').value = f"销售成本"
1545
1547
  sheet.range(f'{target_month}5').number_format = f"¥#,##0.00;¥-#,##0.00"
1546
- sheet.range(f'{target_month}5').value = f"='{last_month}月销售明细'!H2"
1548
+ sheet.range(f'{target_month}5').value = f"='{last_month}月销售明细'!K2"
1549
+
1550
+ sheet.range(f'A6').value = f"销售利润"
1547
1551
  sheet.range(f'{target_month}6').number_format = f"¥#,##0.00;¥-#,##0.00"
1552
+ sheet.range(f'{target_month}6').value = f"='{last_month}月销售明细'!H2"
1553
+
1554
+ # sheet.range(f'{target_month}6').number_format = f"¥#,##0.00;¥-#,##0.00"
1548
1555
  # sheet.range(f'{target_month}6').value = f"=-'{last_month}月退货与报废单列表'!L2 * 3"
1549
1556
  sheet.range(f'{target_month}7').number_format = f"¥#,##0.00;¥-#,##0.00"
1550
1557
  sheet.range(f'{target_month}7').value = f"=-'{last_month}月补扣款列表'!H2"
1551
1558
  sheet.range(f'{target_month}8').number_format = f"¥#,##0.00;¥-#,##0.00"
1552
1559
  sheet.range(f'{target_month}9').number_format = f"¥#,##0.00;¥-#,##0.00"
1553
- sheet.range(f'{target_month}9').value = f"=SUM({target_month}5:{target_month}8)"
1560
+ sheet.range(f'{target_month}9').value = f"=SUM({target_month}6:{target_month}8)"
1554
1561
  sheet.range(f'{target_month}10').number_format = f"¥#,##0.00;¥-#,##0.00"
1555
- sheet.range(f'{target_month}10').value = f"='{last_month}月库存结余'!J2"
1562
+ sheet.range(f'{target_month}10').value = f"='{last_month}月库存结余'!Q2"
1563
+
1556
1564
  sheet.range('A1').value = f'2025年{last_month}月 shein 利润汇总表 {store_name}'
1557
1565
  sheet.range(f'{target_month}:{target_month}').autofit()
1558
1566
  wb.save()
@@ -2442,7 +2450,7 @@ class SheinExcel:
2442
2450
  self.dealFormula(sheet) # 有空再封装优化
2443
2451
  colorize_by_field(sheet, 'SPU')
2444
2452
  autofit_column(sheet, ['商品信息', '店铺名称', 'SKC点击率/SKC转化率', '自主参与活动'])
2445
- column_to_left(sheet, ['店铺名称', 'SKC点击率/SKC转化率', '自主参与活动','近7天SKU销量/SKC销量/SKC曝光'])
2453
+ column_to_left(sheet, ['店铺名称', 'SKC点击率/SKC转化率', '自主参与活动', '近7天SKU销量/SKC销量/SKC曝光'])
2446
2454
  specify_column_width(sheet, ['商品标题'], 150 / 6)
2447
2455
  add_borders(sheet)
2448
2456
  InsertImageV2(sheet, ['SKC图片', 'SKU图片'], 'shein', 120, None, None, True)
@@ -2530,3 +2538,112 @@ class SheinExcel:
2530
2538
  sheet.range(rangeF).number_format = '0.00'
2531
2539
  sheet.range(rangeG).formula = f'=IF(ISNUMBER({rangeB}),{col_week_1}{row}*{col_gross_profit}{row},"")'
2532
2540
  sheet.range(rangeG).number_format = '0.00'
2541
+
2542
+ def write_check_order(self, erp, start_date, end_date):
2543
+ header = ['店铺账号', '店铺别名', '店长', '报账单号', '货号', 'SKC', '平台SKU', '商家SKU', '属性集', '商品数量', '账单类型', '收支类型', '状态', '币种', '金额', 'ERP成本',
2544
+ '成本总额', '业务单号', '费用类型', '备注', '来源单号', '账单创建时间', '台账添加时间', '报账时间', '预计结算日期', '实际结算日期']
2545
+ excel_data = [header]
2546
+
2547
+ dict_store = read_dict_from_file(self.config.shein_store_alias)
2548
+
2549
+ cache_file = f'{self.config.auto_dir}/shein/cache/check_order_{start_date}_{end_date}.json'
2550
+ dict = read_dict_from_file(cache_file)
2551
+ for store_username, data_list in dict.items():
2552
+ for item in data_list:
2553
+ store_name = dict_store.get(store_username)
2554
+ store_manager = self.config.shein_store_manager.get(str(store_username).lower())
2555
+
2556
+ row_item = []
2557
+ row_item.append(store_username)
2558
+ row_item.append(store_name)
2559
+ row_item.append(store_manager)
2560
+ row_item.append(item['reportOrderNo'])
2561
+ row_item.append(item['goodsSn'])
2562
+ row_item.append(item['skcName'])
2563
+ row_item.append(item['skuCode'])
2564
+ row_item.append(item['skuSn'])
2565
+ row_item.append(item['suffix'])
2566
+ row_item.append(item['goodsCount'])
2567
+ row_item.append(item['secondOrderTypeName'])
2568
+ row_item.append(item['inAndOutName'])
2569
+ row_item.append(item['settlementStatusName'])
2570
+ row_item.append(item['settleCurrencyCode'])
2571
+ row_item.append(item['income'])
2572
+ row_item.append(self.bridge.get_sku_cost(item['skuSn'], erp))
2573
+ row_item.append('')
2574
+ row_item.append(item['bzOrderNo'])
2575
+ row_item.append(item['expenseTypeName'])
2576
+ row_item.append(item['remark'])
2577
+ row_item.append(item['sourceNo'])
2578
+ row_item.append(item['addTime'])
2579
+ row_item.append(item['businessCompletedTime'])
2580
+ row_item.append(item['reportTime'])
2581
+ row_item.append(item['estimatePayTime'])
2582
+ row_item.append(item['completedPayTime'])
2583
+
2584
+ excel_data.append(row_item)
2585
+
2586
+ cache_file_excel = f'{self.config.auto_dir}/shein/cache/shein_return_order_list_excel_{start_date}_{end_date}.json'
2587
+ write_dict_to_file(cache_file_excel, excel_data)
2588
+
2589
+ sheet_name = '收支明细'
2590
+ batch_excel_operations(self.config.excel_shein_finance_month_report_pop, [
2591
+ (sheet_name, 'write', excel_data, ['R']),
2592
+ (sheet_name, 'format', self.format_check_order)
2593
+ ])
2594
+
2595
+ header = ['店铺账号', '店铺别名', '店长', '出库金额', '出库成本', '备货作业费', '代收服务费', '订单履约服务费', '订单退货', '退货处理费', '退货单履约服务费', '利润']
2596
+ excel_data = [header]
2597
+ cache_file = f'{self.config.auto_dir}/shein/cache/check_order_{start_date}_{end_date}.json'
2598
+ dict = read_dict_from_file(cache_file)
2599
+ for store_username, data_list in dict.items():
2600
+ store_name = dict_store.get(store_username)
2601
+ store_manager = self.config.shein_store_manager.get(str(store_username).lower())
2602
+ row_item = []
2603
+ row_item.append(store_username)
2604
+ row_item.append(store_name)
2605
+ row_item.append(store_manager)
2606
+ row_item.append('')
2607
+ row_item.append('')
2608
+ row_item.append('')
2609
+ row_item.append('')
2610
+ row_item.append('')
2611
+ row_item.append('')
2612
+ row_item.append('')
2613
+ row_item.append('')
2614
+ row_item.append('')
2615
+ excel_data.append(row_item)
2616
+
2617
+ sheet_name = '总表'
2618
+ batch_excel_operations(self.config.excel_shein_finance_month_report_pop, [
2619
+ (sheet_name, 'write', excel_data),
2620
+ (sheet_name, 'format', self.format_check_order),
2621
+ ('Sheet1', 'delete'),
2622
+ (sheet_name, 'move', 1),
2623
+ ])
2624
+
2625
+ def format_check_order(self, sheet):
2626
+ if sheet.name == '收支明细':
2627
+ beautify_title(sheet)
2628
+ add_borders(sheet)
2629
+ format_to_datetime(sheet, ['时间'])
2630
+ format_to_date(sheet, ['日期'])
2631
+ format_to_money(sheet, ['金额', '成本'])
2632
+ column_to_right(sheet, ['金额', '成本'])
2633
+ column_to_left(sheet, ['货号', '商家SKU'])
2634
+ add_formula_for_column(sheet, '成本总额', '=IF(ISNUMBER(O2),O2*J2,0)')
2635
+
2636
+ if sheet.name == '总表':
2637
+ beautify_title(sheet)
2638
+ add_borders(sheet)
2639
+ format_to_money(sheet, ['金额', '成本', '费', '订单退货', '利润'])
2640
+ column_to_right(sheet, ['金额', '成本', '费', '订单退货', '利润'])
2641
+ add_formula_for_column(sheet, '出库金额', '=SUMIFS(收支明细!O:O,收支明细!A:A,A2,收支明细!L:L,"收入")')
2642
+ add_formula_for_column(sheet, '出库成本', '=SUMIFS(收支明细!P:P,收支明细!A:A,A2,收支明细!L:L,"收入")')
2643
+ add_formula_for_column(sheet, '备货作业费', '=SUMIFS(收支明细!O:O,收支明细!A:A,A2,收支明细!L:L,"支出",收支明细!K:K,"备货作业费")')
2644
+ add_formula_for_column(sheet, '代收服务费', '=SUMIFS(收支明细!O:O,收支明细!A:A,A2,收支明细!L:L,"支出",收支明细!K:K,"代收服务费")')
2645
+ add_formula_for_column(sheet, '订单履约服务费', '=SUMIFS(收支明细!O:O,收支明细!A:A,A2,收支明细!L:L,"支出",收支明细!K:K,"订单履约服务费")')
2646
+ add_formula_for_column(sheet, '订单退货', '=SUMIFS(收支明细!O:O,收支明细!A:A,A2,收支明细!L:L,"支出",收支明细!K:K,"订单退货")')
2647
+ add_formula_for_column(sheet, '退货处理费', '=SUMIFS(收支明细!O:O,收支明细!A:A,A2,收支明细!L:L,"支出",收支明细!K:K,"退货处理费")')
2648
+ add_formula_for_column(sheet, '退货单履约服务费', '=SUMIFS(收支明细!O:O,收支明细!A:A,A2,收支明细!L:L,"支出",收支明细!K:K,"退货单履约服务费")')
2649
+ add_formula_for_column(sheet, '利润', '=D2-E2-F2-G2-H2-I2-J2')
qrpa/shein_lib.py CHANGED
@@ -26,6 +26,7 @@ class SheinLib:
26
26
  self.DictQueryTime = {}
27
27
 
28
28
  self.deal_auth()
29
+ # self.get_user()
29
30
 
30
31
  # 处理鉴权
31
32
  def deal_auth(self):
@@ -101,6 +102,10 @@ class SheinLib:
101
102
  if "crashed" in str(status_error):
102
103
  break
103
104
 
105
+ if web_page.locator('xpath=//div[text()="扫码登录"]').is_visible():
106
+ log('检查到扫码登录,切换至账号登录', self.store_username, self.store_name)
107
+ web_page.locator('xpath=//*[@id="container"]/div[2]/div[4]/img').click()
108
+
104
109
  if web_page.locator('xpath=//div[@id="container" and @alita-name="gmpsso"]//button[@type="button" and @id]').nth(0).is_visible():
105
110
  if 'https://sso.geiwohuo.com/#/home' not in web_page.url:
106
111
  log("鉴权确定按钮可见 点击'确定'按钮", web_page.title(), web_page.url, self.store_username, self.store_name)
@@ -2889,3 +2894,45 @@ class SheinLib:
2889
2894
  write_dict_to_file_ex(cache_file, {self.store_name: NotifyItem}, {self.store_name})
2890
2895
 
2891
2896
  return excel_data
2897
+
2898
+ def check_order_list(self, source, first_day, last_day):
2899
+ page_num = 1
2900
+ page_size = 200 # 列表最多返回200条数据 大了没有用
2901
+
2902
+ cache_file = f'{self.config.auto_dir}/shein/cache/check_order_{first_day}_{last_day}.json'
2903
+ list_item = read_dict_from_file_ex(cache_file, self.store_username)
2904
+
2905
+ url = f"https://sso.geiwohuo.com/gsfs/finance/reportOrder/dualMode/checkOrderList/item/union"
2906
+ payload = {
2907
+ "page" : page_num,
2908
+ "perPage" : page_size,
2909
+ "detailAddTimeStart": f"{first_day} 00:00:00",
2910
+ "detailAddTimeEnd" : f"{last_day} 23:59:59"
2911
+ }
2912
+ response_text = fetch(self.web_page, url, payload)
2913
+ error_code = response_text.get('code')
2914
+ if str(error_code) != '0':
2915
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
2916
+ list_item = response_text['info']['data']
2917
+ total = response_text['info']['meta']['count']
2918
+ totalPage = math.ceil(total / page_size)
2919
+
2920
+ if int(total) == len(list_item):
2921
+ log('总数与缓存数量相同 跳过剩余页抓取', total)
2922
+ return list_item
2923
+
2924
+ for page in range(2, totalPage + 1):
2925
+ log(f'获取收支明细列表 第{page}/{totalPage}页')
2926
+ payload['pageNumber'] = page
2927
+ response_text = fetch(self.web_page, url, payload)
2928
+ spu_list_new = response_text['info']['data']
2929
+ list_item += spu_list_new
2930
+ time.sleep(0.1)
2931
+
2932
+ for item in list_item:
2933
+ supplierSku = item['skuSn']
2934
+ item['cost_price'] = self.bridge.get_sku_cost(supplierSku, source)
2935
+ item['sku_img'] = self.bridge.get_sku_img(supplierSku, source)
2936
+
2937
+ write_dict_to_file_ex(cache_file, {self.store_username: list_item}, [self.store_username])
2938
+ return list_item
qrpa/shein_mysql.py CHANGED
@@ -1,62 +1,62 @@
1
- import json
2
-
3
- from .mysql_module.shein_return_order_model import SheinReturnOrderManager
4
- from .mysql_module.shein_product_model import SheinProductManager
5
- from .fun_base import log
6
-
7
- import os
8
-
9
- class SheinMysql:
10
- def __init__(self, config):
11
- self.config = config
12
-
13
- def upsert_shein_return_order(self, json_file):
14
- log(f'当前使用的数据库: {self.config.db.database_url}')
15
- # 创建管理器实例
16
- manager = SheinReturnOrderManager(self.config.db.database_url)
17
- # 创建数据表
18
- manager.create_tables()
19
- # 读取JSON文件
20
- with open(json_file, 'r', encoding='utf-8') as f:
21
- dict = json.load(f)
22
- for store_username, data_list in dict.items():
23
- manager.upsert_return_order_data(store_username, data_list)
24
-
25
- def upsert_shein_product(self, json_file):
26
- log(f'当前使用的数据库: {self.config.db.database_url}')
27
- # 创建管理器实例
28
- manager = SheinProductManager(self.config.db.database_url)
29
- # 创建数据表
30
- manager.create_tables()
31
- with open(json_file, 'r', encoding='utf-8') as f:
32
- file_list = json.load(f)
33
- for store_username, store_skc_list_file in file_list.items():
34
- with open(store_skc_list_file, 'r', encoding='utf-8') as f:
35
- dict_store_skc_list = json.load(f)
36
- for store_username, data_list in dict_store_skc_list.items():
37
- manager.upsert_product_data(data_list)
38
-
39
- def upsert_shein_product_info(self, json_file):
40
- log(f'当前使用的数据库: {self.config.db.database_url}')
41
- # 创建管理器实例
42
- manager = SheinProductManager(self.config.db.database_url)
43
- # 创建数据表
44
- manager.create_tables()
45
- with open(json_file, 'r', encoding='utf-8') as f:
46
- file_list = json.load(f)
47
- for store_username, store_spu_list in file_list.items():
48
- for spu in store_spu_list:
49
- product_detail_file = f'{self.config.auto_dir}/shein/product_detail/product_detail_{spu}.json'
50
- attribute_file = f'{self.config.auto_dir}/shein/attribute/attribute_template_{spu}.json'
51
- if os.path.exists(product_detail_file):
52
- with open(product_detail_file, 'r', encoding='utf-8') as f:
53
- data_list = json.load(f)
54
- manager.upsert_product_detail(spu, 'product_detail', data_list)
55
- else:
56
- log(f'文件不存在: {product_detail_file}')
57
- if os.path.exists(attribute_file):
58
- with open(attribute_file, 'r', encoding='utf-8') as f:
59
- data_list = json.load(f)
60
- manager.upsert_product_detail(spu, 'attribute_template', data_list)
61
- else:
62
- log(f'文件不存在: {attribute_file}')
1
+ import json
2
+
3
+ from .mysql_module.shein_return_order_model import SheinReturnOrderManager
4
+ from .mysql_module.shein_product_model import SheinProductManager
5
+ from .fun_base import log
6
+
7
+ import os
8
+
9
+ class SheinMysql:
10
+ def __init__(self, config):
11
+ self.config = config
12
+
13
+ def upsert_shein_return_order(self, json_file):
14
+ log(f'当前使用的数据库: {self.config.db.database_url}')
15
+ # 创建管理器实例
16
+ manager = SheinReturnOrderManager(self.config.db.database_url)
17
+ # 创建数据表
18
+ manager.create_tables()
19
+ # 读取JSON文件
20
+ with open(json_file, 'r', encoding='utf-8') as f:
21
+ dict = json.load(f)
22
+ for store_username, data_list in dict.items():
23
+ manager.upsert_return_order_data(store_username, data_list)
24
+
25
+ def upsert_shein_product(self, json_file):
26
+ log(f'当前使用的数据库: {self.config.db.database_url}')
27
+ # 创建管理器实例
28
+ manager = SheinProductManager(self.config.db.database_url)
29
+ # 创建数据表
30
+ manager.create_tables()
31
+ with open(json_file, 'r', encoding='utf-8') as f:
32
+ file_list = json.load(f)
33
+ for store_username, store_skc_list_file in file_list.items():
34
+ with open(store_skc_list_file, 'r', encoding='utf-8') as f:
35
+ dict_store_skc_list = json.load(f)
36
+ for store_username, data_list in dict_store_skc_list.items():
37
+ manager.upsert_product_data(data_list)
38
+
39
+ def upsert_shein_product_info(self, json_file):
40
+ log(f'当前使用的数据库: {self.config.db.database_url}')
41
+ # 创建管理器实例
42
+ manager = SheinProductManager(self.config.db.database_url)
43
+ # 创建数据表
44
+ manager.create_tables()
45
+ with open(json_file, 'r', encoding='utf-8') as f:
46
+ file_list = json.load(f)
47
+ for store_username, store_spu_list in file_list.items():
48
+ for spu in store_spu_list:
49
+ product_detail_file = f'{self.config.auto_dir}/shein/product_detail/product_detail_{spu}.json'
50
+ attribute_file = f'{self.config.auto_dir}/shein/attribute/attribute_template_{spu}.json'
51
+ if os.path.exists(product_detail_file):
52
+ with open(product_detail_file, 'r', encoding='utf-8') as f:
53
+ data_list = json.load(f)
54
+ manager.upsert_product_detail(spu, 'product_detail', data_list)
55
+ else:
56
+ log(f'文件不存在: {product_detail_file}')
57
+ if os.path.exists(attribute_file):
58
+ with open(attribute_file, 'r', encoding='utf-8') as f:
59
+ data_list = json.load(f)
60
+ manager.upsert_product_detail(spu, 'attribute_template', data_list)
61
+ else:
62
+ log(f'文件不存在: {attribute_file}')
qrpa/shein_ziniao.py CHANGED
@@ -488,7 +488,7 @@ class ZiniaoRunner:
488
488
  raise RuntimeError("店铺列表为空")
489
489
 
490
490
  # 多线程并发执行任务
491
- max_threads = 1 if (hostname().lower() == 'krrpa') else 3
491
+ max_threads = 3 if (hostname().lower() == 'krrpa' or hostname().lower() == 'jyrpa') else 3
492
492
  log(f'当前启用线程数: {max_threads}')
493
493
  self.task_manager.run_with_thread_pool(browser_list, max_threads, run, task_key, just_store_username, is_skip_store)
494
494