qrpa 1.0.90__py3-none-any.whl → 1.0.91__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 +35 -8
- qrpa/mysql_module/shein_product_model.py +11 -3
- qrpa/shein_excel.py +1 -1
- qrpa/shein_lib.py +4 -1
- {qrpa-1.0.90.dist-info → qrpa-1.0.91.dist-info}/METADATA +1 -1
- {qrpa-1.0.90.dist-info → qrpa-1.0.91.dist-info}/RECORD +8 -8
- {qrpa-1.0.90.dist-info → qrpa-1.0.91.dist-info}/WHEEL +0 -0
- {qrpa-1.0.90.dist-info → qrpa-1.0.91.dist-info}/top_level.txt +0 -0
qrpa/fun_excel.py
CHANGED
|
@@ -14,6 +14,9 @@ import threading
|
|
|
14
14
|
from playwright.sync_api import sync_playwright
|
|
15
15
|
import psutil
|
|
16
16
|
|
|
17
|
+
import os, sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
17
20
|
from .fun_base import log, sanitize_filename, create_file_path, copy_file, add_https, send_exception
|
|
18
21
|
|
|
19
22
|
excel_color_index = {
|
|
@@ -195,13 +198,13 @@ def merge_by_column_v2(sheet, column_name, other_columns):
|
|
|
195
198
|
# 更安全的数据获取方式,确保获取完整的数据范围
|
|
196
199
|
last_row = get_last_row(sheet, col_letter)
|
|
197
200
|
data = sheet.range(f'{col_letter}1:{col_letter}{last_row}').value
|
|
198
|
-
|
|
201
|
+
|
|
199
202
|
# 确保data是列表格式
|
|
200
203
|
if not isinstance(data, list):
|
|
201
204
|
data = [data]
|
|
202
|
-
|
|
205
|
+
|
|
203
206
|
log(f'数据范围: {col_letter}1:{col_letter}{last_row}, 数据长度: {len(data)}')
|
|
204
|
-
|
|
207
|
+
|
|
205
208
|
start_row = 2 # 从第2行开始,跳过表头
|
|
206
209
|
merge_row_ranges = [] # 用来存储需要合并的行范围 (start_row, end_row)
|
|
207
210
|
|
|
@@ -211,13 +214,13 @@ def merge_by_column_v2(sheet, column_name, other_columns):
|
|
|
211
214
|
col_name = find_column_by_data(sheet, 1, col)
|
|
212
215
|
if col_name:
|
|
213
216
|
all_columns.append(col_name)
|
|
214
|
-
|
|
217
|
+
|
|
215
218
|
log(f'需要合并的列: {all_columns}')
|
|
216
219
|
|
|
217
220
|
# 遍历数据行,从第3行开始比较(因为第1行是表头,第2行是第一个数据行)
|
|
218
221
|
for row in range(3, len(data) + 1):
|
|
219
|
-
log(f'查找 {row}/{len(data)}, 当前值: {data[row-1] if row-1 < len(data) else "超出范围"}, 前一个值: {data[row-2] if row-2 < len(data) else "超出范围"}')
|
|
220
|
-
|
|
222
|
+
log(f'查找 {row}/{len(data)}, 当前值: {data[row - 1] if row - 1 < len(data) else "超出范围"}, 前一个值: {data[row - 2] if row - 2 < len(data) else "超出范围"}')
|
|
223
|
+
|
|
221
224
|
# 检查值是否发生变化
|
|
222
225
|
if row <= len(data) and data[row - 1] != data[row - 2]:
|
|
223
226
|
# 值发生变化,处理前一组
|
|
@@ -233,7 +236,7 @@ def merge_by_column_v2(sheet, column_name, other_columns):
|
|
|
233
236
|
merge_row_ranges.append((start_row, end_row))
|
|
234
237
|
|
|
235
238
|
log(f'行合并范围: {merge_row_ranges}')
|
|
236
|
-
|
|
239
|
+
|
|
237
240
|
# 对每个行范围,在所有指定列中执行合并
|
|
238
241
|
for start_row, end_row in merge_row_ranges:
|
|
239
242
|
if start_row < end_row: # 只有当开始行小于结束行时才合并(多行)
|
|
@@ -756,9 +759,33 @@ def download_images_concurrently(image_urls, platform='shein', img_save_dir=None
|
|
|
756
759
|
results = list(executor.map(lambda url: download_img_v2(url, platform, img_save_path=img_save_dir), image_urls))
|
|
757
760
|
return results
|
|
758
761
|
|
|
762
|
+
def get_chromium_executable():
|
|
763
|
+
"""
|
|
764
|
+
返回 Chromium 可执行文件路径,兼容 PyInstaller 打包后的 exe
|
|
765
|
+
"""
|
|
766
|
+
# PyInstaller 临时目录
|
|
767
|
+
if getattr(sys, 'frozen', False):
|
|
768
|
+
base_path = Path(sys._MEIPASS)
|
|
769
|
+
else:
|
|
770
|
+
base_path = Path(__file__).parent
|
|
771
|
+
|
|
772
|
+
# 尝试查找打包后的浏览器文件
|
|
773
|
+
possible_path = base_path / "playwright" / "driver" / "package" / "chromium_headless_shell-1169" / "chrome-win" / "headless_shell.exe"
|
|
774
|
+
if possible_path.exists():
|
|
775
|
+
return str(possible_path)
|
|
776
|
+
|
|
777
|
+
# fallback: 系统 Playwright 安装目录
|
|
778
|
+
local_appdata = Path(os.environ.get("LOCALAPPDATA", ""))
|
|
779
|
+
fallback_path = local_appdata / "ms-playwright" / "chromium" / "chrome-win" / "chrome.exe"
|
|
780
|
+
if fallback_path.exists():
|
|
781
|
+
return str(fallback_path)
|
|
782
|
+
|
|
783
|
+
raise FileNotFoundError("Chromium 可执行文件未找到,请先执行 'playwright install' 下载浏览器。")
|
|
784
|
+
|
|
759
785
|
def download_img_by_chrome(image_url, save_name):
|
|
786
|
+
chromium_path = get_chromium_executable()
|
|
760
787
|
with sync_playwright() as p:
|
|
761
|
-
browser = p.chromium.launch(headless=True) # 运行时可以看到浏览器
|
|
788
|
+
browser = p.chromium.launch(headless=True, executable_path=chromium_path) # 运行时可以看到浏览器
|
|
762
789
|
context = browser.new_context()
|
|
763
790
|
page = context.new_page()
|
|
764
791
|
# 直接通过Playwright下载图片
|
|
@@ -64,6 +64,9 @@ class SheinProductSkc(Base):
|
|
|
64
64
|
created_at = Column(DateTime, default=datetime.now, comment='创建时间')
|
|
65
65
|
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now, comment='更新时间')
|
|
66
66
|
|
|
67
|
+
# 用户备注字段(供后续web界面使用)
|
|
68
|
+
user_notes = Column(Text, nullable=True, comment='用户备注')
|
|
69
|
+
|
|
67
70
|
# 定义索引
|
|
68
71
|
__table_args__ = (
|
|
69
72
|
Index('ix_skc_id', 'skc_id'),
|
|
@@ -108,6 +111,7 @@ class SheinProductSku(Base):
|
|
|
108
111
|
price = Column(DECIMAL(10, 2), nullable=True, comment='价格')
|
|
109
112
|
erp_cost_price = Column(DECIMAL(10, 2), nullable=True, comment='ERP成本价')
|
|
110
113
|
erp_supplier_name = Column(String(100), nullable=True, comment='ERP默认供货商')
|
|
114
|
+
erp_stock = Column(Integer, nullable=True, comment='ERP库存')
|
|
111
115
|
|
|
112
116
|
# 时间戳
|
|
113
117
|
created_at = Column(DateTime, default=datetime.now, comment='创建时间')
|
|
@@ -218,10 +222,10 @@ class SheinProductManager:
|
|
|
218
222
|
session = self.Session()
|
|
219
223
|
try:
|
|
220
224
|
for data in data_list:
|
|
221
|
-
|
|
225
|
+
|
|
222
226
|
# 处理SKC数据
|
|
223
227
|
skc_record = self._upsert_skc_data(session, data)
|
|
224
|
-
|
|
228
|
+
|
|
225
229
|
# 处理SKU数据
|
|
226
230
|
for sku_data in data.get('skuList', []):
|
|
227
231
|
sku_data['local_skc_id'] = skc_record.id
|
|
@@ -319,6 +323,7 @@ class SheinProductManager:
|
|
|
319
323
|
existing_sku.price = sku_data.get('price')
|
|
320
324
|
existing_sku.erp_cost_price = sku_data.get('erp_cost_price')
|
|
321
325
|
existing_sku.erp_supplier_name = sku_data.get('erp_supplier_name')
|
|
326
|
+
existing_sku.erp_stock = sku_data.get('erp_stock')
|
|
322
327
|
existing_sku.updated_at = datetime.now()
|
|
323
328
|
else:
|
|
324
329
|
# 插入新记录
|
|
@@ -473,4 +478,7 @@ def example_usage2():
|
|
|
473
478
|
|
|
474
479
|
if __name__ == "__main__":
|
|
475
480
|
pass
|
|
476
|
-
|
|
481
|
+
database_url = "mysql+pymysql://root:123wyk@localhost:3306/lz"
|
|
482
|
+
manager = SheinProductManager(database_url)
|
|
483
|
+
manager.create_tables()
|
|
484
|
+
# example_usage()
|
qrpa/shein_excel.py
CHANGED
|
@@ -2341,7 +2341,7 @@ class SheinExcel:
|
|
|
2341
2341
|
self.dealFormula(sheet) # 有空再封装优化
|
|
2342
2342
|
colorize_by_field(sheet, 'SPU')
|
|
2343
2343
|
autofit_column(sheet, ['商品信息', '店铺名称', 'SKC点击率/SKC转化率', '自主参与活动'])
|
|
2344
|
-
column_to_left(sheet, ['店铺名称', 'SKC点击率/SKC转化率', '自主参与活动'])
|
|
2344
|
+
column_to_left(sheet, ['店铺名称', 'SKC点击率/SKC转化率', '自主参与活动','近7天SKU销量/SKC销量/SKC曝光'])
|
|
2345
2345
|
specify_column_width(sheet, ['商品标题'], 150 / 6)
|
|
2346
2346
|
add_borders(sheet)
|
|
2347
2347
|
InsertImageV2(sheet, ['SKC图片', 'SKU图片'], 'shein', 120, None, None, True)
|
qrpa/shein_lib.py
CHANGED
|
@@ -887,6 +887,8 @@ class SheinLib:
|
|
|
887
887
|
cost_price = self.bridge.get_sku_cost(sku_item['supplierSku'], self.config.erp_source)
|
|
888
888
|
sku_item['erp_cost_price'] = cost_price if isinstance(cost_price, (int, float)) else None
|
|
889
889
|
sku_item['erp_supplier_name'] = self.bridge.get_sku_supplier(sku_item['supplierSku'], self.config.erp_source)
|
|
890
|
+
stock = self.bridge.get_sku_stock(sku_item['supplierSku'], self.config.erp_source)
|
|
891
|
+
sku_item['erp_stock'] = stock if isinstance(stock, (int, float)) else None
|
|
890
892
|
|
|
891
893
|
cache_file = f'{self.config.auto_dir}/shein/product/skc_list_{self.store_username}.json'
|
|
892
894
|
write_dict_to_file_ex(cache_file, {self.store_username: skc_list}, [self.store_username])
|
|
@@ -2314,6 +2316,7 @@ class SheinLib:
|
|
|
2314
2316
|
skc = str(spu_info['skc'])
|
|
2315
2317
|
# if not shein_db.exists_sales_1_days_ago(skc):
|
|
2316
2318
|
# log(f'未查到昨天销量: {skc}')
|
|
2319
|
+
self.get_skc_week_actual_sales(skc)
|
|
2317
2320
|
self.get_skc_sales(skc, date_60_days_ago, date_1_days_ago)
|
|
2318
2321
|
skcCode = spu_info['supplierCode']
|
|
2319
2322
|
product_name = DictSpuInfo[spu]['product_name_en']
|
|
@@ -2434,7 +2437,7 @@ class SheinLib:
|
|
|
2434
2437
|
# SKC趋势数据
|
|
2435
2438
|
sku_item.append(skc_trend.get('saleCnt', 0)) # SKC近7天销量
|
|
2436
2439
|
sku_item.append(skc_trend.get('epsUvIdx', 0)) # SKC近7天曝光人数
|
|
2437
|
-
sku_item.append(skc_trend.get('
|
|
2440
|
+
sku_item.append(skc_trend.get('goodsUv', 0)) # SKC近7天商详访客
|
|
2438
2441
|
sku_item.append(skc_trend.get('epsGdsCtrIdx', 0)) # SKC近7天点击率
|
|
2439
2442
|
sku_item.append(skc_trend.get('payUvIdx', 0)) # SKC近7天支付人数
|
|
2440
2443
|
sku_item.append(skc_trend.get('gdsPayCtrIdx', 0)) # SKC近7天支付率
|
|
@@ -5,13 +5,13 @@ qrpa/feishu_bot_app.py,sha256=6r2YqCAMUN7y3F7onoABRmHC7S-UPOLHwbhsQnQ3IRc,9452
|
|
|
5
5
|
qrpa/feishu_client.py,sha256=gXvyhf7r-IqeDhPjM01SfsGf17t8g1ZwUAkhymBkBeg,17544
|
|
6
6
|
qrpa/feishu_logic.py,sha256=yuwb-LeZiHKGlz-W8JobinorHonVa8L-5h12WxnU7_Q,67508
|
|
7
7
|
qrpa/fun_base.py,sha256=lMzqPwsbVfe968CUR2MVNImzIskIUZqPCE2tWxYqb5o,10728
|
|
8
|
-
qrpa/fun_excel.py,sha256
|
|
8
|
+
qrpa/fun_excel.py,sha256=5eOIwenixKZAYnNwoRlFR1Ca3somWNc5lQLJcVZGGDI,118439
|
|
9
9
|
qrpa/fun_file.py,sha256=yzjDV16WL5vRys7J4uQcNzIFkX4D5MAlSCwxcD-mwQo,11966
|
|
10
10
|
qrpa/fun_web.py,sha256=Mv0m2P5fh2-U4DzRoVivqRcXD56BJ_Svj6TZznx49YU,8645
|
|
11
11
|
qrpa/fun_win.py,sha256=-LnTeocdTt72NVH6VgLdpAT9_C5oV9okeudXG6CftMA,8034
|
|
12
12
|
qrpa/shein_daily_report_model.py,sha256=H8oZmIN5Pyqe306W1_xuz87lOqLQ_LI5RjXbaxDkIzE,12589
|
|
13
|
-
qrpa/shein_excel.py,sha256=
|
|
14
|
-
qrpa/shein_lib.py,sha256=
|
|
13
|
+
qrpa/shein_excel.py,sha256=6d_-AEvzLmCPqbmbpGD8-LBnD4izFh9FLdbTrjwOu6A,124864
|
|
14
|
+
qrpa/shein_lib.py,sha256=Mzvooz7abPP61XzzrLj8EzDxJYPk-tPjqQLHgdOk64A,134380
|
|
15
15
|
qrpa/shein_mysql.py,sha256=Sgz6U0_3f4cT5zPf1Ht1OjvSFhrVPLkMxt91NV-ZPCM,3005
|
|
16
16
|
qrpa/shein_sqlite.py,sha256=ZQwD0Gz81q9WY7tY2HMEYvSF9r3N_G_Aur3bYfST9WY,5707
|
|
17
17
|
qrpa/shein_ziniao.py,sha256=4CsOPZXRDEqHJvCGyb8imCPqSH5Ln5fGqPUFqLuFgCg,21276
|
|
@@ -22,9 +22,9 @@ qrpa/time_utils.py,sha256=KFXnF1pMWACAKOSy483riPqvTsMjhQtFJAIhQsZKaMk,30075
|
|
|
22
22
|
qrpa/time_utils_example.py,sha256=shHOXKKF3QSzb0SHsNc34M61wEkkLuM30U9X1THKNS8,8053
|
|
23
23
|
qrpa/wxwork.py,sha256=gIytG19DZ5g7Tsl0-W3EbjfSnpIqZw-ua24gcB78YEg,11264
|
|
24
24
|
qrpa/mysql_module/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
-
qrpa/mysql_module/shein_product_model.py,sha256=
|
|
25
|
+
qrpa/mysql_module/shein_product_model.py,sha256=v21_juWsZqTHj2k08GUGNkoRZ4hkKZKjaE-wmRl2a2k,19257
|
|
26
26
|
qrpa/mysql_module/shein_return_order_model.py,sha256=Zt-bGOH_kCDbakW7uaTmqqo_qTT8v424yidcYSfWvWM,26562
|
|
27
|
-
qrpa-1.0.
|
|
28
|
-
qrpa-1.0.
|
|
29
|
-
qrpa-1.0.
|
|
30
|
-
qrpa-1.0.
|
|
27
|
+
qrpa-1.0.91.dist-info/METADATA,sha256=vGN8tCsE3j9rM2U3aylnrCjYp83FD5wduYCTqeYZBv4,231
|
|
28
|
+
qrpa-1.0.91.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
29
|
+
qrpa-1.0.91.dist-info/top_level.txt,sha256=F6T5igi0fhXDucPPUbmmSC0qFCDEsH5eVijfVF48OFU,5
|
|
30
|
+
qrpa-1.0.91.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|