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

@@ -0,0 +1,476 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ SHEIN商品数据模型
5
+ 使用SQLAlchemy定义SKC表、SKU表和详情表结构
6
+ """
7
+
8
+ from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime, JSON, Date, DECIMAL, Index
9
+ from sqlalchemy.ext.declarative import declarative_base
10
+ from sqlalchemy.orm import sessionmaker
11
+ from datetime import datetime
12
+ import json
13
+ import os
14
+
15
+ # 创建基类
16
+ Base = declarative_base()
17
+
18
+ class SheinProductSkc(Base):
19
+ """
20
+ SHEIN商品SKC表
21
+ 存储SKC维度的商品信息
22
+ """
23
+ __tablename__ = 'shein_product_skc'
24
+
25
+ # 主键ID
26
+ id = Column(Integer, primary_key=True, autoincrement=True, comment='主键ID')
27
+
28
+ # 原始数据中的ID作为skc_id
29
+ skc_id = Column(Integer, nullable=False, unique=True, comment='原始SKC ID')
30
+
31
+ # 店铺信息
32
+ store_username = Column(String(50), nullable=True, comment='店铺账号')
33
+ store_name = Column(String(100), nullable=True, comment='店铺名称')
34
+ store_manager = Column(String(50), nullable=True, comment='店长')
35
+
36
+ # 商品基本信息
37
+ pic_url = Column(Text, nullable=True, comment='SKC主图')
38
+ supplier_code = Column(String(100), nullable=True, comment='商家SKC')
39
+ skc = Column(String(50), nullable=True, comment='平台SKC')
40
+ spu = Column(String(50), nullable=True, comment='SPU编码')
41
+ category_name = Column(String(100), nullable=True, comment='叶子类目')
42
+
43
+ # 上架信息
44
+ shelf_days = Column(Integer, nullable=True, comment='上架天数')
45
+ shelf_date = Column(Date, nullable=True, comment='上架日期')
46
+
47
+ # 商品标签和状态
48
+ goods_label_list = Column(JSON, nullable=True, comment='商品标签列表')
49
+ supply_status = Column(String(50), nullable=True, comment='供货状态')
50
+ shelf_status = Column(Integer, nullable=True, comment='上架状态')
51
+ goods_level = Column(String(50), nullable=True, comment='商品等级')
52
+
53
+ # 其他字段
54
+ group_flag = Column(Integer, nullable=True, comment='组合标志')
55
+ goods_level_can_order_flag = Column(Integer, nullable=True, comment='商品等级可下单标志')
56
+ stock_standard = Column(Integer, nullable=True, comment='备货标准')
57
+ stock_warn_status = Column(Integer, nullable=True, comment='库存预警状态')
58
+
59
+ # 销量汇总
60
+ c7d_sale_cnt_sum = Column(Integer, nullable=True, comment='7日销量汇总')
61
+ shein_sale_by_inventory = Column(Integer, nullable=True, comment='希音库存销售')
62
+
63
+ # 时间戳
64
+ created_at = Column(DateTime, default=datetime.now, comment='创建时间')
65
+ updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now, comment='更新时间')
66
+
67
+ # 定义索引
68
+ __table_args__ = (
69
+ Index('ix_skc_id', 'skc_id'),
70
+ Index('ix_skc', 'skc'),
71
+ Index('ix_spu', 'spu'),
72
+ Index('ix_supplier_code', 'supplier_code'),
73
+ Index('ix_store_username', 'store_username'),
74
+ )
75
+
76
+ def __repr__(self):
77
+ return f"<SheinProductSkc(id={self.id}, skc='{self.skc}', spu='{self.spu}')>"
78
+
79
+ class SheinProductSku(Base):
80
+ """
81
+ SHEIN商品SKU表
82
+ 存储SKU维度的商品信息
83
+ """
84
+ __tablename__ = 'shein_product_sku'
85
+
86
+ # 主键ID
87
+ id = Column(Integer, primary_key=True, autoincrement=True, comment='主键ID')
88
+
89
+ # 原始数据中的ID作为sku_id
90
+ sku_id = Column(Integer, nullable=False, unique=True, comment='原始SKU ID')
91
+
92
+ # 关联SKC本地主键ID
93
+ local_skc_id = Column(Integer, nullable=False, comment='关联的SKC本地主键ID')
94
+
95
+ # SKU基本信息
96
+ sort_value = Column(Integer, nullable=True, comment='排序值')
97
+ sku_code = Column(String(50), nullable=True, comment='SKU编码')
98
+ attr = Column(String(100), nullable=True, comment='SKU属性')
99
+ supplier_sku = Column(String(100), nullable=True, comment='供应商SKU')
100
+
101
+ # 销量数据
102
+ order_cnt = Column(Integer, nullable=True, comment='今日订单数')
103
+ total_sale_volume = Column(Integer, nullable=True, comment='今日总销量')
104
+ c7d_sale_cnt = Column(Integer, nullable=True, comment='7日销量')
105
+ c30d_sale_cnt = Column(Integer, nullable=True, comment='30日销量')
106
+
107
+ # 价格成本信息
108
+ price = Column(DECIMAL(10, 2), nullable=True, comment='价格')
109
+ erp_cost_price = Column(DECIMAL(10, 2), nullable=True, comment='ERP成本价')
110
+ erp_supplier_name = Column(String(100), nullable=True, comment='ERP默认供货商')
111
+
112
+ # 时间戳
113
+ created_at = Column(DateTime, default=datetime.now, comment='创建时间')
114
+ updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now, comment='更新时间')
115
+
116
+ # 定义索引
117
+ __table_args__ = (
118
+ Index('ix_sku_id', 'sku_id'),
119
+ Index('ix_local_skc_id', 'local_skc_id'),
120
+ Index('ix_sku_code', 'sku_code'),
121
+ Index('ix_supplier_sku', 'supplier_sku'),
122
+ )
123
+
124
+ def __repr__(self):
125
+ return f"<SheinProductSku(id={self.id}, sku_code='{self.sku_code}', attr='{self.attr}')>"
126
+
127
+ class SheinProductDetail(Base):
128
+ """
129
+ SHEIN商品详情信息表
130
+ 以KV形式保存SPU维度的JSON数据
131
+ """
132
+ __tablename__ = 'shein_product_detail'
133
+
134
+ # 主键ID
135
+ id = Column(Integer, primary_key=True, autoincrement=True, comment='主键ID')
136
+
137
+ # SPU编码
138
+ spu = Column(String(50), nullable=False, comment='SPU编码')
139
+
140
+ # 字段名称
141
+ field_name = Column(String(100), nullable=False, comment='字段名称')
142
+
143
+ # JSON数据
144
+ json_data = Column(JSON, nullable=True, comment='JSON数据')
145
+
146
+ # 时间戳
147
+ created_at = Column(DateTime, default=datetime.now, comment='创建时间')
148
+ updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now, comment='更新时间')
149
+
150
+ # 定义索引
151
+ __table_args__ = (
152
+ Index('ix_spu', 'spu'),
153
+ Index('ix_field_name', 'field_name'),
154
+ Index('ix_spu_field', 'spu', 'field_name'),
155
+ )
156
+
157
+ def __repr__(self):
158
+ return f"<SheinProductDetail(id={self.id}, spu='{self.spu}', field_name='{self.field_name}')>"
159
+
160
+ class SheinProductManager:
161
+ """
162
+ SHEIN商品数据管理器
163
+ 提供数据库操作相关方法
164
+ """
165
+
166
+ def __init__(self, database_url):
167
+ """
168
+ 初始化数据库连接
169
+
170
+ Args:
171
+ database_url (str): 数据库连接URL,例如:
172
+ mysql+pymysql://username:password@localhost:3306/database_name
173
+ """
174
+ self.engine = create_engine(database_url, echo=False)
175
+ self.Session = sessionmaker(bind=self.engine)
176
+
177
+ def create_tables(self):
178
+ """
179
+ 创建数据表
180
+ """
181
+ Base.metadata.create_all(self.engine)
182
+ print("数据表创建成功!")
183
+
184
+ def drop_tables(self):
185
+ """
186
+ 删除数据表
187
+ """
188
+ Base.metadata.drop_all(self.engine)
189
+ print("数据表删除成功!")
190
+
191
+ def _parse_date(self, date_str):
192
+ """
193
+ 解析日期字符串
194
+ """
195
+ if not date_str:
196
+ return None
197
+ try:
198
+ return datetime.strptime(date_str, '%Y-%m-%d').date()
199
+ except:
200
+ return None
201
+
202
+ def _extract_goods_labels(self, goods_label_list):
203
+ """
204
+ 提取商品标签名称列表
205
+ """
206
+ if not goods_label_list:
207
+ return []
208
+ return [label.get('name', '') for label in goods_label_list if isinstance(label, dict)]
209
+
210
+ def upsert_product_data(self, data_list):
211
+ """
212
+ 从JSON数据中执行upsert操作(插入或更新)
213
+
214
+ Args:
215
+ store_username (str): 店铺账号
216
+ data_list (list): 商品数据列表
217
+ """
218
+ session = self.Session()
219
+ try:
220
+ for data in data_list:
221
+
222
+ # 处理SKC数据
223
+ skc_record = self._upsert_skc_data(session, data)
224
+
225
+ # 处理SKU数据
226
+ for sku_data in data.get('skuList', []):
227
+ sku_data['local_skc_id'] = skc_record.id
228
+ self._upsert_sku_data(session, sku_data)
229
+
230
+ session.commit()
231
+ print(f"成功处理 {len(data_list)} 条商品数据")
232
+
233
+ except Exception as e:
234
+ session.rollback()
235
+ print(f"处理数据失败: {e}")
236
+ raise
237
+ finally:
238
+ session.close()
239
+
240
+ def _upsert_skc_data(self, session, data):
241
+ """
242
+ 插入或更新SKC数据
243
+ 返回SKC记录对象
244
+ """
245
+ skc_id = data.get('id')
246
+ existing_skc = session.query(SheinProductSkc).filter_by(skc_id=skc_id).first()
247
+
248
+ if existing_skc:
249
+ # 更新现有记录(保留用户备注)
250
+ existing_skc.store_username = data.get('store_username')
251
+ existing_skc.store_name = data.get('store_name')
252
+ existing_skc.store_manager = data.get('store_manager')
253
+ existing_skc.pic_url = data.get('picUrl')
254
+ existing_skc.supplier_code = data.get('supplierCode')
255
+ existing_skc.skc = data.get('skc')
256
+ existing_skc.spu = data.get('spu')
257
+ existing_skc.category_name = data.get('categoryName')
258
+ existing_skc.shelf_days = data.get('shelfDays')
259
+ existing_skc.shelf_date = self._parse_date(data.get('shelfDate'))
260
+ existing_skc.goods_label_list = self._extract_goods_labels(data.get('goodsLabelList'))
261
+ existing_skc.supply_status = data.get('supplyStatus', {}).get('name') if data.get('supplyStatus') else None
262
+ existing_skc.shelf_status = data.get('shelfStatus', {}).get('value') if data.get('shelfStatus') else None
263
+ existing_skc.goods_level = data.get('goodsLevel', {}).get('name') if data.get('goodsLevel') else None
264
+ existing_skc.group_flag = data.get('groupFlag')
265
+ existing_skc.goods_level_can_order_flag = 1 if data.get('goodsLevelCanOrderFlag') else 0
266
+ existing_skc.stock_standard = data.get('stockStandard', {}).get('value') if data.get('stockStandard') else None
267
+ existing_skc.stock_warn_status = data.get('stockWarnStatus', {}).get('value') if data.get('stockWarnStatus') else None
268
+ existing_skc.c7d_sale_cnt_sum = data.get('c7dSaleCntSum')
269
+ existing_skc.shein_sale_by_inventory = data.get('sheinSaleByInventory')
270
+ existing_skc.updated_at = datetime.now()
271
+ return existing_skc
272
+ else:
273
+ # 插入新记录
274
+ new_skc = SheinProductSkc(
275
+ skc_id=skc_id,
276
+ store_username=data.get('store_username'),
277
+ store_name=data.get('store_name'),
278
+ store_manager=data.get('store_manager'),
279
+ pic_url=data.get('picUrl'),
280
+ supplier_code=data.get('supplierCode'),
281
+ skc=data.get('skc'),
282
+ spu=data.get('spu'),
283
+ category_name=data.get('categoryName'),
284
+ shelf_days=data.get('shelfDays'),
285
+ shelf_date=self._parse_date(data.get('shelfDate')),
286
+ goods_label_list=self._extract_goods_labels(data.get('goodsLabelList')),
287
+ supply_status=data.get('supplyStatus', {}).get('name') if data.get('supplyStatus') else None,
288
+ shelf_status=data.get('shelfStatus', {}).get('value') if data.get('shelfStatus') else None,
289
+ goods_level=data.get('goodsLevel', {}).get('name') if data.get('goodsLevel') else None,
290
+ group_flag=data.get('groupFlag'),
291
+ goods_level_can_order_flag=1 if data.get('goodsLevelCanOrderFlag') else 0,
292
+ stock_standard=data.get('stockStandard', {}).get('value') if data.get('stockStandard') else None,
293
+ stock_warn_status=data.get('stockWarnStatus', {}).get('value') if data.get('stockWarnStatus') else None,
294
+ c7d_sale_cnt_sum=data.get('c7dSaleCntSum'),
295
+ shein_sale_by_inventory=data.get('sheinSaleByInventory')
296
+ )
297
+ session.add(new_skc)
298
+ session.flush() # 获取主键ID
299
+ return new_skc
300
+
301
+ def _upsert_sku_data(self, session, sku_data):
302
+ """
303
+ 插入或更新SKU数据
304
+ """
305
+ sku_id = sku_data.get('id')
306
+ existing_sku = session.query(SheinProductSku).filter_by(sku_id=sku_id).first()
307
+
308
+ if existing_sku:
309
+ # 更新现有记录(保留用户备注)
310
+ existing_sku.local_skc_id = sku_data.get('local_skc_id')
311
+ existing_sku.sort_value = sku_data.get('sortValue')
312
+ existing_sku.sku_code = sku_data.get('skuCode')
313
+ existing_sku.attr = sku_data.get('attr')
314
+ existing_sku.supplier_sku = sku_data.get('supplierSku')
315
+ existing_sku.order_cnt = sku_data.get('orderCnt')
316
+ existing_sku.total_sale_volume = sku_data.get('totalSaleVolume')
317
+ existing_sku.c7d_sale_cnt = sku_data.get('c7dSaleCnt')
318
+ existing_sku.c30d_sale_cnt = sku_data.get('c30dSaleCnt')
319
+ existing_sku.price = sku_data.get('price')
320
+ existing_sku.erp_cost_price = sku_data.get('erp_cost_price')
321
+ existing_sku.erp_supplier_name = sku_data.get('erp_supplier_name')
322
+ existing_sku.updated_at = datetime.now()
323
+ else:
324
+ # 插入新记录
325
+ new_sku = SheinProductSku(
326
+ sku_id=sku_id,
327
+ local_skc_id=sku_data.get('local_skc_id'),
328
+ sort_value=sku_data.get('sortValue'),
329
+ sku_code=sku_data.get('skuCode'),
330
+ attr=sku_data.get('attr'),
331
+ supplier_sku=sku_data.get('supplierSku'),
332
+ order_cnt=sku_data.get('orderCnt'),
333
+ total_sale_volume=sku_data.get('totalSaleVolume'),
334
+ c7d_sale_cnt=sku_data.get('c7dSaleCnt'),
335
+ c30d_sale_cnt=sku_data.get('c30dSaleCnt'),
336
+ price=sku_data.get('price'),
337
+ erp_cost_price=sku_data.get('erp_cost_price'),
338
+ erp_supplier_name=sku_data.get('erp_supplier_name')
339
+ )
340
+ session.add(new_sku)
341
+
342
+ def upsert_product_detail(self, spu, field_name, json_data):
343
+ """
344
+ 插入或更新商品详情数据
345
+
346
+ Args:
347
+ spu (str): SPU编码
348
+ field_name (str): 字段名称
349
+ json_data (dict): JSON数据
350
+ """
351
+ session = self.Session()
352
+ try:
353
+ existing_detail = session.query(SheinProductDetail).filter_by(
354
+ spu=spu, field_name=field_name
355
+ ).first()
356
+
357
+ if existing_detail:
358
+ # 更新现有记录
359
+ existing_detail.json_data = json_data
360
+ existing_detail.updated_at = datetime.now()
361
+ else:
362
+ # 插入新记录
363
+ new_detail = SheinProductDetail(
364
+ spu=spu,
365
+ field_name=field_name,
366
+ json_data=json_data
367
+ )
368
+ session.add(new_detail)
369
+
370
+ session.commit()
371
+ print(f"成功处理详情数据: spu={spu}, field_name={field_name}")
372
+
373
+ except Exception as e:
374
+ session.rollback()
375
+ print(f"处理详情数据失败: {e}")
376
+ raise
377
+ finally:
378
+ session.close()
379
+
380
+ def get_skc_products(self, limit=None, offset=None):
381
+ """
382
+ 查询SKC商品列表
383
+
384
+ Args:
385
+ limit (int): 限制返回数量
386
+ offset (int): 偏移量
387
+
388
+ Returns:
389
+ list: SKC商品列表
390
+ """
391
+ session = self.Session()
392
+ try:
393
+ query = session.query(SheinProductSkc)
394
+ if offset:
395
+ query = query.offset(offset)
396
+ if limit:
397
+ query = query.limit(limit)
398
+ return query.all()
399
+ finally:
400
+ session.close()
401
+
402
+ def search_products(self, **kwargs):
403
+ """
404
+ 根据条件搜索商品
405
+
406
+ Args:
407
+ **kwargs: 搜索条件,如skc, spu, store_username等
408
+
409
+ Returns:
410
+ list: 符合条件的商品列表
411
+ """
412
+ session = self.Session()
413
+ try:
414
+ query = session.query(SheinProductSkc)
415
+
416
+ # 根据传入的条件进行过滤
417
+ for key, value in kwargs.items():
418
+ if hasattr(SheinProductSkc, key) and value is not None:
419
+ if isinstance(value, str) and key in ['skc', 'spu', 'supplier_code', 'category_name']:
420
+ # 字符串字段支持模糊搜索
421
+ query = query.filter(getattr(SheinProductSkc, key).like(f'%{value}%'))
422
+ else:
423
+ query = query.filter(getattr(SheinProductSkc, key) == value)
424
+
425
+ return query.all()
426
+ finally:
427
+ session.close()
428
+
429
+ def example_usage():
430
+ """
431
+ 使用示例
432
+ """
433
+ # 数据库连接URL(请根据实际情况修改)
434
+ database_url = "mysql+pymysql://root:123wyk@localhost:3306/lz"
435
+
436
+ # 创建管理器实例
437
+ manager = SheinProductManager(database_url)
438
+
439
+ # 创建数据表
440
+ manager.create_tables()
441
+
442
+ # 从JSON文件导入数据
443
+ json_file = "skc_list_GS4355889.json"
444
+
445
+ # 读取JSON文件
446
+ with open(json_file, 'r', encoding='utf-8') as f:
447
+ data_dict = json.load(f)
448
+ for store_username, data_list in data_dict.items():
449
+ manager.upsert_product_data(data_list)
450
+
451
+ # 查询示例
452
+ products = manager.get_skc_products(limit=10)
453
+ for product in products:
454
+ print(f"SKC: {product.skc}, SPU: {product.spu}, 类目: {product.category_name}")
455
+
456
+ # 搜索示例
457
+ search_results = manager.search_products(store_username="GS4355889", shelf_status=1)
458
+ print(f"已上架商品数量: {len(search_results)}")
459
+
460
+ # 详情数据示例
461
+ # manager.upsert_product_detail("i250319906447", "attribute_template", {"template_id": "t23082580827"})
462
+
463
+ def example_usage2():
464
+ database_url = "mysql+pymysql://root:123wyk@localhost:3306/lz"
465
+ manager = SheinProductManager(database_url)
466
+ manager.create_tables()
467
+ # 从JSON文件导入数据
468
+ json_file = "attribute_template_t23082580827.json"
469
+ # 读取JSON文件
470
+ with open(json_file, 'r', encoding='utf-8') as f:
471
+ data_dict = json.load(f)
472
+ manager.upsert_product_detail("t23082580827", "attribute_template", data_dict)
473
+
474
+ if __name__ == "__main__":
475
+ pass
476
+ # example_usage()
qrpa/shein_lib.py CHANGED
@@ -634,17 +634,102 @@ class SheinLib:
634
634
  log(f'正在获取 {self.store_name} 最近一个月出库金额: {last_item["totalCustomerAmount"]}')
635
635
  return last_item['totalCustomerAmount']
636
636
 
637
+ def get_product_attr(self, spu, attr_name):
638
+ try:
639
+ product_detail = self.get_product_detail(spu)
640
+ product_type_id = product_detail.get('product_type_id')
641
+ category_id = product_detail.get('category_id')
642
+
643
+ if not product_type_id or not category_id:
644
+ return None # 或者根据需要返回一个默认值
645
+
646
+ attribute_template = self.get_attribute_templates(spu, category_id, [product_type_id])
647
+ attr_info = attribute_template.get('attribute_infos', [])
648
+
649
+ # 查找材质属性映射,防止没有匹配项
650
+ attr_item = next((item for item in attr_info if item.get('attribute_name') == attr_name), None)
651
+ if not attr_item:
652
+ return None # 或者返回一个默认值
653
+
654
+ attr_id = attr_item.get('attribute_id')
655
+
656
+ # 拿到产品材质的属性值ID
657
+ product_attribute_list = product_detail.get('product_attribute_list', [])
658
+ attribute_value_id = next((item['attribute_value_id'] for item in product_attribute_list if item.get('attribute_id') == attr_id), None)
659
+ if not attribute_value_id:
660
+ return None # 或者返回一个默认值
661
+
662
+ # 获取属性值名称
663
+ attr_value = next((item['attribute_value'] for item in attr_item.get('attribute_value_info_list', []) if item.get('attribute_value_id') == attribute_value_id), None)
664
+ return attr_value # 返回找到的属性值
665
+ except Exception as e:
666
+ log(f"Error occurred: {e}")
667
+ send_exception()
668
+ return None # 或者返回一个默认值
669
+
670
+ def get_attribute_templates(self, spu_name, category_id, product_type_id_list):
671
+ log(f'正在获取 {spu_name} 商品属性模板')
672
+
673
+ if not isinstance(product_type_id_list, list):
674
+ raise '参数错误: product_type_id_list 需要是列表'
675
+
676
+ cache_file = f'{self.config.auto_dir}/shein/attribute/attribute_template_{spu_name}.json'
677
+ attr_list = read_dict_from_file(cache_file, 3600 * 24 * 7)
678
+ if len(attr_list) > 0:
679
+ return attr_list
680
+
681
+ url = f"https://sso.geiwohuo.com/spmp-api-prefix/spmp/basic/query_attribute_templates"
682
+ payload = {
683
+ "category_id" : category_id,
684
+ "for_update" : True,
685
+ "product_type_id_list": product_type_id_list,
686
+ "spu_name" : spu_name
687
+ }
688
+ response_text = fetch(self.web_page, url, payload)
689
+ error_code = response_text.get('code')
690
+ if str(error_code) != '0':
691
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
692
+ info = response_text.get('info')
693
+
694
+ data = info.get('data')[0]
695
+ write_dict_to_file(cache_file, data)
696
+ return data
697
+
698
+ def get_product_detail(self, spu_name):
699
+ cache_file = f'{self.config.auto_dir}/shein/product_detail/product_detail_{spu_name}.json'
700
+ info = read_dict_from_file(cache_file, 3600 * 24 * 7)
701
+ if len(info) > 0:
702
+ return info
703
+
704
+ log(f'正在获取 {spu_name} 商品详情')
705
+ url = f"https://sso.geiwohuo.com/spmp-api-prefix/spmp/product/get_product_detail"
706
+ payload = {
707
+ "spu_name": spu_name
708
+ }
709
+ response_text = fetch(self.web_page, url, payload)
710
+ error_code = response_text.get('code')
711
+ if str(error_code) != '0':
712
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
713
+ info = response_text.get('info')
714
+ write_dict_to_file(cache_file, info)
715
+ return info
716
+
637
717
  # 存储商品库
638
718
  def store_product_info(self):
639
719
  # todo 商品详情 属性 规格 图片 重量 与 尺寸
640
720
  skc_list = self.get_bak_base_info()
641
721
  cache_file = f'{self.config.auto_dir}/shein/sku_price/sku_price_{self.store_username}.json'
642
722
  dict_sku = read_dict_from_file(cache_file)
723
+ dict_product_detail = []
643
724
  for skc_item in skc_list:
644
725
  skc_item['store_username'] = self.store_username
645
726
  skc_item['store_name'] = self.store_name
646
727
  skc_item['store_manager'] = self.config.shein_store_manager.get(str(self.store_username).lower())
647
728
  spu = skc_item['spu']
729
+ if spu not in dict_product_detail:
730
+ dict_product_detail.append(spu)
731
+ material = self.get_product_attr(spu, '材质')
732
+ log(material) # 这一步是为了获取 spu 详情和属性
648
733
 
649
734
  # 倒序遍历 skuList,安全删除
650
735
  for i in range(len(skc_item['skuList']) - 1, -1, -1):
@@ -660,6 +745,12 @@ class SheinLib:
660
745
  cache_file = f'{self.config.auto_dir}/shein/product/skc_list_{self.store_username}.json'
661
746
  write_dict_to_file_ex(cache_file, {self.store_username: skc_list}, [self.store_username])
662
747
 
748
+ skc_file = f'{self.config.auto_dir}/shein/product/skc_list_file.json'
749
+ write_dict_to_file_ex(skc_file, {self.store_username: cache_file}, [self.store_username])
750
+
751
+ detail_file = f'{self.config.auto_dir}/shein/product/product_detail_file.json'
752
+ write_dict_to_file_ex(detail_file, {self.store_username: dict_product_detail}, [self.store_username])
753
+
663
754
  # 获取备货信息列表
664
755
  def get_bak_base_info(self):
665
756
  log(f'获取备货信息列表 {self.store_name} {self.store_username}')
qrpa/shein_mysql.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import json
2
2
 
3
3
  from .mysql_module.shein_return_order_model import SheinReturnOrderManager
4
+ from .mysql_module.shein_product_model import SheinProductManager
4
5
  from .fun_base import log
5
6
 
6
7
  class SheinMysql:
@@ -17,4 +18,37 @@ class SheinMysql:
17
18
  with open(json_file, 'r', encoding='utf-8') as f:
18
19
  dict = json.load(f)
19
20
  for store_username, data_list in dict.items():
20
- manager.upsert_return_order_data(store_username, data_list)
21
+ manager.upsert_return_order_data(store_username, data_list)
22
+
23
+ def upsert_shein_product(self, json_file):
24
+ log(f'当前使用的数据库: {self.config.db.database_url}')
25
+ # 创建管理器实例
26
+ manager = SheinProductManager(self.config.db.database_url)
27
+ # 创建数据表
28
+ manager.create_tables()
29
+ with open(json_file, 'r', encoding='utf-8') as f:
30
+ file_list = json.load(f)
31
+ for store_username, store_skc_list_file in file_list.items():
32
+ with open(store_skc_list_file, 'r', encoding='utf-8') as f:
33
+ dict_store_skc_list = json.load(f)
34
+ for store_username, data_list in dict_store_skc_list.items():
35
+ manager.upsert_product_data(data_list)
36
+
37
+ def upsert_shein_product_info(self, json_file):
38
+ log(f'当前使用的数据库: {self.config.db.database_url}')
39
+ # 创建管理器实例
40
+ manager = SheinProductManager(self.config.db.database_url)
41
+ # 创建数据表
42
+ manager.create_tables()
43
+ with open(json_file, 'r', encoding='utf-8') as f:
44
+ file_list = json.load(f)
45
+ for store_username, store_spu_list in file_list.items():
46
+ for spu in store_spu_list:
47
+ product_detail_file = f'{self.config.auto_dir}/shein/product_detail/product_detail_{spu}.json'
48
+ attribute_file = f'{self.config.auto_dir}/shein/attribute/attribute_template_{spu}.json'
49
+ with open(product_detail_file, 'r', encoding='utf-8') as f:
50
+ data_list = json.load(f)
51
+ manager.upsert_product_detail(spu, 'product_detail', data_list)
52
+ with open(attribute_file, 'r', encoding='utf-8') as f:
53
+ data_list = json.load(f)
54
+ manager.upsert_product_detail(spu, 'attribute_template', data_list)
qrpa/shein_ziniao.py CHANGED
@@ -259,6 +259,7 @@ class ZiniaoBrowser:
259
259
  page = browser_context.pages[0]
260
260
  page.goto(launcher_page)
261
261
  page.wait_for_load_state('load')
262
+ page.wait_for_timeout(6000)
262
263
 
263
264
  run_func(page, store_username, store_name, task_key)
264
265
 
@@ -278,15 +279,14 @@ class ZiniaoTaskManager:
278
279
  is_skip_store: Optional[Callable] = None
279
280
  ):
280
281
  """运行单个店铺的任务"""
282
+ store_id = browser_info.get('browserOauth')
283
+ store_name = browser_info.get("browserName")
284
+ store_username = browser_info.get("store_username")
285
+
281
286
  retry_count = 0
282
287
  while True:
283
288
  try:
284
289
  retry_count += 1
285
-
286
- store_id = browser_info.get('browserOauth')
287
- store_name = browser_info.get("browserName")
288
- store_username = browser_info.get("store_username")
289
-
290
290
  # 记录店铺账号与店铺别名对应关系
291
291
  cache_file = f'{self.config.auto_dir}/shein_store_alias.json'
292
292
  write_dict_to_file_ex(cache_file, {store_username: store_name}, [store_username])
@@ -349,7 +349,7 @@ class ZiniaoTaskManager:
349
349
  self.browser.close_store(store_id)
350
350
  break
351
351
  except:
352
- send_exception(f'第{retry_count}次运行失败,准备重新打开店铺')
352
+ send_exception(f'第{retry_count}次运行失败,准备重新打开店铺: {store_username},{store_name},{store_id}')
353
353
  if retry_count > 5:
354
354
  break
355
355
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qrpa
3
- Version: 1.0.66
3
+ Version: 1.0.67
4
4
  Summary: qsir's rpa library
5
5
  Author: QSir
6
6
  Author-email: QSir <1171725650@qq.com>
@@ -11,10 +11,10 @@ qrpa/fun_web.py,sha256=F6cxwwOxB8twg2XK73oAvKla0FqpwDYJiM37CWmFwXo,6322
11
11
  qrpa/fun_win.py,sha256=-LnTeocdTt72NVH6VgLdpAT9_C5oV9okeudXG6CftMA,8034
12
12
  qrpa/shein_daily_report_model.py,sha256=H8oZmIN5Pyqe306W1_xuz87lOqLQ_LI5RjXbaxDkIzE,12589
13
13
  qrpa/shein_excel.py,sha256=vtmeEF_LbH6cVyitDDCNjuT76Nuov6Zvhsf-gIMd0H0,124780
14
- qrpa/shein_lib.py,sha256=j77mz_ImVOxtXAQOOibyUiq_4golmPqP7D_WYKfG7E8,122338
15
- qrpa/shein_mysql.py,sha256=MGPJsz13evsLygZWhmitpPzUswiTKZ91VFvr8KA0M40,750
14
+ qrpa/shein_lib.py,sha256=qeo46Htko_12-Tsag78hjyeMHoNaySCXgqT-h_-IjVs,126711
15
+ qrpa/shein_mysql.py,sha256=SrgBYPNWaKHIpD5Q7hqz3GWvytXO8u9SPvKxJvLwYsI,2720
16
16
  qrpa/shein_sqlite.py,sha256=ZQwD0Gz81q9WY7tY2HMEYvSF9r3N_G_Aur3bYfST9WY,5707
17
- qrpa/shein_ziniao.py,sha256=kAOirjawPf-VxBxHFNpdDHCN2zL-O1U-2xybpmt34Xs,18692
17
+ qrpa/shein_ziniao.py,sha256=Xc4pgSa7PxgmR24rClgz_HcTRb2fdbXp6slzfpCOThI,18745
18
18
  qrpa/temu_chrome.py,sha256=CbtFy1QPan9xJdJcNZj-EsVGhUvv3ZTEPVDEA4-im40,2803
19
19
  qrpa/temu_excel.py,sha256=2hGw76YWzkTZGyFCuuUAab4oHptYX9a6U6yjpNsL7FE,6990
20
20
  qrpa/temu_lib.py,sha256=hYB59zsLS3m3NTic_duTwPMOTSxlHyQVa8OhHnHm-1g,7199
@@ -22,8 +22,9 @@ qrpa/time_utils.py,sha256=ef0hhbN_6b-gcnz5ETIVOoxemIMvcxGVGGIRnHnGaBo,29564
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=qViI_Ik3SkXXxqJ1nXjimvfB_a5uiwW9RXL0fOreBao,18880
25
26
  qrpa/mysql_module/shein_return_order_model.py,sha256=Zt-bGOH_kCDbakW7uaTmqqo_qTT8v424yidcYSfWvWM,26562
26
- qrpa-1.0.66.dist-info/METADATA,sha256=lY0GLxRmJagu_OgNkZPVsJl8UuTS586Q_Ds4sreo0fc,231
27
- qrpa-1.0.66.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
- qrpa-1.0.66.dist-info/top_level.txt,sha256=F6T5igi0fhXDucPPUbmmSC0qFCDEsH5eVijfVF48OFU,5
29
- qrpa-1.0.66.dist-info/RECORD,,
27
+ qrpa-1.0.67.dist-info/METADATA,sha256=zI6fBzT7JgPGnMZcC-Td_Iw0UkRKIFJEIOYXUcR9NZ4,231
28
+ qrpa-1.0.67.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
29
+ qrpa-1.0.67.dist-info/top_level.txt,sha256=F6T5igi0fhXDucPPUbmmSC0qFCDEsH5eVijfVF48OFU,5
30
+ qrpa-1.0.67.dist-info/RECORD,,
File without changes