Functions-d 1.34__tar.gz → 1.36__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.
@@ -9,10 +9,6 @@ import urllib.request
9
9
  import WeComMsg
10
10
  import xlwings as xw
11
11
  import yagmail
12
- import smtplib
13
- from email.mime.multipart import MIMEMultipart
14
- from email.mime.text import MIMEText
15
- from email.mime.application import MIMEApplication
16
12
  import HiveClient
17
13
  from PIL import ImageGrab, Image
18
14
  from bs4 import BeautifulSoup
@@ -29,9 +25,12 @@ from tenacity import retry, stop_after_attempt, wait_fixed
29
25
  import requests
30
26
  import pandas as pd
31
27
  import os
32
- from io import BytesIO
33
- from requests.adapters import HTTPAdapter
34
- from urllib3.util.retry import Retry
28
+ import time
29
+ import smtplib
30
+ from email.mime.multipart import MIMEMultipart
31
+ from email.mime.text import MIMEText
32
+ from email.mime.application import MIMEApplication
33
+ from email.mime.image import MIMEImage
35
34
 
36
35
 
37
36
  class DataProcessingAndMessaging:
@@ -79,6 +78,15 @@ class DataProcessingAndMessaging:
79
78
  self.wechat_doc_access_token = None
80
79
  self._wechat_doc_logger = None # 企微文档独立日志器(延迟初始化)
81
80
 
81
+ # -------------------------- 邮件SMTP全局配置 --------------------------
82
+ self.SMTP_SENDER = "cc_yingxiao@xin.com"
83
+ self.SMTP_PWD = "cw46pfeznNQx"
84
+ self.SMTP_HOST = "mail.xin.com"
85
+ self.SMTP_PORT = 587
86
+ self.SMTP_TIMEOUT = 300 # 超时延长至5分钟
87
+ self.MAIL_RETRY_TIMES = 3 # 失败重试3次
88
+ self.MAIL_RETRY_INTERVAL = 5 # 重试间隔5秒
89
+
82
90
 
83
91
  # -------------------------- 企微文档日志:延迟初始化独立日志器 --------------------------
84
92
  def _init_wechat_doc_logger(self):
@@ -130,6 +138,8 @@ class DataProcessingAndMessaging:
130
138
  # -------------------------- 脚本路径和文件名初始化 --------------------------
131
139
  def Start_Get_filepath_and_filename(self):
132
140
  self.start_time = time.time()
141
+ # ========== 新增:运行开始时追加10行空行分隔 ==========
142
+ self.logger.info('\n' * 5)
133
143
  caller_frame = inspect.stack()[1]
134
144
  self.current_script_name = caller_frame.filename
135
145
  self.log_filename = os.path.splitext(self.current_script_name)[0] + ".log"
@@ -148,7 +158,7 @@ class DataProcessingAndMessaging:
148
158
  elapsed_time = round(end_time - self.start_time, 0)
149
159
  print(f"运行时间:{elapsed_time} 秒")
150
160
  self.logger.info(f"运行时间:{elapsed_time} 秒")
151
- self.logger.info('\n' * 10)
161
+ # self.logger.info('\n' * 10)
152
162
 
153
163
  # -------------------------- 企业微信消息发送 --------------------------
154
164
  # 仅展示修改后的 uxin_wx 方法,其余代码不变
@@ -815,16 +825,14 @@ class DataProcessingAndMessaging:
815
825
  self.screen(filename, sheet_name,
816
826
  f"{start_range}:%s" % (self.column_label(len(data.columns)) + str(len(data) + 3)), image_path)
817
827
 
818
- # -------------------------- 发送邮件(新版-优化增强版) --------------------------
828
+ # -------------------------- 发送邮件(新版-优化增强版+重试+防超时) --------------------------
819
829
  def send_email_new(self, recipient_emails, cc_emails=None, bcc_emails=None, subject="", html_body="",
820
830
  attachments=None):
821
831
  # 1. 内部工具:格式化邮箱(和旧版完全对齐,转列表+过滤无效值)
822
832
  def format_email(emails):
823
833
  if not emails:
824
834
  return []
825
- # 单个邮箱转列表,列表直接使用
826
835
  email_list = [emails] if isinstance(emails, str) else emails
827
- # 过滤:非空字符串 + 简单格式校验(含@和.)
828
836
  valid_emails = [
829
837
  e.strip() for e in email_list
830
838
  if isinstance(e, str) and e.strip() and '@' in e.strip() and '.' in e.strip()
@@ -853,17 +861,16 @@ class DataProcessingAndMessaging:
853
861
  }
854
862
  return mime_map.get(suffix, 'application/octet-stream')
855
863
 
856
- # 3. 参数标准化处理(修复None报错隐患)
864
+ # 3. 参数标准化处理
857
865
  subject = subject.strip()
858
866
  to_emails = format_email(recipient_emails)
859
867
  cc_emails = format_email(cc_emails)
860
868
  bcc_emails = format_email(bcc_emails)
861
869
  attachments = attachments or []
862
- # 附件标准化:单个字符串转列表
863
870
  if isinstance(attachments, str):
864
871
  attachments = [attachments.strip()]
865
872
 
866
- # 4. 核心参数校验(提前报错,避免无效连接)
873
+ # 4. 核心参数校验
867
874
  if not to_emails:
868
875
  err_msg = "❌ 邮件发送失败:无有效收件人邮箱"
869
876
  self.logger.error(err_msg)
@@ -875,7 +882,7 @@ class DataProcessingAndMessaging:
875
882
  print(err_msg)
876
883
  raise ValueError(err_msg)
877
884
 
878
- # 5. 控制台打印(和旧版完全对齐,实时展示发送进度)
885
+ # 5. 控制台打印
879
886
  print(f"📧 开始发送邮件 - 主题: {subject}")
880
887
  print(f"📥 收件人: {', '.join(to_emails)}")
881
888
  if cc_emails:
@@ -886,7 +893,7 @@ class DataProcessingAndMessaging:
886
893
  attach_names = [os.path.basename(att) for att in attachments]
887
894
  print(f"📎 附件: {', '.join(attach_names)}")
888
895
 
889
- # 6. 日志记录(和原新版逻辑对齐)
896
+ # 6. 日志记录
890
897
  self.logger.info(f"开始发送邮件 - 主题: {subject}")
891
898
  self.logger.info(f"收件人: {', '.join(to_emails)}")
892
899
  if cc_emails:
@@ -897,106 +904,147 @@ class DataProcessingAndMessaging:
897
904
  attach_names = [os.path.basename(att) for att in attachments]
898
905
  self.logger.info(f"附件: {', '.join(attach_names)}")
899
906
 
900
- # 7. SMTP固定配置
901
- sender_email = 'cc_yingxiao@xin.com'
902
- sender_password = 'cw46pfeznNQx'
903
- smtp_host = 'mail.xin.com'
904
- smtp_port = 587
907
+ # 所有收件人提前合并去重
908
+ all_recipients = list(set(to_emails + cc_emails + bcc_emails))
909
+ last_exception = None
905
910
 
906
- try:
907
- # 8. 构建邮件对象
908
- msg = MIMEMultipart()
909
- msg['From'] = sender_email
910
- msg['To'] = ', '.join(to_emails)
911
- if cc_emails:
912
- msg['Cc'] = ', '.join(cc_emails)
913
- if bcc_emails:
914
- msg['Bcc'] = ', '.join(bcc_emails)
915
- msg['Subject'] = subject
916
-
917
- # 9. 邮件正文(修复中文乱码,指定utf-8编码)
918
- body = MIMEText(html_body, 'html', 'utf-8')
919
- msg.attach(body)
920
-
921
- # 10. 附件处理(全格式支持+提前校验)
922
- valid_attachments = []
923
- for attachment in attachments:
924
- attachment = attachment.strip()
925
- if not os.path.exists(attachment):
926
- error_msg = f"❌ 邮件发送失败:附件不存在 -> {attachment}"
927
- self.logger.error(error_msg)
928
- print(error_msg)
929
- raise FileNotFoundError(error_msg)
930
-
931
- # 自动识别MIME类型,适配不同文件
932
- file_name = os.path.basename(attachment)
933
- mime_type = get_mime_type(attachment)
934
-
935
- with open(attachment, 'rb') as file:
936
- file_content = file.read()
937
-
938
- # 按文件类型选择对应的MIME对象
939
- if mime_type.startswith('image/'):
940
- part = MIMEImage(file_content, _subtype=mime_type.split('/')[1])
941
- elif mime_type == 'text/plain' or mime_type == 'text/csv':
942
- part = MIMEText(file_content.decode('utf-8'), _subtype=mime_type.split('/')[1], _charset='utf-8')
943
- else:
944
- part = MIMEApplication(file_content, _subtype=mime_type.split('/')[1])
945
-
946
- part['Content-Disposition'] = f'attachment; filename="{file_name}"'
947
- part['Content-Type'] = f'{mime_type}; name="{file_name}"'
948
- msg.attach(part)
949
- valid_attachments.append(file_name)
950
- self.logger.debug(f"已添加附件: {file_name}")
951
- print(f"✅ 已添加附件: {file_name}")
952
-
953
- # 11. 连接SMTP服务器并发送(修复核心bug:587端口必须启用TLS)
954
- print(f"🔌 正在连接SMTP服务器 {smtp_host}:{smtp_port}...")
955
- with smtplib.SMTP(smtp_host, smtp_port, timeout=120) as smtp:
956
- smtp.starttls() # 587端口强制启用TLS,绝大多数服务器要求
957
- smtp.login(sender_email, sender_password)
958
- print(f"🔐 SMTP服务器登录成功")
959
-
960
- # 所有收件人去重,避免重复发送
961
- all_recipients = list(set(to_emails + cc_emails + bcc_emails))
962
- smtp.sendmail(sender_email, all_recipients, msg.as_string())
963
-
964
- # 12. 发送成功:控制台打印+日志(和旧版完全对齐)
965
- success_msg = f"✅ 邮件发送成功 | 主题:{subject} | 收件人:{len(to_emails)}人"
966
- if cc_emails:
967
- success_msg += f" | 抄送:{len(cc_emails)}人"
968
- if bcc_emails:
969
- success_msg += f" | 密送:{len(bcc_emails)}人"
970
- if valid_attachments:
971
- success_msg += f" | 附件:{len(valid_attachments)}个"
911
+ # 7. 循环重试发送(解决网络超时/抖动)
912
+ for retry_idx in range(1, self.MAIL_RETRY_TIMES + 1):
913
+ try:
914
+ # 8. 构建邮件对象
915
+ msg = MIMEMultipart()
916
+ msg['From'] = self.SMTP_SENDER
917
+ msg['To'] = ', '.join(to_emails)
918
+ if cc_emails:
919
+ msg['Cc'] = ', '.join(cc_emails)
920
+ if bcc_emails:
921
+ msg['Bcc'] = ', '.join(bcc_emails)
922
+ msg['Subject'] = subject
923
+
924
+ # 9. 邮件正文
925
+ body = MIMEText(html_body, 'html', 'utf-8')
926
+ msg.attach(body)
927
+
928
+ # 10. 附件处理 + 安全解码 + 中文文件名修复
929
+ valid_attachments = []
930
+ for attachment in attachments:
931
+ attachment = attachment.strip()
932
+ if not os.path.exists(attachment):
933
+ error_msg = f"❌ 邮件发送失败:附件不存在 -> {attachment}"
934
+ self.logger.error(error_msg)
935
+ print(error_msg)
936
+ raise FileNotFoundError(error_msg)
937
+
938
+ file_name = os.path.basename(attachment)
939
+ mime_type = get_mime_type(attachment)
940
+
941
+ # 二进制读取,避免大文件/编码报错
942
+ try:
943
+ with open(attachment, 'rb') as file:
944
+ file_content = file.read()
945
+ except Exception as e:
946
+ err = f"❌ 读取附件失败 {attachment}:{str(e)}"
947
+ self.logger.error(err, exc_info=True)
948
+ print(err)
949
+ raise RuntimeError(err)
950
+
951
+ # 构造附件
952
+ if mime_type.startswith('image/'):
953
+ part = MIMEImage(file_content, _subtype=mime_type.split('/')[1])
954
+ elif mime_type in ('text/plain', 'text/csv'):
955
+ # 文本文件容错解码
956
+ text = file_content.decode("utf-8", errors="replace")
957
+ part = MIMEText(text, _subtype=mime_type.split('/')[1], _charset='utf-8')
958
+ else:
959
+ part = MIMEApplication(file_content, _subtype=mime_type.split('/')[1])
960
+
961
+ # 修复中文附件名乱码(RFC2231标准)
962
+ part.add_header('Content-Disposition', 'attachment', filename=file_name)
963
+ part.set_param("filename*", f"utf-8''{file_name}", header="Content-Disposition")
964
+ part['Content-Type'] = f'{mime_type}'
965
+ msg.attach(part)
966
+
967
+ valid_attachments.append(file_name)
968
+ self.logger.debug(f"已添加附件: {file_name}")
969
+ print(f"✅ 已添加附件: {file_name}")
970
+
971
+ # 11. 连接SMTP服务器(延长超时 + 双重ehlo提升兼容性)
972
+ print(f"🔌 第{retry_idx}次尝试连接 SMTP {self.SMTP_HOST}:{self.SMTP_PORT}")
973
+ self.logger.info(f"第{retry_idx}次连接 SMTP 服务器")
974
+
975
+ with smtplib.SMTP(self.SMTP_HOST, self.SMTP_PORT, timeout=self.SMTP_TIMEOUT) as smtp:
976
+ smtp.ehlo()
977
+ smtp.starttls()
978
+ smtp.ehlo()
979
+ smtp.login(self.SMTP_SENDER, self.SMTP_PWD)
980
+ print(f"🔐 SMTP服务器登录成功")
981
+
982
+ smtp.sendmail(self.SMTP_SENDER, all_recipients, msg.as_string())
983
+
984
+ # 发送成功
985
+ success_msg = f"✅ 邮件发送成功 | 主题:{subject} | 收件人:{len(to_emails)}人"
986
+ if cc_emails:
987
+ success_msg += f" | 抄送:{len(cc_emails)}人"
988
+ if bcc_emails:
989
+ success_msg += f" | 密送:{len(bcc_emails)}人"
990
+ if valid_attachments:
991
+ success_msg += f" | 附件:{len(valid_attachments)}个"
992
+
993
+ self.logger.info(success_msg)
994
+ print(success_msg)
995
+ return True
972
996
 
973
- self.logger.info(success_msg)
974
- print(success_msg)
975
- return True
997
+ # 可重试异常:超时、连接断开
998
+ except (TimeoutError, smtplib.SMTPServerDisconnected) as e:
999
+ last_exception = e
1000
+ err = f"⚠️ 第{retry_idx}次发送超时/连接断开:{str(e)}"
1001
+ self.logger.warning(err)
1002
+ print(err)
1003
+ if retry_idx < self.MAIL_RETRY_TIMES:
1004
+ print(f"⏳ {self.MAIL_RETRY_INTERVAL} 秒后进行重试...")
1005
+ time.sleep(self.MAIL_RETRY_INTERVAL)
1006
+ continue
1007
+
1008
+ # 账号密码错误:致命异常,直接终止重试
1009
+ except smtplib.SMTPAuthenticationError:
1010
+ err_msg = "❌ 邮件发送失败:SMTP账号/密码错误,终止重试"
1011
+ self.logger.error(err_msg, exc_info=True)
1012
+ print(err_msg)
1013
+ raise ValueError(err_msg)
976
1014
 
977
- # 13. 分类异常捕获(和旧版对齐,易排查问题)
978
- except smtplib.SMTPAuthenticationError:
979
- err_msg = "❌ 邮件发送失败:SMTP账号/密码/授权码错误"
980
- self.logger.error(err_msg, exc_info=True)
981
- print(err_msg)
982
- raise ValueError(err_msg)
983
- except smtplib.SMTPConnectError:
984
- err_msg = "❌ 邮件发送失败:SMTP服务器连接失败(检查host/port/防火墙/网络)"
985
- self.logger.error(err_msg, exc_info=True)
986
- print(err_msg)
987
- raise ConnectionError(err_msg)
988
- except smtplib.SMTPException as e:
989
- err_msg = f"❌ 邮件发送失败:SMTP协议错误 - {str(e)}"
990
- self.logger.error(err_msg, exc_info=True)
991
- print(err_msg)
992
- raise RuntimeError(err_msg)
993
- except FileNotFoundError:
994
- raise # 附件错误已提前处理,直接抛出
995
- except Exception as e:
996
- err_msg = f"❌ 邮件发送失败:{str(e)}"
997
- self.logger.error(err_msg, exc_info=True)
998
- print(err_msg)
999
- raise RuntimeError(err_msg)
1015
+ # 连接失败
1016
+ except smtplib.SMTPConnectError:
1017
+ err_msg = "❌ 邮件发送失败:SMTP服务器连接失败(检查网络/防火墙)"
1018
+ self.logger.error(err_msg, exc_info=True)
1019
+ print(err_msg)
1020
+ raise ConnectionError(err_msg)
1021
+
1022
+ # 其他SMTP协议异常
1023
+ except smtplib.SMTPException as e:
1024
+ err_msg = f"❌ 邮件发送失败:SMTP协议错误 - {str(e)}"
1025
+ self.logger.error(err_msg, exc_info=True)
1026
+ print(err_msg)
1027
+ raise RuntimeError(err_msg)
1028
+
1029
+ # 文件类异常,直接抛出
1030
+ except (FileNotFoundError, RuntimeError):
1031
+ raise
1032
+
1033
+ # 通用未知异常
1034
+ except Exception as e:
1035
+ last_exception = e
1036
+ err = f"⚠️ 第{retry_idx}次发送未知异常:{str(e)}"
1037
+ self.logger.error(err, exc_info=True)
1038
+ print(err)
1039
+ if retry_idx < self.MAIL_RETRY_TIMES:
1040
+ time.sleep(self.MAIL_RETRY_INTERVAL)
1041
+ continue
1042
+
1043
+ # 所有重试全部失败
1044
+ final_err = f"❌ 邮件{self.MAIL_RETRY_TIMES}次重试全部失败,最终异常:{str(last_exception)}"
1045
+ self.logger.error(final_err, exc_info=True)
1046
+ print(final_err)
1047
+ raise RuntimeError(final_err)
1000
1048
 
1001
1049
  # -------------------------- Excel格式化 --------------------------
1002
1050
  def format_excel_worksheet(self, worksheet, df, workbook):
@@ -1687,28 +1735,38 @@ class DataProcessingAndMessaging:
1687
1735
  self.logger.warning(f"关闭Excel进程时发生异常: {str(e)}")
1688
1736
 
1689
1737
  # -------------------------- 上传文件/DF到内网文件服务器(最终完整版) --------------------------
1690
- def upload_to_internal_server(self, input_data, filename_in_server: str = "dataframe_result.xlsx"):
1738
+ # -------------------------- 上传文件/DF到内网文件服务器(带可控自动下载最终版) --------------------------
1739
+ def upload_to_internal_server(self, input_data, filename_in_server: str = "dataframe_result.xlsx",
1740
+ auto_download: bool = False, download_save_path: str = None):
1691
1741
  """
1692
- 上传数据到内网 http://fs-cc.xin.com(按要求定制:重试3次、读超时5分钟,无拆分无压缩)
1693
- :param input_data: 支持 3 种输入 →
1694
- 1) 单个 DataFrame
1695
- 2) 字典 {sheet名: df} → 自动生成多Sheet Excel
1696
- 3) 本地Excel文件路径(str)
1742
+ 上传数据到内网 http://fs-cc.xin.com(带可控自动下载功能)
1743
+ :param input_data: 支持 3 种输入 → 1) 单个 DataFrame 2) 字典 {sheet名: df} 3) 本地Excel文件路径(str)
1697
1744
  :param filename_in_server: 服务器上显示的文件名
1745
+ :param auto_download: 上传成功后是否自动下载,【默认False=关闭下载】,仅传入True时启动下载
1746
+ :param download_save_path: 下载文件的本地保存路径(可选),默认与日志文件同目录
1698
1747
  :return: 下载链接(失败返回None)
1699
1748
  """
1749
+ import requests
1750
+ import pandas as pd
1751
+ import os
1752
+ import datetime
1753
+ from io import BytesIO
1754
+ from requests.adapters import HTTPAdapter
1755
+ from urllib3.util.retry import Retry
1756
+
1700
1757
  upload_url = "http://fs-cc.xin.com"
1701
1758
  self.logger.info(f"开始上传数据到内网服务器,服务器文件名:{filename_in_server}")
1702
1759
  print(f"📤 正在上传 → 服务器文件名:{filename_in_server}")
1703
1760
 
1704
- # ====================== 【按要求修改:重试固定3次】 ======================
1705
- def create_retry_session(retries=3):
1761
+ # ====================== 【完全保留原有配置:重试3次、读超时5分钟】 ======================
1762
+ def create_retry_session(retries=3, allowed_methods=None):
1763
+ allowed_methods = allowed_methods or ["POST"]
1706
1764
  session = requests.Session()
1707
1765
  retry_strategy = Retry(
1708
1766
  total=retries,
1709
1767
  backoff_factor=2,
1710
1768
  status_forcelist=[500, 502, 503, 504, 408],
1711
- allowed_methods=["POST"],
1769
+ allowed_methods=allowed_methods,
1712
1770
  raise_on_status=False
1713
1771
  )
1714
1772
  adapter = HTTPAdapter(max_retries=retry_strategy)
@@ -1718,9 +1776,48 @@ class DataProcessingAndMessaging:
1718
1776
 
1719
1777
  # ======================================================================
1720
1778
 
1779
+ # ====================== 【新增:自动下载核心函数(与上传逻辑完全对齐)】 ======================
1780
+ def _auto_download_file(download_url, save_path, file_name):
1781
+ """内部自动下载函数,带重试保障、流式下载、日志同步"""
1782
+ try:
1783
+ # 自动创建保存目录,不存在则新建
1784
+ os.makedirs(save_path, exist_ok=True)
1785
+ full_save_path = os.path.join(save_path, file_name)
1786
+
1787
+ self.logger.info(f"📥 启动自动下载,文件保存路径:{full_save_path}")
1788
+ print(f"📥 启动自动下载,文件保存路径:{full_save_path}")
1789
+
1790
+ # 流式下载(支持大文件,避免内存溢出),带3次重试、5分钟超时
1791
+ session = create_retry_session(retries=3, allowed_methods=["GET"])
1792
+ response = session.get(download_url, timeout=(10, 300), stream=True)
1793
+
1794
+ if response.status_code == 200:
1795
+ # 分块写入文件
1796
+ with open(full_save_path, 'wb') as f:
1797
+ for chunk in response.iter_content(chunk_size=8192):
1798
+ if chunk:
1799
+ f.write(chunk)
1800
+
1801
+ self.logger.info(f"✅ 自动下载成功,文件已保存至:{full_save_path}")
1802
+ print(f"✅ 自动下载成功,文件已保存至:{full_save_path}")
1803
+ return full_save_path
1804
+ else:
1805
+ err_msg = f"❌ 自动下载失败,服务器响应状态码:{response.status_code}"
1806
+ self.logger.error(err_msg)
1807
+ print(err_msg)
1808
+ return None
1809
+
1810
+ except Exception as e:
1811
+ err_msg = f"❌ 自动下载异常:{str(e)}"
1812
+ self.logger.error(err_msg, exc_info=True)
1813
+ print(err_msg)
1814
+ return None
1815
+
1816
+ # ======================================================================
1817
+
1721
1818
  try:
1722
1819
  # ==============================================
1723
- # 【完全保留原逻辑:无Sheet拆分、无ZIP压缩】
1820
+ # 【100%完全保留原有上传逻辑:无Sheet拆分、无ZIP压缩】
1724
1821
  # ==============================================
1725
1822
  if isinstance(input_data, dict):
1726
1823
  # 字典 → 多Sheet Excel
@@ -1759,25 +1856,23 @@ class DataProcessingAndMessaging:
1759
1856
  else:
1760
1857
  raise ValueError(f"不支持输入类型:{type(input_data)}")
1761
1858
 
1762
- # 上传
1859
+ # 上传执行
1763
1860
  session = create_retry_session()
1764
1861
  files = {"file": (filename_in_server, file_obj, file_type)}
1765
- # ====================== 【按要求修改:读超时改为5分钟(300秒)】 ======================
1766
1862
  response = session.post(upload_url, files=files, timeout=(10, 600))
1767
- # ======================================================================
1768
1863
 
1769
1864
  # 关闭文件
1770
1865
  if isinstance(input_data, str):
1771
1866
  file_obj.close()
1772
1867
 
1773
- # 结果处理
1868
+ # 上传结果处理
1774
1869
  if response.status_code == 200:
1775
1870
  download_url = response.text.strip()
1776
- self.logger.info(f"✅ 上传成功,链接:{download_url}")
1871
+ self.logger.info(f"✅ 上传成功,下载链接:{download_url}")
1777
1872
  print("✅ 上传成功!")
1778
1873
  print("🔗 下载地址:", download_url)
1779
1874
 
1780
- # 生成同名链接文件(完全保留原逻辑)
1875
+ # 生成同名链接文件(完全保留原有逻辑)
1781
1876
  file_base_name = os.path.splitext(filename_in_server)[0]
1782
1877
  link_file_name = f"{file_base_name}.log"
1783
1878
  link_path = os.path.join(os.path.dirname(self.main_log_file), link_file_name)
@@ -1789,10 +1884,19 @@ class DataProcessingAndMessaging:
1789
1884
  f.write(file_content)
1790
1885
 
1791
1886
  self.logger.info(f"上传链接已保存到:{link_path}")
1887
+
1888
+ # ====================== 【核心:仅当auto_download=True时,才启动自动下载】 ======================
1889
+ if auto_download:
1890
+ # 下载路径优先级:用户自定义路径 > 默认日志文件同目录
1891
+ final_save_path = download_save_path if download_save_path else os.path.dirname(self.main_log_file)
1892
+ # 执行自动下载
1893
+ _auto_download_file(download_url, final_save_path, filename_in_server)
1894
+ # ======================================================================
1895
+
1792
1896
  return download_url
1793
1897
 
1794
1898
  else:
1795
- err = f"❌ 上传失败,状态码:{response.status_code}"
1899
+ err = f"❌ 上传失败,服务器响应状态码:{response.status_code}"
1796
1900
  self.logger.error(err)
1797
1901
  print(err)
1798
1902
  return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Functions_d
3
- Version: 1.34
3
+ Version: 1.36
4
4
  Summary: 包含数据处理、Hive交互、企业微信消息发送、Excel操作等功能的工具类库
5
5
  Author: DongYang
6
6
  Author-email: 649898871@qq.com
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Functions_d
3
- Version: 1.34
3
+ Version: 1.36
4
4
  Summary: 包含数据处理、Hive交互、企业微信消息发送、Excel操作等功能的工具类库
5
5
  Author: DongYang
6
6
  Author-email: 649898871@qq.com
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = Functions_d
3
- version = 1.34
3
+ version = 1.36
4
4
  author = DongYang
5
5
  author_email = 649898871@qq.com
6
6
  description = 包含数据处理、Hive交互、企业微信消息发送、Excel操作等功能的工具类库
File without changes
File without changes
File without changes