mdbq 1.2.2__tar.gz → 1.2.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.
Files changed (46) hide show
  1. {mdbq-1.2.2 → mdbq-1.2.4}/PKG-INFO +1 -1
  2. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/aggregation/aggregation.py +24 -2
  3. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/aggregation/mysql_types.py +8 -2
  4. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/dataframe/converter.py +5 -2
  5. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/mysql/mysql.py +49 -12
  6. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq.egg-info/PKG-INFO +1 -1
  7. {mdbq-1.2.2 → mdbq-1.2.4}/setup.py +1 -1
  8. {mdbq-1.2.2 → mdbq-1.2.4}/README.txt +0 -0
  9. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/__init__.py +0 -0
  10. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/__version__.py +0 -0
  11. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/aggregation/__init__.py +0 -0
  12. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/aggregation/df_types.py +0 -0
  13. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/aggregation/optimize_data.py +0 -0
  14. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/aggregation/query_data.py +0 -0
  15. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/bdup/__init__.py +0 -0
  16. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/bdup/bdup.py +0 -0
  17. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/clean/__init__.py +0 -0
  18. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/clean/data_clean.py +0 -0
  19. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/company/__init__.py +0 -0
  20. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/company/copysh.py +0 -0
  21. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/config/__init__.py +0 -0
  22. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/config/get_myconf.py +0 -0
  23. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/config/products.py +0 -0
  24. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/config/set_support.py +0 -0
  25. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/config/update_conf.py +0 -0
  26. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/dataframe/__init__.py +0 -0
  27. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/log/__init__.py +0 -0
  28. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/log/mylogger.py +0 -0
  29. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/mongo/__init__.py +0 -0
  30. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/mongo/mongo.py +0 -0
  31. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/mysql/__init__.py +0 -0
  32. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/mysql/data_types_/345/215/263/345/260/206/345/210/240/351/231/244.py" +0 -0
  33. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/mysql/s_query.py +0 -0
  34. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/mysql/year_month_day.py +0 -0
  35. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/other/__init__.py +0 -0
  36. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/other/porxy.py +0 -0
  37. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/other/pov_city.py +0 -0
  38. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/other/ua_sj.py +0 -0
  39. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/pbix/__init__.py +0 -0
  40. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/pbix/pbix_refresh.py +0 -0
  41. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/pbix/refresh_all.py +0 -0
  42. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq/spider/__init__.py +0 -0
  43. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq.egg-info/SOURCES.txt +0 -0
  44. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq.egg-info/dependency_links.txt +0 -0
  45. {mdbq-1.2.2 → mdbq-1.2.4}/mdbq.egg-info/top_level.txt +0 -0
  46. {mdbq-1.2.2 → mdbq-1.2.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mdbq
3
- Version: 1.2.2
3
+ Version: 1.2.4
4
4
  Home-page: https://pypi.org/project/mdbsql
5
5
  Author: xigua,
6
6
  Author-email: 2587125111@qq.com
@@ -438,6 +438,7 @@ class DatabaseUpdate:
438
438
  new_name = f'未分类_{date1}_全部渠道_商品明细.csv'
439
439
  df.rename(columns={'商品ID': '商品id'}, inplace=True)
440
440
  df.insert(loc=0, column='日期', value=date1)
441
+ df['最近上架时间'].loc[0] = df['最近上架时间'].loc[1] # 填充这一列, 避免上传 mysql 日期类型报错
441
442
  if 'sku' in new_name:
442
443
  db_name = '京东数据2'
443
444
  collection_name = 'sku_商品明细'
@@ -929,7 +930,7 @@ def one_file_to_mysql(file, db_name, table_name, target_service, database):
929
930
  filename = os.path.basename(file)
930
931
  df = pd.read_csv(file, encoding='utf-8_sig', header=0, na_filter=False, float_precision='high')
931
932
  m = mysql.MysqlUpload(username=username, password=password, host=host, port=port)
932
- m.df_to_mysql(df=df, db_name=db_name, table_name=table_name, filename=filename)
933
+ m.df_to_mysql(df=df, db_name=db_name, table_name=table_name, filename=filename, df_sql=True)
933
934
 
934
935
 
935
936
  def file_dir(one_file=True):
@@ -974,6 +975,7 @@ def file_dir(one_file=True):
974
975
  path=os.path.join(path, sub_path),
975
976
  db_name = db_name,
976
977
  collection_name = table_name,
978
+ dbs={'mysql': True, 'mongodb': True},
977
979
  )
978
980
  data.update({'入库进度': 1}) # 更新进度为已上传
979
981
  # 将进度信息写回文件
@@ -981,7 +983,27 @@ def file_dir(one_file=True):
981
983
  df.to_csv(os.path.join(support_file, filename), encoding='utf-8_sig', index=False, header=True)
982
984
 
983
985
 
986
+ def test():
987
+ path = '/Users/xigua/数据中心/原始文件2/京东报表/JD商品明细spu'
988
+ for root, dirs, files in os.walk(path, topdown=False):
989
+ for name in files:
990
+ if name.endswith('.csv') and 'baidu' not in name and '~' not in name:
991
+ df = pd.read_csv(os.path.join(root, name), encoding='utf-8_sig', header=0, na_filter=False)
992
+ df['最近上架时间'].loc[0] = df['最近上架时间'].loc[1]
993
+ # print(df[['日期', '最近上架时间']])
994
+ df.to_csv(os.path.join(root, name), encoding='utf-8_sig', index=False, header=True)
995
+ # break
996
+ # break
997
+
998
+
984
999
  if __name__ == '__main__':
985
1000
  # username, password, host, port = get_myconf.select_config_values(target_service='nas', database='mysql')
986
1001
  # print(username, password, host, port)
987
- file_dir(one_file=True)
1002
+ file_dir(one_file=False)
1003
+ # one_file_to_mysql(
1004
+ # file='/Users/xigua/数据中心/原始文件2/京东报表/商品信息导出/spu/京东商品信息_批量SPU导出-批量任务_2024-08-10.csv',
1005
+ # db_name='京东数据2',
1006
+ # table_name='京东spu商品信息',
1007
+ # target_service='home_lx',
1008
+ # database='mysql'
1009
+ # )
@@ -123,6 +123,7 @@ class DataTypes:
123
123
  sort_keys=True, # 默认为False。如果为True,则字典的输出将按键排序。
124
124
  indent=4,
125
125
  )
126
+ print(f'已更新 json 文件: {self.json_file}')
126
127
  time.sleep(1)
127
128
 
128
129
  def load_dtypes(self, db_name, table_name, cl='mysql', ):
@@ -205,6 +206,7 @@ def mysql_all_dtypes(db_name=None, table_name=None, path=None):
205
206
  time.sleep(0.5)
206
207
 
207
208
  d = DataTypes()
209
+ d.json_file = os.path.join(path, 'mysql_types.json') # # json 保存位置
208
210
  for result in results:
209
211
  for db_n, table_n in result.items():
210
212
  # print(db_n, table_n, db_name, table_name)
@@ -229,12 +231,16 @@ def mysql_all_dtypes(db_name=None, table_name=None, path=None):
229
231
  cl='mysql',
230
232
  db_name=db_n,
231
233
  table_name=table_n,
232
- is_file_dtype=True
234
+ is_file_dtype=True # True表示旧文件有限
233
235
  )
234
236
  else:
235
237
  print(f'数据库回传数据(name_type)为空')
236
238
  # print(d.datas)
237
239
  d.as_json_file()
238
240
 
241
+
239
242
  if __name__ == '__main__':
240
- mysql_all_dtypes() # 更新 mysql 中所有数据库的 dtypes 信息到本地 json
243
+ # 更新 mysql 中所有数据库的 dtypes 信息到本地 json
244
+ mysql_all_dtypes(
245
+ path='/Users/xigua/Downloads',
246
+ )
@@ -43,11 +43,14 @@ class DataFrameConverter(object):
43
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
44
  # 尝试转换合适的数据类型
45
45
  if df[col].dtype == 'object':
46
+ # "_"符号会被错误识别
46
47
  try:
47
- df[col] = df[col].apply(lambda x: int(x) if '_' not in str(x) else x)
48
+ df[col] = df[col].apply(lambda x: int(x) if '_' not in str(x) and '.' not in str(x) else x) # 不含小数点尝试转整数
48
49
  except:
50
+ pass
51
+ if df[col].dtype == 'object':
49
52
  try:
50
- df[col] = df[col].apply(lambda x: float(x) if '_' not in str(x) else x)
53
+ df[col] = df[col].apply(lambda x: float(x) if '.' in str(x) and '_' not in str(x) else x)
51
54
  except:
52
55
  pass
53
56
  if df[col].dtype == 'float' or df[col].dtype == 'float64': # 对于小数类型, 保留 6 位小数
@@ -9,7 +9,9 @@ import warnings
9
9
  import pymysql
10
10
  import numpy as np
11
11
  import pandas as pd
12
+ import sqlalchemy.types
12
13
  from more_itertools.more import iequals
14
+ from pandas.core.dtypes.common import INT64_DTYPE
13
15
  from sqlalchemy import create_engine
14
16
  import os
15
17
  import calendar
@@ -20,18 +22,20 @@ from mdbq.aggregation import mysql_types
20
22
 
21
23
  warnings.filterwarnings('ignore')
22
24
  """
23
- 建表规范:
24
- 1. 先建 json 表,再批量上传数据;(非常重要)
25
- 在初创数据表时, 如果有不同类报表,新版和旧版都要取一个文件,先创建数据表,再导其他数据;
26
- 例如有的报表转化率是0%,数据类型会被识别为2位小数: decimal(10, 2),正常值应类似 0.43%,应保留4个小数, 创建类型为 decimal(10, 4)
27
- 为了避免以上可能数据类型错误的情况,初创时要先检查一遍数据类型,确认没问题再导其他数据!
28
- 即导一个表,然后删除数据库,但保留 mysql_types.json,并检查表的数据类型(有问题就手动改 json 文件),之后会按 json 的 types 上传数据;
25
+ 建表流程:
26
+ 尽可能手动建表,再上传数据
27
+ 1. 每个表手动上传一个文件建表
28
+ 2. 全部建表完成,建议所有表的数据类型,有问题的在数据库修改
29
+ 3. 清空所有数据表,仅保留列信息
30
+ 4. 下载所有数据表的 dtypes 信息到 json 文件
31
+ 5. 之后可以正常上传数据
29
32
 
30
- 2. 数据库和数据表名如果有字母,必须使用小写,大写在建库后会自动变小写,再次上传数据会找不到数据库(macos和linux都有这种情况)
31
- 3. 无论是数据库/表/列名还是值,尽量避免特殊字符或者表情符号,数据库/表/列名尽量都使用 `列名` 转义,避免错误
32
- 4. 小数必须使用 decimal, 禁止 float 和 double, 因为计算精度差异,后续需要聚合数据时会引发很多问题
33
- 5. 日期类型暂时全部用 DATETIME,使用 DATE 在后续可能会重复插入不能排重,因为 df 进来的数据, 日期是带时间的,而数据库中日期不含时间
34
- 6. 目前小数自动适配类型转换,对于文本或者大数全部用 mediumtext, 因为部分表涉及爬虫数据,进来的字符长度未知,暂时统一 mediumtext 避免入库失败
33
+ 建表规范:
34
+ 1. 数据库和数据表名如果有字母,必须使用小写,大写在建库后会自动变小写,再次上传数据会找不到数据库(macos和linux都有这种情况)
35
+ 2. 无论是数据库/表/列名还是值,尽量避免特殊字符或者表情符号,数据库/表/列名尽量都使用 `列名` 转义,避免错误
36
+ 3. 小数必须使用 decimal, 禁止 float double, 因为计算精度差异,后续需要聚合数据时会引发很多问题
37
+ 4. 日期类型暂时全部用 DATETIME,使用 DATE 在后续可能会重复插入不能排重,因为 df 进来的数据, 日期是带时间的,而数据库中日期不含时间
38
+ 5. 目前小数自动适配类型转换,对于文本或者大数全部用 mediumtext, 因为部分表涉及爬虫数据,进来的字符长度未知,暂时统一 mediumtext 避免入库失败
35
39
 
36
40
 
37
41
 
@@ -56,7 +60,7 @@ class MysqlUpload:
56
60
  }
57
61
  self.filename = None
58
62
 
59
- def df_to_mysql(self, df, table_name, db_name='远程数据源', drop_dup=True, drop_duplicates=False, filename=None, count=None):
63
+ def df_to_mysql(self, df, table_name, db_name='远程数据源', df_sql=False, drop_dup=True, drop_duplicates=False, filename=None, count=None):
60
64
  """
61
65
  将 df 写入数据库
62
66
  db_name: 数据库名称
@@ -73,9 +77,23 @@ class MysqlUpload:
73
77
  else:
74
78
  print(f'{db_name}: {table_name} 传入的 df 不是有效的 dataframe 结构, {self.filename}')
75
79
  return
80
+
76
81
  cv = converter.DataFrameConverter()
77
82
  df = cv.convert_df_cols(df=df) # 清理 dataframe 非法值
78
83
 
84
+ # if df_sql:
85
+ # now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S ")
86
+ # print(f'{now}正在更新 mysql ({self.host}:{self.port}) {db_name}/{table_name}, {count},{self.filename}')
87
+ # engine = create_engine(f"mysql+pymysql://{self.username}:{self.password}@{self.host}:{self.port}/{db_name}") # 创建数据库引擎
88
+ # df.to_sql(
89
+ # name=table_name,
90
+ # con=engine,
91
+ # if_exists='append',
92
+ # index=False,
93
+ # chunksize=1000,
94
+ # dtype={'京东价': 'INT'},
95
+ # )
96
+ # return
79
97
  connection = pymysql.connect(**self.config) # 连接数据库
80
98
  with connection.cursor() as cursor:
81
99
  cursor.execute(f"SHOW DATABASES LIKE '{db_name}'") # 检查数据库是否存在
@@ -132,6 +150,22 @@ class MysqlUpload:
132
150
  print(f'{self.filename}: {e}')
133
151
  connection.commit() # 提交事务
134
152
 
153
+ if df_sql:
154
+ now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S ")
155
+ print(f'{now}正在更新 mysql ({self.host}:{self.port}) {db_name}/{table_name}, {count},{self.filename}')
156
+ engine = create_engine(
157
+ f"mysql+pymysql://{self.username}:{self.password}@{self.host}:{self.port}/{db_name}") # 创建数据库引擎
158
+ df.to_sql(
159
+ name=table_name,
160
+ con=engine,
161
+ if_exists='append',
162
+ index=False,
163
+ chunksize=1000
164
+ )
165
+ connection.close()
166
+ return
167
+
168
+ # print(cl, db_n, tb_n)
135
169
  # 返回这些结果的目的是等添加完列再写 json 文件才能读到 types 信息
136
170
  if cl and db_n and tb_n:
137
171
  mysql_types.mysql_all_dtypes(db_name=db_name, table_name=table_name) # 更新一个表的 dtypes
@@ -152,6 +186,7 @@ class MysqlUpload:
152
186
  # 5. 更新插入数据
153
187
  now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S ")
154
188
  print(f'{now}正在更新 mysql ({self.host}:{self.port}) {db_name}/{table_name}, {count},{self.filename}')
189
+
155
190
  datas = df.to_dict(orient='records')
156
191
  for data in datas:
157
192
  try:
@@ -183,6 +218,7 @@ class MysqlUpload:
183
218
  print(f'mysql -> df_to_mysql 报错: {e}, {self.filename}')
184
219
  # breakpoint()
185
220
  connection.commit() # 提交事务
221
+ connection.close()
186
222
 
187
223
  def convert_dtypes(self, df, db_name, table_name):
188
224
  """
@@ -208,6 +244,7 @@ class MysqlUpload:
208
244
  col_not_exist = cols
209
245
  # 对文件不存在的列信息进行数据类型转换(按指定规则)
210
246
  dtypes.update({col: self.convert_dtype_to_sql(df=df, col=col, dtype=df[col].dtype) for col in col_not_exist})
247
+ # print(dtypes)
211
248
  # 至此 df 中全部列类型已经转换完成
212
249
  # 返回结果, 示例: {'上市年份': 'mediumtext', '商品id': 'mediumtext', '平台': 'mediumtext'}
213
250
  return dtypes, cl, db_n, tb_n # 返回这些结果的目的是等添加完列再写 json 文件才能读到 types 信息
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mdbq
3
- Version: 1.2.2
3
+ Version: 1.2.4
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.2.2',
6
+ version='1.2.4',
7
7
  author='xigua, ',
8
8
  author_email="2587125111@qq.com",
9
9
  url='https://pypi.org/project/mdbsql',
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
File without changes
File without changes
File without changes