mdbq 1.1.2__tar.gz → 1.1.4__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.
- {mdbq-1.1.2 → mdbq-1.1.4}/PKG-INFO +1 -1
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/aggregation/aggregation.py +76 -30
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/aggregation/df_types.py +1 -1
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/aggregation/mysql_types.py +5 -4
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/aggregation/query_data.py +6 -6
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/clean/data_clean.py +6 -2
- mdbq-1.1.4/mdbq/dataframe/converter.py +81 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/mongo/mongo.py +3 -3
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/mysql/mysql.py +37 -26
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq.egg-info/PKG-INFO +1 -1
- {mdbq-1.1.2 → mdbq-1.1.4}/setup.py +1 -1
- mdbq-1.1.2/mdbq/dataframe/converter.py +0 -112
- {mdbq-1.1.2 → mdbq-1.1.4}/README.txt +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/__version__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/aggregation/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/aggregation/optimize_data.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/bdup/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/bdup/bdup.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/clean/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/company/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/company/copysh.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/config/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/config/get_myconf.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/config/products.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/config/set_support.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/config/update_conf.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/dataframe/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/log/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/log/mylogger.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/mongo/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/mysql/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/mysql/data_types_/345/215/263/345/260/206/345/210/240/351/231/244.py" +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/mysql/s_query.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/mysql/year_month_day.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/other/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/other/porxy.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/other/pov_city.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/other/ua_sj.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/pbix/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/pbix/pbix_refresh.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/pbix/refresh_all.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq/spider/__init__.py +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq.egg-info/SOURCES.txt +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq.egg-info/dependency_links.txt +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/mdbq.egg-info/top_level.txt +0 -0
- {mdbq-1.1.2 → mdbq-1.1.4}/setup.cfg +0 -0
@@ -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 = '
|
95
|
-
collection_name = f'
|
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 = '
|
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 = '
|
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 = '
|
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 = '
|
140
|
-
collection_name = '
|
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 = '
|
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 = '
|
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 = '
|
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 = '
|
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 = '
|
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 = '
|
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 = '
|
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 = '
|
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 = '
|
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 = '
|
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 = '
|
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 = '
|
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 = '
|
619
|
-
collection_name = f'
|
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=os.path.join(path, sub_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
|
-
|
929
|
-
|
930
|
-
|
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', '
|
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', '
|
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
|
-
# '
|
181
|
+
# '推广数据2',
|
182
182
|
# '市场数据2',
|
183
|
-
# '
|
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='
|
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='
|
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
|
-
|
1117
|
-
|
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', '
|
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
|
-
# '
|
718
|
+
# '推广数据2',
|
719
719
|
# '市场数据2',
|
720
|
-
# '
|
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
|
-
|
154
|
+
# else:
|
155
|
+
# print(f'重复数据不插入: {condition[:50]}...')
|
154
156
|
except Exception as e:
|
155
|
-
print(
|
156
|
-
print(
|
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
|
-
|
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
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
elif dtype == 'datetime64[ns]':
|
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
|
-
|
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
|
-
|
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,
|
240
|
-
elif int_step >= 2 and f_step
|
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
|
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', '
|
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
|
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='
|
713
|
-
table_name='
|
723
|
+
db_name='推广数据2',
|
724
|
+
table_name='创意报表',
|
714
725
|
target_service='home_lx',
|
715
726
|
database='mysql'
|
716
727
|
)
|
@@ -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
|
{mdbq-1.1.2 → mdbq-1.1.4}/mdbq/mysql/data_types_/345/215/263/345/260/206/345/210/240/351/231/244.py"
RENAMED
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
|