universal-function-zsd 1.0.0__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.
- universal_function_zsd-1.0.0/LICENSE +19 -0
- universal_function_zsd-1.0.0/MANIFEST.in +0 -0
- universal_function_zsd-1.0.0/PKG-INFO +14 -0
- universal_function_zsd-1.0.0/README.md +2 -0
- universal_function_zsd-1.0.0/pyproject.toml +15 -0
- universal_function_zsd-1.0.0/setup.cfg +4 -0
- universal_function_zsd-1.0.0/src/universal_function_zsd/__init__.py +0 -0
- universal_function_zsd-1.0.0/src/universal_function_zsd/universal_function.py +461 -0
- universal_function_zsd-1.0.0/src/universal_function_zsd.egg-info/PKG-INFO +14 -0
- universal_function_zsd-1.0.0/src/universal_function_zsd.egg-info/SOURCES.txt +10 -0
- universal_function_zsd-1.0.0/src/universal_function_zsd.egg-info/dependency_links.txt +1 -0
- universal_function_zsd-1.0.0/src/universal_function_zsd.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2018 The Python Packaging Authority
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: universal_function_zsd
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: 可用于大部分项目的通用型函数库
|
|
5
|
+
Author-email: Colin Zhang <zsd0830@163.com>
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
|
|
13
|
+
本函数包一般用于现有的项目,具备一定的通用性;
|
|
14
|
+
目前由张绍东维护,有任何问题可咨询zsd0830@163.com。
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "universal_function_zsd"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
authors = [
|
|
5
|
+
{ name = "Colin Zhang", email = "zsd0830@163.com" },
|
|
6
|
+
]
|
|
7
|
+
dependencies = []
|
|
8
|
+
description = "可用于大部分项目的通用型函数库"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Operating System :: OS Independent",
|
|
15
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# @Time : 2024/11/13 10:00
|
|
3
|
+
# @Author : Zhang Shaodong
|
|
4
|
+
# @Email : zsd0830@163.com
|
|
5
|
+
# @File : universal_function.py
|
|
6
|
+
# @Info : 该脚本中包含通用的函数模块
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import time
|
|
10
|
+
import json
|
|
11
|
+
import pandas as pd
|
|
12
|
+
import random
|
|
13
|
+
import pymysql
|
|
14
|
+
import datetime
|
|
15
|
+
import bs4
|
|
16
|
+
import re
|
|
17
|
+
import sys
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# 如果数据库改了,就要修改这里
|
|
21
|
+
ip_database = {"localhost": "wom_db_local", "BA_USING": "BA_USING", "BI_READ": "bi"} # 需修改本地数据库名
|
|
22
|
+
dic_connet = {"localhost": {'host': 'localhost', 'port': 3306, 'user': 'root', 'password': 'zwp650811', 'database': 'wom_db_local'},
|
|
23
|
+
"BA_USING": {'host': '10.26.241.164', 'port': 3306, 'user': 'BA_USING', 'password': 'BA_USING@2022', 'database': ip_database["BA_USING"]},
|
|
24
|
+
"BI_READ": {'host': '10.26.241.164', 'port': 3306, 'user': 'BI_READ', 'password': 'Bireader@1027', 'database': ip_database["BI_READ"]}}
|
|
25
|
+
|
|
26
|
+
# 通用功能
|
|
27
|
+
#########################################################################
|
|
28
|
+
# 功能:判断sth是否为NaN、None或者空字符串,NaN、None或者空字符串返回True,其他情况返回False
|
|
29
|
+
def is_nano(sth):
|
|
30
|
+
if not sth:
|
|
31
|
+
return True
|
|
32
|
+
if isinstance(sth, float):
|
|
33
|
+
if np.isnan(sth):
|
|
34
|
+
return True
|
|
35
|
+
return False
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# 文件读取
|
|
39
|
+
#########################################################################
|
|
40
|
+
|
|
41
|
+
# 功能:读取json文件变成字典格式
|
|
42
|
+
# 输入:json_file - json文件的路径 - str
|
|
43
|
+
# 输出:data_dict - json文件转化成的字典 - dict
|
|
44
|
+
def read_json(json_file: str):
|
|
45
|
+
with open(json_file, 'r', encoding='utf-8') as load_f:
|
|
46
|
+
data_dict = json.load(load_f)
|
|
47
|
+
return data_dict
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# 数据库相关
|
|
51
|
+
#########################################################################
|
|
52
|
+
|
|
53
|
+
# 功能:尝试多次连接数据库
|
|
54
|
+
def get_cursor_times(config, times):
|
|
55
|
+
cnt_conn = 0
|
|
56
|
+
while cnt_conn < times:
|
|
57
|
+
try:
|
|
58
|
+
conn = pymysql.connect(**config)
|
|
59
|
+
cursor = conn.cursor()
|
|
60
|
+
break
|
|
61
|
+
except:
|
|
62
|
+
print(f'数据库连接失败,现进行第{cnt_conn}次重新连接,总共{times}次重新连接的机会...')
|
|
63
|
+
sleep_some_seconds(20, 21, 1)
|
|
64
|
+
cnt_conn += 1
|
|
65
|
+
return cursor, conn
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# 将dataframe写进数据库
|
|
69
|
+
def df2mysql(db_config, db, insert_df, insert_tbl, cover_flag):
|
|
70
|
+
if len(insert_df) != 0:
|
|
71
|
+
insert_cursor, insert_conn = get_cursor_times(db_config[db], 10000)
|
|
72
|
+
# 将dataframe中的Nan用None代替
|
|
73
|
+
insert_df = insert_df.where(insert_df.notnull(), None)
|
|
74
|
+
len_cols = insert_df.columns.size
|
|
75
|
+
insert_sql = f"{'replace' if cover_flag else 'insert ignore'} into {insert_tbl} values ({', '.join(['%s']*len_cols)})"
|
|
76
|
+
insert_data = (tuple(row) for _, row in insert_df.iterrows())
|
|
77
|
+
try:
|
|
78
|
+
insert_cursor.executemany(insert_sql, insert_data)
|
|
79
|
+
insert_conn.commit()
|
|
80
|
+
print(f"数据插入{insert_tbl}成功(๑•̀ㅂ•́)و✧")
|
|
81
|
+
except Exception as e:
|
|
82
|
+
print(e, f"数据插入{insert_tbl}失败:", insert_data)
|
|
83
|
+
finally:
|
|
84
|
+
insert_cursor.close()
|
|
85
|
+
insert_conn.close()
|
|
86
|
+
else:
|
|
87
|
+
print(f'无数据需要插入{insert_tbl}ε=(´ο`*)))')
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# 功能:将dict格式的数据插入insert_db的insert_tbl中
|
|
91
|
+
# 输入样例
|
|
92
|
+
# insert_db = 'BA_USING'
|
|
93
|
+
# insert_tbl = 'autohome_policy_post'
|
|
94
|
+
# db_config = {"BA_USING": {'host': '10.26.241.164', 'port': 3306, 'user': 'BA_USING', 'password': 'BA_USING@2022',
|
|
95
|
+
# 'database': "BA_USING"}}
|
|
96
|
+
def dict2mysql(db_config, db, insert_dict, insert_tbl, cover_flag):
|
|
97
|
+
insert_cursor, insert_conn = gc.get_cursor_times(db_config[db], 10000)
|
|
98
|
+
keys = ", ".join(insert_dict.keys())
|
|
99
|
+
values = ", ".join(['%s'] * len(insert_dict.keys()))
|
|
100
|
+
if cover_flag:
|
|
101
|
+
insert_sql = '''
|
|
102
|
+
INSERT INTO {table}({keys}) VALUES ({values}) ON DUPLICATE KEY UPDATE
|
|
103
|
+
'''.format(table=insert_tbl, keys=keys, values=values)
|
|
104
|
+
update = ','.join([" {key} = values({key})".format(key=key) for key in insert_dict])
|
|
105
|
+
insert_sql += update
|
|
106
|
+
else:
|
|
107
|
+
insert_sql = """
|
|
108
|
+
INSERT ignore INTO {table}({keys}) VALUES ({values})
|
|
109
|
+
""".format(table=insert_tbl, keys=keys, values=values)
|
|
110
|
+
try:
|
|
111
|
+
insert_cursor.execute(insert_sql, tuple(insert_dict.values()))
|
|
112
|
+
insert_conn.commit()
|
|
113
|
+
print("数据库插入结果数据成功(๑•̀ㅂ•́)و✧")
|
|
114
|
+
except Exception as e:
|
|
115
|
+
print(e, "数据库插入数据失败:", insert_dict)
|
|
116
|
+
finally:
|
|
117
|
+
insert_cursor.close()
|
|
118
|
+
insert_conn.close()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# 功能:修正sql查询得到的数据,为其加入表头
|
|
122
|
+
def fix_sql_df(results, col_name_list):
|
|
123
|
+
col_name = []
|
|
124
|
+
for head in col_name_list:
|
|
125
|
+
col_name.append(head[0])
|
|
126
|
+
df = pd.DataFrame(list(results), columns=col_name)
|
|
127
|
+
return df
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# 功能:查询某段sql,并返回一个df(带表头)
|
|
131
|
+
def read_sql2df(db, db_config, sql):
|
|
132
|
+
# 连接导入数据库
|
|
133
|
+
cursor, conn = get_cursor_times(db_config[db], 10000)
|
|
134
|
+
cursor.execute(sql)
|
|
135
|
+
results = cursor.fetchall() # 用于返回多条数据
|
|
136
|
+
col_name_list = cursor.description
|
|
137
|
+
cursor.close()
|
|
138
|
+
conn.close()
|
|
139
|
+
df = fix_sql_df(results, col_name_list)
|
|
140
|
+
return df
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# 功能:执行一段sql,但不返回数据
|
|
144
|
+
def process_sql(db, db_config, sql):
|
|
145
|
+
cursor, conn = gc.get_cursor_times(db_config[db], 10000)
|
|
146
|
+
try:
|
|
147
|
+
cursor.execute(sql)
|
|
148
|
+
conn.commit()
|
|
149
|
+
except Exception as e:
|
|
150
|
+
conn.rollback()
|
|
151
|
+
print("执行失败:", e)
|
|
152
|
+
finally:
|
|
153
|
+
cursor.close()
|
|
154
|
+
conn.close()
|
|
155
|
+
|
|
156
|
+
# 时间处理的模块
|
|
157
|
+
#########################################################################
|
|
158
|
+
|
|
159
|
+
# 功能:获取当前时间,返回yyyymmddhhmmss格式的时间字符串
|
|
160
|
+
# 输入:-
|
|
161
|
+
# 输出:time_out - yyyymmddhhmmss格式的时间字符串 - str
|
|
162
|
+
def get_time_now():
|
|
163
|
+
time_out = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
|
|
164
|
+
return time_out
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# 功能:获取当前时间,返回 %Y-%m-%d %H:%M:%S 格式的时间字符串
|
|
168
|
+
# 输入:-
|
|
169
|
+
# 输出:datetime_out - %Y-%m-%d %H:%M:%S格式的时间字符串 - str
|
|
170
|
+
def get_datetime_now():
|
|
171
|
+
datetime_out = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
172
|
+
return datetime_out
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# 功能:比较两个"yyyy-mm-dd"格式时间字符串的大小
|
|
176
|
+
# 输入:time1 - 时间1 - str,如'2022-01-01'
|
|
177
|
+
# time2 - 时间2 - str,如'2022-01-01'
|
|
178
|
+
# identifier - 比较符,可选5种:大于(>)、大于等于(>=)、等于(=)、小于等于(<=)、小于(<) - str
|
|
179
|
+
# 输出:True/False - 比较结果 - bool
|
|
180
|
+
def compare_time_v1(time1: str, time2: str, identifier: str):
|
|
181
|
+
s_time = time.mktime(time.strptime(time1, '%Y-%m-%d'))
|
|
182
|
+
e_time = time.mktime(time.strptime(time2, '%Y-%m-%d'))
|
|
183
|
+
if identifier == '>':
|
|
184
|
+
if int(s_time) - int(e_time) > 0:
|
|
185
|
+
return True
|
|
186
|
+
else:
|
|
187
|
+
return False
|
|
188
|
+
if identifier == '<':
|
|
189
|
+
if int(s_time) - int(e_time) < 0:
|
|
190
|
+
return True
|
|
191
|
+
else:
|
|
192
|
+
return False
|
|
193
|
+
if identifier == '>=':
|
|
194
|
+
if int(s_time) - int(e_time) >= 0:
|
|
195
|
+
return True
|
|
196
|
+
else:
|
|
197
|
+
return False
|
|
198
|
+
if identifier == '<=':
|
|
199
|
+
if int(s_time) - int(e_time) <= 0:
|
|
200
|
+
return True
|
|
201
|
+
else:
|
|
202
|
+
return False
|
|
203
|
+
if identifier == '=':
|
|
204
|
+
if int(s_time) - int(e_time) == 0:
|
|
205
|
+
return True
|
|
206
|
+
else:
|
|
207
|
+
return False
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
# 功能:比较两个"yyyy-mm-dd hh:mm:ss"格式时间字符串的大小
|
|
211
|
+
# 输入:time1 - 时间1 - str,如'2022-01-01 00:00:00'
|
|
212
|
+
# time2 - 时间2 - str,如'2022-01-01 00:00:00'
|
|
213
|
+
# identifier - 比较符,可选5种:大于(>)、大于等于(>=)、等于(=)、小于等于(<=)、小于(<) - str
|
|
214
|
+
# 输出:True/False - 比较结果 - bool
|
|
215
|
+
def compare_time_v2(time1: str, time2: str, identifier: str):
|
|
216
|
+
s_time = time.mktime(time.strptime(time1, '%Y-%m-%d %H:%M:%S'))
|
|
217
|
+
e_time = time.mktime(time.strptime(time2, '%Y-%m-%d %H:%M:%S'))
|
|
218
|
+
if identifier == '>':
|
|
219
|
+
if int(s_time) - int(e_time) > 0:
|
|
220
|
+
return True
|
|
221
|
+
else:
|
|
222
|
+
return False
|
|
223
|
+
if identifier == '<':
|
|
224
|
+
if int(s_time) - int(e_time) < 0:
|
|
225
|
+
return True
|
|
226
|
+
else:
|
|
227
|
+
return False
|
|
228
|
+
if identifier == '>=':
|
|
229
|
+
if int(s_time) - int(e_time) >= 0:
|
|
230
|
+
return True
|
|
231
|
+
else:
|
|
232
|
+
return False
|
|
233
|
+
if identifier == '<=':
|
|
234
|
+
if int(s_time) - int(e_time) <= 0:
|
|
235
|
+
return True
|
|
236
|
+
else:
|
|
237
|
+
return False
|
|
238
|
+
if identifier == '=':
|
|
239
|
+
if int(s_time) - int(e_time) == 0:
|
|
240
|
+
return True
|
|
241
|
+
else:
|
|
242
|
+
return False
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
# 功能:将自epoch以来经过的秒数字符串转化为"yyyy-mm-dd hh:mm:ss"格式
|
|
246
|
+
# 输入:stamp_string - 自epoch以来经过的秒数字符串 - str,如'1545925769'
|
|
247
|
+
# 输出:date_time - "yyyy-mm-dd hh:mm:ss"格式的时间字符串 - str
|
|
248
|
+
def stamp2date(stamp_string: str):
|
|
249
|
+
time_array = time.localtime(int(stamp_string))
|
|
250
|
+
date_time = time.strftime("%Y-%m-%d %H:%M:%S", time_array)
|
|
251
|
+
return date_time
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
# 功能:随机sleep n - m 秒,k表示小数点后k位的时间
|
|
255
|
+
# 输入:m - 最短时间 - int
|
|
256
|
+
# n - 最长时间 - int
|
|
257
|
+
# k - 小数点后k位 - int
|
|
258
|
+
# 输出:True - 表示完成 - bool
|
|
259
|
+
def sleep_some_seconds(m: int, n: int, k: int):
|
|
260
|
+
time.sleep(round(random.uniform(m, n), k))
|
|
261
|
+
return True
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
# 功能:计算sec(秒数)与当前时间的时间间隔,并且输出指定格式的字符串形式
|
|
265
|
+
# 输入:sec - 最短时间 - int/str
|
|
266
|
+
# date_format - 指定的输出格式 - str
|
|
267
|
+
# 输出:time_gap - 指定格式的时间间隔 - str
|
|
268
|
+
def change2date(sec, date_format: str):
|
|
269
|
+
sec = int(sec)
|
|
270
|
+
time_gap = time.time() - sec
|
|
271
|
+
time_gap = time.strftime(date_format, time.localtime(time_gap))
|
|
272
|
+
return time_gap
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
# 功能:将n天前/n小时前/n周前转化为%Y-%m-%d %H:%M:%S的字符串格式
|
|
276
|
+
# 输入:before - 时间表达形式 - str
|
|
277
|
+
# 输出:datetime_str - 格式化的时间字符串 - str
|
|
278
|
+
def before2datetime(before: str):
|
|
279
|
+
before_str = re.findall(r"(\d{4}-\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2})", before)
|
|
280
|
+
if before_str != []:
|
|
281
|
+
datetime_str = before_str[0]
|
|
282
|
+
else:
|
|
283
|
+
if '前天' in before:
|
|
284
|
+
sec = 2 * 86400
|
|
285
|
+
datetime_str = change2date(sec, date_format='%Y-%m-%d %H:%M:%S')
|
|
286
|
+
elif '周前' in before:
|
|
287
|
+
a = re.findall('(.*?)天前', before)
|
|
288
|
+
sec = int(a[0]) * 7 * 86400
|
|
289
|
+
datetime_str = change2date(sec, date_format='%Y-%m-%d %H:%M:%S')
|
|
290
|
+
elif '天前' in before:
|
|
291
|
+
a = re.findall('(.*?)天前', before)
|
|
292
|
+
sec = int(a[0]) * 86400
|
|
293
|
+
datetime_str = change2date(sec, date_format='%Y-%m-%d %H:%M:%S')
|
|
294
|
+
elif '小时前' in before:
|
|
295
|
+
a = re.findall('(.*?)小时前', before)
|
|
296
|
+
sec = int(a[0]) * 3600
|
|
297
|
+
datetime_str = change2date(sec, date_format='%Y-%m-%d %H:%M:%S')
|
|
298
|
+
elif '分钟前' in before:
|
|
299
|
+
a = re.findall('(.*?)分钟前', before)
|
|
300
|
+
sec = int(a[0]) * 60
|
|
301
|
+
datetime_str = change2date(sec, date_format='%Y-%m-%d %H:%M:%S')
|
|
302
|
+
elif '秒钟前' in before:
|
|
303
|
+
a = re.findall('(.*?)秒钟前', before)
|
|
304
|
+
sec = int(a[0])
|
|
305
|
+
datetime_str = change2date(sec, date_format='%Y-%m-%d %H:%M:%S')
|
|
306
|
+
elif '刚刚' in before:
|
|
307
|
+
sec = 0
|
|
308
|
+
datetime_str = change2date(sec, date_format='%Y-%m-%d %H:%M:%S')
|
|
309
|
+
else:
|
|
310
|
+
print('意外的时间表达方式!!!!!!return当前时间')
|
|
311
|
+
sec = 0
|
|
312
|
+
datetime_str = change2date(sec, date_format='%Y-%m-%d %H:%M:%S')
|
|
313
|
+
return datetime_str
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
# 功能:将yyyymmdd-yyyymmdd格式的字符串拆分,并转化为前后两个时间的起始及结束datetime
|
|
317
|
+
# 输入:text - 两个时间的表达形式,yyyymmdd-yyyymmdd - str
|
|
318
|
+
# 输出:True/False - 若输入不符合格式要求,则直接返回False - bool
|
|
319
|
+
# start_dt - 起始的dateframe字符串
|
|
320
|
+
# end_dt - 结束的dateframe字符串
|
|
321
|
+
def split_yyyymmdd(text: str):
|
|
322
|
+
date_list = text.split('-')
|
|
323
|
+
start_text = date_list[0]
|
|
324
|
+
end_text = date_list[1]
|
|
325
|
+
if len(date_list) != 2 or len(start_text) != 8 or len(end_text) != 8 or int(start_text) > int(end_text):
|
|
326
|
+
return False, '', ''
|
|
327
|
+
else:
|
|
328
|
+
start_dt = start_text[:4] + '-' + start_text[4:6] + '-' + start_text[6:8] + ' 00:00:00'
|
|
329
|
+
end_dt = end_text[:4] + '-' + end_text[4:6] + '-' + end_text[6:8] + ' 23:59:59'
|
|
330
|
+
return True, start_dt, end_dt
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
# 功能:根据当前时间,反馈现在是周几
|
|
334
|
+
# 输入:-
|
|
335
|
+
# 输出:weekday - 周几 - str
|
|
336
|
+
def get_day_of_week():
|
|
337
|
+
day_of_week = datetime.datetime.now().weekday() + 1
|
|
338
|
+
if day_of_week == 1:
|
|
339
|
+
weekday = '周一'
|
|
340
|
+
elif day_of_week == 2:
|
|
341
|
+
weekday = '周二'
|
|
342
|
+
elif day_of_week == 3:
|
|
343
|
+
weekday = '周三'
|
|
344
|
+
elif day_of_week == 4:
|
|
345
|
+
weekday = '周四'
|
|
346
|
+
elif day_of_week == 5:
|
|
347
|
+
weekday = '周五'
|
|
348
|
+
elif day_of_week == 6:
|
|
349
|
+
weekday = '周六'
|
|
350
|
+
else:
|
|
351
|
+
weekday = '周日'
|
|
352
|
+
return weekday
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
# 功能:根据输入的date格式,得到n_day前的date格式日期
|
|
356
|
+
# 输入:date_start - 起始的日期 - datetime.date
|
|
357
|
+
# n_day - n天前 - int
|
|
358
|
+
# 输出:date_before - n_day天之前的date - datetime.date
|
|
359
|
+
def get_date_before(date_start, n_day):
|
|
360
|
+
days = datetime.timedelta(days=n_day)
|
|
361
|
+
date_before = date_start - days
|
|
362
|
+
return date_before
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
# excel处理模块
|
|
366
|
+
#########################################################################
|
|
367
|
+
|
|
368
|
+
# 功能:将一个df写入到excel的指定位置
|
|
369
|
+
def wirte_df2excel(goal_sheet, start_row, start_col, df_input, align_style, header_include=False):
|
|
370
|
+
col_idx = start_col
|
|
371
|
+
# 如果表头也要写入,就把表头放在第一行
|
|
372
|
+
if header_include:
|
|
373
|
+
df_input.T.reset_index().rename(columns={'index': '列名'}).T
|
|
374
|
+
for row in df_input.iteritems():
|
|
375
|
+
input_list = row[1].apply(str).to_list()
|
|
376
|
+
row_idx = start_row
|
|
377
|
+
for ele in input_list:
|
|
378
|
+
try:
|
|
379
|
+
goal_sheet.cell(row=row_idx, column=col_idx).value = ele
|
|
380
|
+
goal_sheet.cell(row=row_idx, column=col_idx).alignment = align_style
|
|
381
|
+
except:
|
|
382
|
+
print('无法写入:', ele)
|
|
383
|
+
row_idx += 1
|
|
384
|
+
col_idx += 1
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
# 功能:将一个series写入到excel的指定位置
|
|
388
|
+
def write_series2excel(goal_sheet, start_row, start_col, series_input, align_style, value_only=False, top_n=10000000):
|
|
389
|
+
cnt = 0
|
|
390
|
+
for idx, val in series_input.items():
|
|
391
|
+
if val is not None:
|
|
392
|
+
# 如果要把索引也记录上
|
|
393
|
+
if not value_only:
|
|
394
|
+
goal_sheet.cell(row=start_row, column=start_col).value = idx
|
|
395
|
+
goal_sheet.cell(row=start_row, column=start_col+1).value = val
|
|
396
|
+
goal_sheet.cell(row=start_row, column=start_col).alignment = align_style
|
|
397
|
+
goal_sheet.cell(row=start_row, column=start_col+1).alignment = align_style
|
|
398
|
+
else:
|
|
399
|
+
goal_sheet.cell(row=start_row, column=start_col).value = val
|
|
400
|
+
goal_sheet.cell(row=start_row, column=start_col).alignment = align_style
|
|
401
|
+
cnt += 1
|
|
402
|
+
if cnt >= top_n:
|
|
403
|
+
break
|
|
404
|
+
start_row += 1
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
# 功能:将一个数值写入到excel的指定位置
|
|
408
|
+
def write_val2excel(goal_sheet, row_pos, col_pos, val, align_style):
|
|
409
|
+
goal_sheet.cell(row=row_pos, column=col_pos).value = val
|
|
410
|
+
goal_sheet.cell(row=row_pos, column=col_pos).alignment = align_style
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
# 自动化处理模块
|
|
415
|
+
#########################################################################
|
|
416
|
+
|
|
417
|
+
# 功能:自动发送指定邮件给指定的人
|
|
418
|
+
# 输入:f_origin - 宏文件的地址 - str
|
|
419
|
+
# to_list - 发送的用户清单 - list
|
|
420
|
+
# cc_list - 抄送的用户清单 - list
|
|
421
|
+
# attached_list - 附件的地址list,支持最多两个附件 - list
|
|
422
|
+
# subject_text - 邮件标题 - str
|
|
423
|
+
# content_text - 正文内容 - str
|
|
424
|
+
# 输出:-
|
|
425
|
+
def send_mail(f_origin, to_list, cc_list, attached_list, subject_text, content_text):
|
|
426
|
+
if len(attached_list) > 2:
|
|
427
|
+
print('附件数过多,请缩减至2个及以下的附件。')
|
|
428
|
+
sys.quit()
|
|
429
|
+
to_string = '; '.join(to_list)
|
|
430
|
+
cc_string = '; '.join(cc_list)
|
|
431
|
+
# 更新xlsm的内容信息
|
|
432
|
+
print('开始对xlsm的内容信息进行更新...')
|
|
433
|
+
wb = load_workbook(f_origin, keep_vba=True)
|
|
434
|
+
ws_1 = wb.get_sheet_by_name('发送清单')
|
|
435
|
+
ws_1.cell(row=2, column=1).value = to_string
|
|
436
|
+
ws_1.cell(row=2, column=2).value = cc_string
|
|
437
|
+
n_idx = 3
|
|
438
|
+
for attached in attached_list:
|
|
439
|
+
ws_1.cell(row=2, column=n_idx).value = attached
|
|
440
|
+
n_idx += 1
|
|
441
|
+
ws_2 = wb.get_sheet_by_name('正文')
|
|
442
|
+
ws_2.cell(row=1, column=2).value = subject_text
|
|
443
|
+
ws_2.cell(row=2, column=2).value = content_text
|
|
444
|
+
f_goal = f_origin[:-5] + f'_tmp_{get_time_now()}.xlsm'
|
|
445
|
+
wb.save(f_goal)
|
|
446
|
+
time.sleep(3)
|
|
447
|
+
# 通过excel的宏进行发送
|
|
448
|
+
app = xw.App(visible=False, add_book=False)
|
|
449
|
+
app.screen_updating = False
|
|
450
|
+
# 宏文件
|
|
451
|
+
wb = app.books.open(f_goal)
|
|
452
|
+
# 执行宏文件
|
|
453
|
+
marco = wb.macro('Mygirl') # 这里需要特别注意,当你的宏名是唯一的时候,不需要写模块名,但如果模块名和宏名重复,需要补全
|
|
454
|
+
marco()
|
|
455
|
+
time.sleep(3) # 等待macro运行完毕,具体等待时长视宏运行的时间
|
|
456
|
+
# 保存关闭退出
|
|
457
|
+
wb.save()
|
|
458
|
+
wb.close()
|
|
459
|
+
app.quit()
|
|
460
|
+
print('邮件发送成功(๑•̀ㅂ•́)و✧')
|
|
461
|
+
os.remove(f_goal)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: universal_function_zsd
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: 可用于大部分项目的通用型函数库
|
|
5
|
+
Author-email: Colin Zhang <zsd0830@163.com>
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
|
|
13
|
+
本函数包一般用于现有的项目,具备一定的通用性;
|
|
14
|
+
目前由张绍东维护,有任何问题可咨询zsd0830@163.com。
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
src/universal_function_zsd/__init__.py
|
|
6
|
+
src/universal_function_zsd/universal_function.py
|
|
7
|
+
src/universal_function_zsd.egg-info/PKG-INFO
|
|
8
|
+
src/universal_function_zsd.egg-info/SOURCES.txt
|
|
9
|
+
src/universal_function_zsd.egg-info/dependency_links.txt
|
|
10
|
+
src/universal_function_zsd.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
universal_function_zsd
|