mdbq 1.1.2__tar.gz → 1.1.3__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.
Files changed (47) hide show
  1. {mdbq-1.1.2 → mdbq-1.1.3}/PKG-INFO +1 -1
  2. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/aggregation/aggregation.py +76 -30
  3. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/aggregation/df_types.py +1 -1
  4. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/aggregation/mysql_types.py +5 -4
  5. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/aggregation/query_data.py +6 -6
  6. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/clean/data_clean.py +6 -2
  7. mdbq-1.1.3/mdbq/dataframe/converter.py +81 -0
  8. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/mongo/mongo.py +3 -3
  9. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/mysql/mysql.py +37 -26
  10. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq.egg-info/PKG-INFO +1 -1
  11. {mdbq-1.1.2 → mdbq-1.1.3}/setup.py +1 -1
  12. mdbq-1.1.2/mdbq/dataframe/converter.py +0 -112
  13. {mdbq-1.1.2 → mdbq-1.1.3}/README.txt +0 -0
  14. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/__init__.py +0 -0
  15. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/__version__.py +0 -0
  16. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/aggregation/__init__.py +0 -0
  17. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/aggregation/optimize_data.py +0 -0
  18. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/bdup/__init__.py +0 -0
  19. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/bdup/bdup.py +0 -0
  20. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/clean/__init__.py +0 -0
  21. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/company/__init__.py +0 -0
  22. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/company/copysh.py +0 -0
  23. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/config/__init__.py +0 -0
  24. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/config/get_myconf.py +0 -0
  25. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/config/products.py +0 -0
  26. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/config/set_support.py +0 -0
  27. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/config/update_conf.py +0 -0
  28. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/dataframe/__init__.py +0 -0
  29. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/log/__init__.py +0 -0
  30. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/log/mylogger.py +0 -0
  31. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/mongo/__init__.py +0 -0
  32. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/mysql/__init__.py +0 -0
  33. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/mysql/data_types_/345/215/263/345/260/206/345/210/240/351/231/244.py" +0 -0
  34. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/mysql/s_query.py +0 -0
  35. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/mysql/year_month_day.py +0 -0
  36. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/other/__init__.py +0 -0
  37. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/other/porxy.py +0 -0
  38. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/other/pov_city.py +0 -0
  39. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/other/ua_sj.py +0 -0
  40. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/pbix/__init__.py +0 -0
  41. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/pbix/pbix_refresh.py +0 -0
  42. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/pbix/refresh_all.py +0 -0
  43. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq/spider/__init__.py +0 -0
  44. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq.egg-info/SOURCES.txt +0 -0
  45. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq.egg-info/dependency_links.txt +0 -0
  46. {mdbq-1.1.2 → mdbq-1.1.3}/mdbq.egg-info/top_level.txt +0 -0
  47. {mdbq-1.1.2 → mdbq-1.1.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mdbq
3
- Version: 1.1.2
3
+ Version: 1.1.3
4
4
  Home-page: https://pypi.org/project/mdbsql
5
5
  Author: xigua,
6
6
  Author-email: 2587125111@qq.com
@@ -23,6 +23,21 @@ import getpass
23
23
 
24
24
  warnings.filterwarnings('ignore')
25
25
  """
26
+ 建表规范:
27
+ 1. 先建 json 表,再批量上传数据;(非常重要)
28
+ 在初创数据表时, 如果有不同类报表,新版和旧版都要取一个文件,先创建数据表,再导其他数据;
29
+ 例如有的报表转化率是0%,数据类型会被识别为2位小数: decimal(10, 2),正常值应类似 0.43%,应保留4个小数, 创建类型为 decimal(10, 4)
30
+ 为了避免以上可能数据类型错误的情况,初创时要先检查一遍数据类型,确认没问题再导其他数据!
31
+ 即导一个表,然后删除数据库,但保留 mysql_types.json,并检查表的数据类型(有问题就手动改 json 文件),之后会按 json 的 types 上传数据;
32
+
33
+ 2. 数据库和数据表名如果有字母,必须使用小写,大写在建库后会自动变小写,再次上传数据会找不到数据库(macos和linux都有这种情况)
34
+ 3. 无论是数据库/表/列名还是值,尽量避免特殊字符或者表情符号,数据库/表/列名尽量都使用 `列名` 转义,避免错误
35
+ 4. 小数必须使用 decimal, 禁止 float 和 double, 因为计算精度差异,后续需要聚合数据时会引发很多问题
36
+ 5. 日期类型暂时全部用 DATETIME,使用 DATE 在后续可能会重复插入不能排重,因为 df 进来的数据, 日期是带时间的,而数据库中日期不含时间
37
+ 6. 目前小数自动适配类型转换,对于文本或者大数全部用 mediumtext, 因为部分表涉及爬虫数据,进来的字符长度未知,暂时统一 mediumtext 避免入库失败
38
+
39
+
40
+
26
41
  1. DatabaseUpdate: 程序用于对爬虫下载的原始数据进行清洗并入库;
27
42
  数据清洗主要包括对字段名的非法字符处理,对 df 中的非法值进行预处理;
28
43
  数据入库时会较检并更新本地 json 文件的 dtypes 信息;
@@ -91,8 +106,8 @@ class DatabaseUpdate:
91
106
  # df.replace(to_replace=['\\N'], value=0, regex=False, inplace=True) # 替换掉特殊字符
92
107
  # df.replace(to_replace=[''], value=0, regex=False, inplace=True)
93
108
  # df.fillna(0, inplace=True)
94
- db_name = '天猫数据2'
95
- collection_name = f'推广数据_{tg_name}'
109
+ db_name = '推广数据2'
110
+ collection_name = f'{tg_name}'
96
111
  if name.endswith('.csv') and '超级直播' in name:
97
112
  # 超级直播
98
113
  df = pd.read_csv(os.path.join(root, name), encoding=encoding, header=0, na_filter=False)
@@ -109,8 +124,8 @@ class DatabaseUpdate:
109
124
  shop_name = ''
110
125
  # df.replace(to_replace=['\\N'], value=0, regex=False, inplace=True) # 替换掉特殊字符
111
126
  # df.replace(to_replace=[''], value=0, regex=False, inplace=True)
112
- db_name = '天猫数据2'
113
- collection_name = '推广数据_超级直播'
127
+ db_name = '推广数据2'
128
+ collection_name = '超级直播'
114
129
  elif name.endswith('.xls') and '短直联投' in name:
115
130
  # 短直联投
116
131
  df = pd.read_excel(os.path.join(root, name), sheet_name=None, header=0)
@@ -119,8 +134,8 @@ class DatabaseUpdate:
119
134
  print(f'{name} 报表数据为空')
120
135
  continue
121
136
  # df.replace(to_replace=[''], value=0, regex=False, inplace=True)
122
- db_name = '天猫数据2'
123
- collection_name = '推广数据_短直联投'
137
+ db_name = '推广数据2'
138
+ collection_name = '短直联投'
124
139
  elif name.endswith('.xls') and '视频加速推广' in name:
125
140
  # 超级短视频
126
141
  df = pd.read_excel(os.path.join(root, name), sheet_name=None, header=0)
@@ -129,15 +144,15 @@ class DatabaseUpdate:
129
144
  print(f'{name} 报表数据为空')
130
145
  continue
131
146
  # df.replace(to_replace=[''], value=0, regex=False, inplace=True)
132
- db_name = '天猫数据2'
133
- collection_name = '推广数据_超级短视频'
147
+ db_name = '推广数据2'
148
+ collection_name = '超级短视频'
134
149
  if '人群报表汇总' in name:
135
150
  df = pd.read_csv(os.path.join(root, name), encoding='utf-8_sig', header=1, na_filter=False)
136
151
  if len(df) == 0:
137
152
  print(f'{name} 报表数据为空')
138
153
  continue
139
- db_name = '天猫数据2'
140
- collection_name = '天猫_达摩盘_DMP报表'
154
+ db_name = '推广数据2'
155
+ collection_name = '达摩盘_dmp报表'
141
156
  # ----------------- 推广报表 分割线 -----------------
142
157
  # ----------------- 推广报表 分割线 -----------------
143
158
  date01 = re.findall(r'(\d{4}-\d{2}-\d{2})_\d{4}-\d{2}-\d{2}', str(name))
@@ -162,7 +177,7 @@ class DatabaseUpdate:
162
177
  else '智能场景' if x == '智能场景(原万相台)'
163
178
  else x
164
179
  )
165
- db_name = '生意参谋数据2'
180
+ db_name = '生意参谋2'
166
181
  if '经营优势' in df['一级来源'].tolist(): # 新版流量
167
182
  if '数据周期' in df.columns.tolist():
168
183
  collection_name='店铺来源_月数据_新版'
@@ -185,7 +200,7 @@ class DatabaseUpdate:
185
200
  if date01[0] != date02[0]:
186
201
  data_lis = date01[0] + '_' + date02[0]
187
202
  df.insert(loc=1, column='数据周期', value=data_lis)
188
- db_name = '生意参谋数据2'
203
+ db_name = '生意参谋2'
189
204
  collection_name = '商品排行'
190
205
  elif name.endswith('.xls') and '参谋店铺整体日报' in name:
191
206
  # 自助取数,店铺日报
@@ -194,7 +209,7 @@ class DatabaseUpdate:
194
209
  print(f'{name} 报表数据为空')
195
210
  continue
196
211
  df.rename(columns={'统计日期': '日期'}, inplace=True)
197
- db_name = '生意参谋数据2'
212
+ db_name = '生意参谋2'
198
213
  collection_name = '自助取数_整体日报'
199
214
  elif name.endswith('.xls') and '参谋每日流量_自助取数_新版' in name:
200
215
  # 自助取数,每日流量
@@ -213,7 +228,7 @@ class DatabaseUpdate:
213
228
  else '智能场景' if x == '智能场景(原万相台)'
214
229
  else x
215
230
  )
216
- db_name = '生意参谋数据2'
231
+ db_name = '生意参谋2'
217
232
  collection_name = '自助取数_每日流量'
218
233
  elif name.endswith('.xls') and '商品sku' in name:
219
234
  # 自助取数,商品sku
@@ -227,7 +242,7 @@ class DatabaseUpdate:
227
242
  'SKU ID': 'sku id',
228
243
  '商品SKU': '商品sku',
229
244
  }, inplace=True)
230
- db_name = '生意参谋数据2'
245
+ db_name = '生意参谋2'
231
246
  collection_name = '自助取数_商品sku'
232
247
  elif name.endswith('.xls') and '参谋店铺流量来源(月)' in name:
233
248
  # 自助取数,月店铺流量来源
@@ -247,7 +262,7 @@ class DatabaseUpdate:
247
262
  else x
248
263
  )
249
264
  df['日期'] = df['数据周期'].apply(lambda x: re.findall('(.*) ~', x)[0])
250
- db_name = '生意参谋数据2'
265
+ db_name = '生意参谋2'
251
266
  collection_name = '自助取数_店铺流量_月数据'
252
267
  elif name.endswith('.csv') and 'baobei' in name:
253
268
  # 生意经宝贝指标日数据
@@ -340,7 +355,7 @@ class DatabaseUpdate:
340
355
  continue
341
356
  df.rename(columns={'场次ID': '场次id', '商品ID': '商品id'}, inplace=True)
342
357
  df['日期'] = df['支付时间'].apply(lambda x: x.strftime('%Y-%m-%d'))
343
- db_name = '生意参谋数据2'
358
+ db_name = '生意参谋2'
344
359
  collection_name = '直播间成交订单明细'
345
360
  elif name.endswith('.xlsx') and '直播间大盘数据' in name:
346
361
  # 直播间大盘数据
@@ -349,7 +364,7 @@ class DatabaseUpdate:
349
364
  print(f'{name} 报表数据为空')
350
365
  continue
351
366
  df.rename(columns={'统计日期': '日期'}, inplace=True)
352
- db_name = '生意参谋数据2'
367
+ db_name = '生意参谋2'
353
368
  collection_name = '直播间大盘数据'
354
369
  elif name.endswith('.xls') and '直播业绩-成交拆解' in name:
355
370
  # 直播业绩-成交拆解
@@ -358,7 +373,7 @@ class DatabaseUpdate:
358
373
  print(f'{name} 报表数据为空')
359
374
  continue
360
375
  df.rename(columns={'统计日期': '日期'}, inplace=True)
361
- db_name = '生意参谋数据2'
376
+ db_name = '生意参谋2'
362
377
  collection_name = '直播业绩'
363
378
  elif name.endswith('.csv') and '淘宝店铺数据' in name:
364
379
  df = pd.read_csv(os.path.join(root, name), encoding='utf-8_sig', header=0, na_filter=False)
@@ -370,11 +385,11 @@ class DatabaseUpdate:
370
385
  df = df[df['人群规模'] != '']
371
386
  if len(df) == 0:
372
387
  continue
373
- db_name = '天猫数据2'
388
+ db_name = '推广数据2'
374
389
  collection_name = '万相台_人群洞察'
375
390
  elif name.endswith('.csv') and '客户_客户概况_画像' in name:
376
391
  df = pd.read_csv(os.path.join(root, name), encoding='utf-8_sig', header=0, na_filter=False)
377
- db_name = '生意参谋数据2'
392
+ db_name = '生意参谋2'
378
393
  collection_name = '客户_客户概况_画像'
379
394
  elif name.endswith('.csv') and '市场排行_店铺' in name:
380
395
  df = pd.read_csv(os.path.join(root, name), encoding='utf-8_sig', header=0, na_filter=False)
@@ -556,7 +571,7 @@ class DatabaseUpdate:
556
571
  continue
557
572
  df = df[df['缩略图'] != '合计']
558
573
  db_name = '生意经2'
559
- collection_name = 'E3_零售明细统计'
574
+ collection_name = 'e3_零售明细统计'
560
575
 
561
576
  # 商品素材,必须保持放在最后处理
562
577
  elif name.endswith('xlsx'):
@@ -615,8 +630,8 @@ class DatabaseUpdate:
615
630
  # print(f'{name}/{sheet4} 跳过')
616
631
  continue
617
632
  df.insert(loc=1, column='报表类型', value=sheet4)
618
- db_name = '天猫数据2'
619
- collection_name = f'推广数据_品销宝_{sheet4}'
633
+ db_name = '推广数据2'
634
+ collection_name = f'品销宝_{sheet4}'
620
635
  self.datas.append(
621
636
  {
622
637
  '数据库名': db_name,
@@ -834,7 +849,7 @@ class DatabaseUpdate:
834
849
  return df
835
850
 
836
851
 
837
- def upload(path, db_name, collection_name):
852
+ def upload(path, db_name, collection_name, one_file=False):
838
853
  """ 上传一个文件夹到数据库 """
839
854
  username, password, host, port = get_myconf.select_config_values(
840
855
  target_service='home_lx',
@@ -905,10 +920,40 @@ def upload(path, db_name, collection_name):
905
920
  except Exception as e:
906
921
  print(name, e)
907
922
  i += 1
923
+ if one_file: # 给 file_dir 函数调用
924
+ break # 每个文件夹只上传一个文件
908
925
  if d.client:
909
926
  d.client.close() # 必须手动关闭数据库连接
910
927
 
911
928
 
929
+ def file_dir():
930
+ """
931
+ 按照文件记录对照表
932
+ 批量上传数据库
933
+ """
934
+ filename = '文件目录对照表.csv'
935
+ if platform.system() == 'Windows':
936
+ path = 'C:\\同步空间\\BaiduSyncdisk\\原始文件2'
937
+ else:
938
+ path = '/Users/xigua/数据中心/原始文件2'
939
+ df = pd.read_csv(os.path.join(path, filename), encoding='utf-8_sig', header=0, na_filter=False)
940
+ datas = df.to_dict('records') # 转字典
941
+ for data in datas:
942
+ # print(data)
943
+ if data['入库进度'] == 0:
944
+ sub_path, db_name, collection_name = data['子文件夹'], data['数据库名'], data['数据表']
945
+ # print(os.path.join(path, sub_path), db_name, collection_name)
946
+ upload(
947
+ path=dir_path,
948
+ db_name=db_name,
949
+ collection_name=collection_name,
950
+ one_file=True
951
+ )
952
+ data.update({'入库进度': 1}) # 更新进度
953
+ df = pd.DataFrame.from_dict(datas, orient='columns')
954
+ df.to_csv(os.path.join(path, filename), encoding='utf-8_sig', index=False, header=True)
955
+
956
+
912
957
  def main():
913
958
  d = DatabaseUpdate(path='/Users/xigua/Downloads')
914
959
  d.new_unzip(is_move=True)
@@ -924,8 +969,9 @@ def main():
924
969
  if __name__ == '__main__':
925
970
  # username, password, host, port = get_myconf.select_config_values(target_service='nas', database='mysql')
926
971
  # print(username, password, host, port)
927
- upload(
928
- path='/Users/xigua/数据中心/原始文件2/生意经/宝贝指标',
929
- db_name = '生意经2',
930
- collection_name = '宝贝指标',
931
- )
972
+ # upload(
973
+ # path='/Users/xigua/数据中心/原始文件2/生意经/E3零售明细统计',
974
+ # db_name = '生意经2',
975
+ # collection_name = 'e3_零售明细统计',
976
+ # )
977
+ file_dir()
@@ -80,7 +80,7 @@ class DataTypes:
80
80
  self.datas.update(dtypes)
81
81
  return self.datas[db_name][collection_name]
82
82
  else: # 存在则读取,并更新 df 的 dtypes
83
- if db_name in list(self.datas.keys()): # ['京东数据2', '天猫数据2', '生意参谋数据2', '生意经2']
83
+ if db_name in list(self.datas.keys()): # ['京东数据2', '推广数据2', '生意参谋2', '生意经2']
84
84
  if collection_name in list(self.datas[db_name].keys()):
85
85
  if is_file_dtype: # 旧数据优先
86
86
  # # 用 dtypes 更新, 允许手动指定 json 文件里面的数据类型
@@ -67,7 +67,7 @@ class DataTypes:
67
67
  def get_mysql_types(self, cl, dtypes, db_name, table_name, is_file_dtype=True):
68
68
  """ 更新 mysql 的 types 信息到 json 文件 """
69
69
  if cl in self.datas.keys():
70
- if db_name in list(self.datas[cl].keys()): # ['京东数据2', '天猫数据2', '生意参谋数据2', '生意经2']
70
+ if db_name in list(self.datas[cl].keys()): # ['京东数据2', '推广数据2', '生意参谋2', '生意经2']
71
71
  if table_name in list(self.datas[cl][db_name].keys()):
72
72
  if is_file_dtype: # 旧数据优先
73
73
  # # 用 dtypes 更新, 允许手动指定 json 文件里面的数据类型
@@ -178,14 +178,14 @@ def mysql_all_dtypes(db_name=None, table_name=None, path=None):
178
178
 
179
179
  # db_name_lists = [
180
180
  # '京东数据2',
181
- # '天猫数据2',
181
+ # '推广数据2',
182
182
  # '市场数据2',
183
- # '生意参谋数据2',
183
+ # '生意参谋2',
184
184
  # '生意经2',
185
185
  # '属性设置2',
186
186
  # '聚合数据',
187
187
  # ]
188
- results = []
188
+ results = [] # 返回结果示例: [{'云电影': '电影更新'}, {'生意经2': 'e3_零售明细统计'}]
189
189
  for db_ in db_name_lists:
190
190
  config.update({'database': db_}) # 添加更新 config 字段
191
191
  connection = pymysql.connect(**config) # 连接数据库
@@ -233,6 +233,7 @@ def mysql_all_dtypes(db_name=None, table_name=None, path=None):
233
233
  )
234
234
  else:
235
235
  print(f'数据库回传数据(name_type)为空')
236
+ # print(d.datas)
236
237
  d.as_json_file()
237
238
 
238
239
  if __name__ == '__main__':
@@ -48,8 +48,8 @@ class MongoDatasQuery:
48
48
  '直接成交金额': 1,
49
49
  }
50
50
  df = self.download.data_to_df(
51
- db_name='天猫数据2',
52
- collection_name='推广数据_宝贝主体报表',
51
+ db_name='推广数据2',
52
+ collection_name='宝贝主体报表',
53
53
  projection=projection,
54
54
  )
55
55
  return df
@@ -100,8 +100,8 @@ class MysqlDatasQuery:
100
100
  '直接成交金额': 1,
101
101
  }
102
102
  df = self.download.data_to_df(
103
- db_name='天猫数据2',
104
- table_name='推广数据_宝贝主体报表',
103
+ db_name='推广数据2',
104
+ table_name='宝贝主体报表',
105
105
  start_date=start_date,
106
106
  end_date=end_date,
107
107
  projection=projection,
@@ -377,7 +377,7 @@ class GroupBy:
377
377
  def performance(self, bb_tg=True):
378
378
  # print(self.data_tgyj)
379
379
  tg, syj, idbm, pic, cost = (
380
- self.data_tgyj['推广数据_宝贝主体报表'],
380
+ self.data_tgyj['宝贝主体报表'],
381
381
  self.data_tgyj['天猫生意经_宝贝指标'],
382
382
  self.data_tgyj['商品id编码表'],
383
383
  self.data_tgyj['商品id图片对照表'],
@@ -502,7 +502,7 @@ def data_aggregation(service_databases=[{}]):
502
502
  data_dict = [
503
503
  {
504
504
  '数据库名': '聚合数据',
505
- '集合名': '推广数据_宝贝主体报表',
505
+ '集合名': '宝贝主体报表',
506
506
  '数据主体': sdq.tg_wxt(),
507
507
  },
508
508
  {
@@ -1113,8 +1113,12 @@ class DataClean:
1113
1113
  t_path = str(pathlib.Path(self.source_path, '京东报表/JD商家榜单'))
1114
1114
  bib(t_path, _as_month=True)
1115
1115
  elif name.endswith('.csv') and '导出-批量任务' in name:
1116
- t_path = str(pathlib.Path(self.source_path, '京东报表/商品信息导出'))
1117
- bib(t_path, _as_month=False)
1116
+ if 'SKU' in name:
1117
+ t_path = str(pathlib.Path(self.source_path, '京东报表/商品信息导出/sku'))
1118
+ bib(t_path, _as_month=False)
1119
+ elif 'SPU' in name:
1120
+ t_path = str(pathlib.Path(self.source_path, '京东报表/商品信息导出/spu'))
1121
+ bib(t_path, _as_month=False)
1118
1122
  elif name.endswith('.csv') and '_行业分析_竞争分析' in name:
1119
1123
  t_path = str(pathlib.Path(self.source_path, '京东报表/行业竞争分析'))
1120
1124
  bib(t_path, _as_month=True)
@@ -0,0 +1,81 @@
1
+ # -*- coding:utf-8 -*-
2
+ import pandas as pd
3
+ import numpy as np
4
+ from decimal import Decimal
5
+ import re
6
+
7
+
8
+ class DataFrameConverter(object):
9
+ def __init__(self, df=pd.DataFrame({})):
10
+ self.df = df
11
+
12
+ def convert_df_cols(self, df=pd.DataFrame({})):
13
+ """
14
+ 清理 dataframe 非法值
15
+ 对数据类型进行转换(尝试将 object 类型转为 int 或 float)
16
+ """
17
+ if len(df) == 0:
18
+ df = self.df
19
+ if len(df) == 0:
20
+ return
21
+
22
+ def find_longest_decimal_value(number_list):
23
+ # 取列表中小数位数最长的值
24
+ longest_value = None
25
+ max_decimals = 0
26
+ for num in number_list:
27
+ decimal_places = len(str(num).split('.')[1])
28
+ if decimal_places > max_decimals:
29
+ max_decimals = decimal_places
30
+ longest_value = num
31
+ return longest_value
32
+
33
+ # dtypes = df.dtypes.apply(str).to_dict() # 将 dataframe 数据类型转为字典形式
34
+ df.replace([np.inf, -np.inf], 0, inplace=True) # 清理一些非法值
35
+ df.replace(to_replace=['\\N', '-', '--', '', 'nan'], value=0, regex=False, inplace=True) # 替换掉特殊字符
36
+ df.replace(to_replace=[','], value='', regex=True, inplace=True)
37
+ df.replace(to_replace=['="'], value='', regex=True, inplace=True) # ="和"不可以放在一起清洗, 因为有: id=86785565
38
+ df.replace(to_replace=['"'], value='', regex=True, inplace=True)
39
+ cols = df.columns.tolist()
40
+
41
+ for col in cols:
42
+ # 百分比在某些数据库中不兼容, 转换百分比为小数
43
+ df[col] = df[col].apply(lambda x: float(float((str(x).rstrip("%"))) / 100) if str(x).endswith('%') and '~' not in str(x) else x)
44
+ # 尝试转换合适的数据类型
45
+ if df[col].dtype == 'object':
46
+ try:
47
+ df[col] = df[col].apply(lambda x: int(x) if '_' not in str(x) else x)
48
+ except:
49
+ try:
50
+ df[col] = df[col].apply(lambda x: float(x) if '_' not in str(x) else x)
51
+ except:
52
+ pass
53
+ if df[col].dtype == 'float' or df[col].dtype == 'float64': # 对于小数类型, 保留 6 位小数
54
+ df[col] = df[col].fillna(0.0).apply(lambda x: round(x, 6))
55
+ # df[col] = df[col].fillna(0.0).apply(lambda x: "{:.6f}".format(x))
56
+ # df[col] = df[col].apply('float64')
57
+
58
+ # 转换日期样式的列为日期类型
59
+ value = df.loc[0, col]
60
+ if value:
61
+ res = re.match(r'\d{4}-\d{2}-\d{2}|\d{4}-\d{2}-\d{2} |\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}', str(value))
62
+ if res:
63
+ try:
64
+ df[col] = df[col].apply(lambda x: pd.to_datetime(x))
65
+ except:
66
+ pass
67
+ new_col = col.lower()
68
+ df.rename(columns={col: new_col}, inplace=True)
69
+ df.fillna(0, inplace=True)
70
+ return df
71
+
72
+
73
+ if __name__ == '__main__':
74
+ # df = pd.DataFrame(np.random.randn(5, 3), columns=['a', 'b', 'c'])
75
+ # converter = DataFrameConverter()
76
+ # df = converter.convert_df_cols(df)
77
+ # print(df['a'].dtype)
78
+ # print(df)
79
+ pattern = 'dfa_dfawr__'
80
+ pattern = re.sub(r'_+$', '', pattern)
81
+ print(pattern)
@@ -658,7 +658,7 @@ class OptimizeDatas:
658
658
  def rename_column(self):
659
659
  """ 批量修改数据库的列名 """
660
660
  """
661
- # for db_name in ['京东数据2', '天猫数据2', '市场数据2', '生意参谋数据2', '生意经2', '属性设置2',]:
661
+ # for db_name in ['京东数据2', '推广数据2', '市场数据2', '生意参谋2', '生意经2', '属性设置2',]:
662
662
  # s = OptimizeDatas(username=username, password=password, host=host, port=port)
663
663
  # s.db_name = db_name
664
664
  # s.rename_column()
@@ -715,9 +715,9 @@ if __name__ == '__main__':
715
715
 
716
716
  # for db_name in [
717
717
  # '京东数据2',
718
- # '天猫数据2',
718
+ # '推广数据2',
719
719
  # '市场数据2',
720
- # '生意参谋数据2',
720
+ # '生意参谋2',
721
721
  # '生意经2',
722
722
  # '属性设置2',
723
723
  # ]:
@@ -43,14 +43,15 @@ class MysqlUpload:
43
43
  db_name: 数据库名称
44
44
  table_name: 集合/表名称
45
45
  drop_duplicates:仅限于聚合数据使用,其他情况不要设置
46
+ filename: 传这个参数是方便定位产生错误的文件
46
47
  """
47
48
  self.filename = filename
48
49
  if isinstance(df, pd.DataFrame):
49
50
  if len(df) == 0:
50
- print(f'{db_name}: {table_name} 传入的 df 数据长度为0')
51
+ print(f'{db_name}: {table_name} 传入的 df 数据长度为0, {self.filename}')
51
52
  return
52
53
  else:
53
- print(f'{db_name}: {table_name} 传入的 df 不是有效的 dataframe 结构')
54
+ print(f'{db_name}: {table_name} 传入的 df 不是有效的 dataframe 结构, {self.filename}')
54
55
  return
55
56
  cv = converter.DataFrameConverter()
56
57
  df = cv.convert_df_cols(df=df) # 清理 dataframe 非法值
@@ -144,16 +145,19 @@ class MysqlUpload:
144
145
  # print(condition)
145
146
 
146
147
  sql = f"SELECT {cols} FROM `{table_name}` WHERE {condition}"
148
+ # sql = f"SELECT {cols} FROM `{table_name}` WHERE `创建时间` = '2014-09-19 14:32:33'"
147
149
  cursor.execute(sql)
148
150
  result = cursor.fetchall() # 获取查询结果, 有结果返回 list 表示数据已存在(不重复插入),没有则返回空 tuple
149
151
  if not result: # 数据不存在则插入
150
152
  sql = f"INSERT INTO `{table_name}` ({cols}) VALUES ({values});"
151
153
  cursor.execute(sql)
152
- else:
153
- print(f'重复数据不插入: {condition}')
154
+ # else:
155
+ # print(f'重复数据不插入: {condition[:50]}...')
154
156
  except Exception as e:
155
- print(f'{self.filename}:')
156
- print(f'mysql -> df_to_mysql 报错: {e}')
157
+ # print(data)
158
+ # print(values)
159
+ print(f'mysql -> df_to_mysql 报错: {e}, {self.filename}')
160
+ # breakpoint()
157
161
  connection.commit() # 提交事务
158
162
 
159
163
  def convert_dtypes(self, df, db_name, table_name):
@@ -201,32 +205,35 @@ class MysqlUpload:
201
205
  return longest_value
202
206
 
203
207
  # 最优先处理 ID 类型, 在 mysql 里面, 有些列数字过长不能存储为 int 类型
204
- if 'id' in col or 'ID' in col or 'Id' in col or '摘要' in col or '商家编码' in col or '单号' in col or '款号' in col:
205
- return 'mediumtext'
208
+ # if 'id' in col or 'ID' in col or 'Id' in col or '摘要' in col or '商家编码' in col or '单号' in col or '款号' in col:
209
+ # return 'mediumtext'
206
210
  if '商品编码' in col: # 京东sku/spu商品信息
207
211
  return 'mediumtext'
208
212
  if '文件大小' in col: # bw 程序
209
213
  return 'mediumtext'
210
- elif '日期' in col or '时间' in col:
211
- try:
212
- k = pd.to_datetime(df[col].tolist()[0]) # 检查是否可以转为日期
213
- return 'DATE'
214
- except:
215
- return 'mediumtext'
216
- elif dtype == 'datetime64[ns]': # 日期可能显示为数字, 因为放在判断 int 的前面
217
- return 'DATE'
214
+ # elif '日期' in col or '时间' in col:
215
+ # try:
216
+ # k = pd.to_datetime(df[col].tolist()[0]) # 检查是否可以转为日期
217
+ # return 'DATE'
218
+ # except:
219
+ # return 'mediumtext'
220
+ elif dtype == 'datetime64[ns]':
221
+ return 'DATETIME' # 使用 DATE 后续排重可能会引发不能排重
218
222
  elif dtype == 'int32':
219
- if len(str(max(df[col].tolist()))) >= 10: # 数值长度超限转为 mediumtext
223
+ max_num = str(max(df[col].tolist()))
224
+ if len(max_num) >= 10: # 数值长度超限转为 mediumtext
220
225
  return 'mediumtext'
221
226
  return 'INT'
222
227
  elif dtype == 'int64':
223
- if len(str(max(df[col].tolist()))) >= 10:
228
+ max_num = str(max(df[col].tolist()))
229
+ if len(max_num) >= 10:
224
230
  return 'mediumtext'
225
231
  return 'INT'
226
232
  elif dtype == 'float64':
227
233
  res = find_longest_decimal_value(df[col].tolist()) # 取小数位数最长的值
228
234
  int_step = len(str(res).split('.')[0]) # 整数位数长度
229
235
  f_step = len(str(res).split('.')[1]) # 小数位数长度
236
+
230
237
  if int_step >= 12:
231
238
  return 'mediumtext' # mysql 中不要使用 float 和 double 类型,会影响计算结果
232
239
  elif int_step >= 8 and f_step >= 0:
@@ -236,14 +243,18 @@ class MysqlUpload:
236
243
  elif int_step >= 4 and f_step >= 0:
237
244
  return 'decimal(10, 2)'
238
245
  elif int_step >= 2 and f_step >= 6:
239
- return 'decimal(12, 4)'
240
- elif int_step >= 2 and f_step >= 4:
246
+ return 'decimal(12, 6)'
247
+ elif int_step >= 2 and f_step > 4:
248
+ return 'decimal(10, 6)'
249
+ elif int_step >= 2 and f_step > 2:
241
250
  return 'decimal(10, 4)'
242
251
  elif int_step >= 2 and f_step >= 0:
243
252
  return 'decimal(10, 2)'
244
253
  elif int_step >= 1 and f_step >= 6:
245
254
  return 'decimal(10, 6)'
246
- elif int_step >= 1 and f_step >= 4:
255
+ elif int_step >= 1 and f_step > 4:
256
+ return 'decimal(10, 6)'
257
+ elif int_step >= 1 and f_step > 2:
247
258
  return 'decimal(10, 4)'
248
259
  else:
249
260
  return 'decimal(10, 2)'
@@ -624,7 +635,7 @@ class OptimizeDatas:
624
635
  def rename_column(self):
625
636
  """ 批量修改数据库的列名 """
626
637
  """
627
- # for db_name in ['京东数据2', '天猫数据2', '市场数据2', '生意参谋数据2', '生意经2', '属性设置2',]:
638
+ # for db_name in ['京东数据2', '推广数据2', '市场数据2', '生意参谋2', '生意经2', '属性设置2',]:
628
639
  # s = OptimizeDatas(username=username, password=password, host=host, port=port)
629
640
  # s.db_name = db_name
630
641
  # s.rename_column()
@@ -697,7 +708,7 @@ def download_datas(table_name, save_path, start_date):
697
708
  def one_file_to_mysql(file, db_name, table_name, target_service, database):
698
709
  username, password, host, port = get_myconf.select_config_values(target_service=target_service, database=database)
699
710
  filename = os.path.basename(file)
700
- df = pd.read_csv(file, encoding='utf-8_sig', header=0, na_filter=False)
711
+ df = pd.read_csv(file, encoding='utf-8_sig', header=0, na_filter=False, float_precision='high')
701
712
  m = MysqlUpload(username=username, password=password, host=host, port=port)
702
713
  m.df_to_mysql(df=df, db_name=db_name, table_name=table_name, filename=filename)
703
714
 
@@ -706,11 +717,11 @@ if __name__ == '__main__':
706
717
  # username, password, host, port = get_myconf.select_config_values(target_service='home_lx', database='mysql')
707
718
  # print(username, password, host, port)
708
719
 
709
- file = '/Users/xigua/数据中心/原始文件2/生意经/宝贝指标/2024-08/baobeitrans-2024-08-22.csv'
720
+ file = '/Users/xigua/数据中心/原始文件2/推广报表/创意报表/创意报表_万里马官方旗舰店_2024-07-05_2024-07-19.csv'
710
721
  one_file_to_mysql(
711
722
  file=file,
712
- db_name='生意经2',
713
- table_name='宝贝指标',
723
+ db_name='推广数据2',
724
+ table_name='创意报表',
714
725
  target_service='home_lx',
715
726
  database='mysql'
716
727
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mdbq
3
- Version: 1.1.2
3
+ Version: 1.1.3
4
4
  Home-page: https://pypi.org/project/mdbsql
5
5
  Author: xigua,
6
6
  Author-email: 2587125111@qq.com
@@ -3,7 +3,7 @@
3
3
  from setuptools import setup, find_packages
4
4
 
5
5
  setup(name='mdbq',
6
- version='1.1.2',
6
+ version='1.1.3',
7
7
  author='xigua, ',
8
8
  author_email="2587125111@qq.com",
9
9
  url='https://pypi.org/project/mdbsql',
@@ -1,112 +0,0 @@
1
- # -*- coding:utf-8 -*-
2
- import pandas as pd
3
- import numpy as np
4
- import re
5
-
6
-
7
- class DataFrameConverter(object):
8
- def __init__(self, df=pd.DataFrame({})):
9
- self.df = df
10
-
11
- def convert_df_cols(self, df=pd.DataFrame({})):
12
- """
13
- 清理 dataframe 非法值
14
- 对数据类型进行转换(尝试将 object 类型转为 int 或 float)
15
- """
16
- if len(df) == 0:
17
- df = self.df
18
- if len(df) == 0:
19
- return
20
- # dtypes = df.dtypes.apply(str).to_dict() # 将 dataframe 数据类型转为字典形式
21
- df.replace([np.inf, -np.inf], 0, inplace=True) # 清理一些非法值
22
- df.replace(to_replace=['\\N', '-', '--', '', 'nan'], value=0, regex=False, inplace=True) # 替换掉特殊字符
23
- df.replace(to_replace=[','], value='', regex=True, inplace=True)
24
- df.replace(to_replace=['="'], value='', regex=True, inplace=True) # ="和"不可以放在一起清洗, 因为有: id=86785565
25
- df.replace(to_replace=['"'], value='', regex=True, inplace=True)
26
- cols = df.columns.tolist()
27
-
28
- for col in cols:
29
- # df[col] = df[col].apply(lambda x: re.sub('[="]', '', str(x)) if '="' in str(x) else x)
30
- # 百分比在某些数据库中不兼容, 转换百分比为小数
31
- df[col] = df[col].apply(lambda x: float(float((str(x).rstrip("%"))) / 100) if str(x).endswith('%') and '~' not in str(x) else x)
32
- # 尝试转换合适的数据类型
33
- if df[col].dtype == 'object':
34
- try:
35
- # df[col] = df[col].astype(int) # 尝试转换 int
36
- df[col] = df[col].apply(lambda x: int(x) if '_' not in str(x) else x)
37
- except:
38
- # df[col] = df[col].astype('float64', errors='ignore') # 尝试转换 float, 报错则忽略
39
- try:
40
- df[col] = df[col].apply(lambda x: float(x) if '_' not in str(x) else x)
41
- except:
42
- pass
43
- if df[col].dtype == 'float': # 对于小数类型, 保留 6 位小数
44
- df[col] = df[col].apply(lambda x: round(float(x), 6) if x != 0 else x)
45
- # 清理列名, 在 mysql 里面列名不能含有某些特殊字符
46
- if '日期' in col or '时间' in col:
47
- try:
48
- df[col] = df[col].apply(lambda x: pd.to_datetime(x))
49
- except:
50
- pass
51
- new_col = col.lower()
52
- df.rename(columns={col: new_col}, inplace=True)
53
- df.fillna(0, inplace=True)
54
- return df
55
-
56
- def convert_df_cols_bak(self, df=pd.DataFrame({})):
57
- """
58
- 清理 dataframe 列名的不合规字符(mysql)
59
- 对数据类型进行转换(尝试将 object 类型转为 int 或 float)
60
- """
61
- if len(df) == 0:
62
- df = self.df
63
- if len(df) == 0:
64
- return
65
- # dtypes = df.dtypes.apply(str).to_dict() # 将 dataframe 数据类型转为字典形式
66
- df.replace([np.inf, -np.inf], 0, inplace=True) # 清理一些非法值
67
- df.replace(to_replace=['\\N', '-', '--', '', 'nan'], value=0, regex=False, inplace=True) # 替换掉特殊字符
68
- df.replace(to_replace=[','], value='', regex=True, inplace=True)
69
- df.replace(to_replace=['="'], value='', regex=True, inplace=True) # ="和"不可以放在一起清洗, 因为有: id=86785565
70
- df.replace(to_replace=['"'], value='', regex=True, inplace=True)
71
- cols = df.columns.tolist()
72
-
73
- for col in cols:
74
- # df[col] = df[col].apply(lambda x: re.sub('[="]', '', str(x)) if '="' in str(x) else x)
75
- # 百分比在某些数据库中不兼容, 转换百分比为小数
76
- df[col] = df[col].apply(lambda x: float(float((str(x).rstrip("%"))) / 100) if str(x).endswith('%') and '~' not in str(x) else x)
77
- # 尝试转换合适的数据类型
78
- if df[col].dtype == 'object':
79
- try:
80
- # df[col] = df[col].astype(int) # 尝试转换 int
81
- df[col] = df[col].apply(lambda x: int(x) if '_' not in str(x) else x)
82
- except:
83
- # df[col] = df[col].astype('float64', errors='ignore') # 尝试转换 float, 报错则忽略
84
- try:
85
- df[col] = df[col].apply(lambda x: float(x) if '_' not in str(x) else x)
86
- except:
87
- pass
88
- if df[col].dtype == 'float': # 对于小数类型, 保留 6 位小数
89
- df[col] = df[col].apply(lambda x: round(float(x), 6) if x != 0 else x)
90
- # 清理列名, 在 mysql 里面列名不能含有某些特殊字符
91
- if '日期' in col or '时间' in col:
92
- try:
93
- df[col] = df[col].apply(lambda x: pd.to_datetime(x))
94
- except:
95
- pass
96
- new_col = col.lower()
97
- new_col = re.sub(r'[\',,()()/=<>+\-*^"’\[\]~#|&% .;]', '_', new_col)
98
- new_col = re.sub(r'_+$', '', new_col)
99
- df.rename(columns={col: new_col}, inplace=True)
100
- df.fillna(0, inplace=True)
101
- return df
102
-
103
-
104
- if __name__ == '__main__':
105
- # df = pd.DataFrame(np.random.randn(5, 3), columns=['a', 'b', 'c'])
106
- # converter = DataFrameConverter()
107
- # df = converter.convert_df_cols(df)
108
- # print(df['a'].dtype)
109
- # print(df)
110
- pattern = 'dfa_dfawr__'
111
- pattern = re.sub(r'_+$', '', pattern)
112
- print(pattern)
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
File without changes
File without changes
File without changes
File without changes
File without changes