excel_handler.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import sys
  2. import os
  3. import time
  4. from openpyxl import load_workbook
  5. def get_resource_path(relative_path):
  6. """ 获取资源绝对路径,兼容开发环境和 PyInstaller 打包环境 """
  7. if hasattr(sys, '_MEIPASS'):
  8. # PyInstaller 打包后的临时解压路径
  9. return os.path.join(sys._MEIPASS, relative_path)
  10. # 开发环境下的路径
  11. base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  12. return os.path.join(base_dir, relative_path)
  13. def get_existing_info(file_path):
  14. """
  15. 读取已有文件中的链接和最后一行编码
  16. """
  17. links = set()
  18. last_code = 0
  19. if not os.path.exists(file_path):
  20. return links, last_code
  21. try:
  22. wb = load_workbook(file_path, data_only=True)
  23. ws = wb.active
  24. # 假设 A 列是编码,K 列是链接
  25. for r in range(3, ws.max_row + 1):
  26. code_val = ws.cell(row=r, column=1).value
  27. link_val = ws.cell(row=r, column=11).value
  28. if link_val:
  29. links.add(str(link_val).strip())
  30. if isinstance(code_val, (int, float)):
  31. last_code = max(last_code, int(code_val))
  32. except:
  33. pass
  34. return links, last_code
  35. def append_to_template(products, output_path, status_callback=None):
  36. """
  37. 将产品数据追加写入到指定的 Excel 文件中。
  38. 增加文件占用检测:如果文件被打开,则暂停任务直到关闭。
  39. 并在第二个 Sheet 中记录商品总数。
  40. """
  41. template_path = get_resource_path(os.path.join('templates', '【进价】产品信息空表.xlsx'))
  42. if not os.path.exists(template_path):
  43. template_path = os.path.join('templates', '【进价】产品信息空表.xlsx')
  44. if not os.path.exists(template_path):
  45. raise FileNotFoundError(f"未找到核心模板文件: {template_path}")
  46. if os.path.exists(output_path):
  47. wb = load_workbook(output_path)
  48. else:
  49. os.makedirs(os.path.dirname(output_path), exist_ok=True)
  50. wb = load_workbook(template_path)
  51. # 1. 写入主数据 Sheet
  52. ws = wb.active
  53. # 寻找起始行 (基于第 11 列“产品链接”进行判定,防止覆盖)
  54. start_row = 3
  55. for r in range(3, ws.max_row + 2):
  56. val_link = ws.cell(row=r, column=11).value
  57. if val_link is None or str(val_link).strip() == "":
  58. start_row = r
  59. break
  60. else:
  61. start_row = ws.max_row + 1
  62. # 获取当前已有的链接集合,用于后续统计唯一商品
  63. existing_links = set()
  64. for r in range(3, start_row):
  65. link = ws.cell(row=r, column=11).value
  66. if link: existing_links.add(str(link).strip())
  67. for i, product in enumerate(products):
  68. row = start_row + i
  69. ws.cell(row=row, column=1, value=row - 2)
  70. ws.cell(row=row, column=2, value=product.get('category', ''))
  71. ws.cell(row=row, column=3, value=product.get('brand', ''))
  72. ws.cell(row=row, column=4, value=product.get('name', ''))
  73. ws.cell(row=row, column=5, value=product.get('color', ''))
  74. ws.cell(row=row, column=6, value=product.get('spec', ''))
  75. ws.cell(row=row, column=7, value=product.get('material', ''))
  76. ws.cell(row=row, column=8, value=product.get('price', ''))
  77. ws.cell(row=row, column=9, value=product.get('moq', ''))
  78. ws.cell(row=row, column=10, value=product.get('wholesale_price', ''))
  79. ws.cell(row=row, column=11, value=product.get('link', ''))
  80. ws.cell(row=row, column=12, value=product.get('supplier', ''))
  81. link = product.get('link')
  82. if link: existing_links.add(str(link).strip())
  83. # 2. 写入/更新计数 Sheet (第二个 Sheet)
  84. sheet_names = wb.sheetnames
  85. if len(sheet_names) < 2:
  86. wb.create_sheet("统计状态")
  87. ws_stat = wb["统计状态"]
  88. ws_stat.cell(row=1, column=1, value="已解析商品总数")
  89. ws_stat.cell(row=1, column=2, value=len(existing_links))
  90. ws_stat.cell(row=2, column=1, value="最后更新时间")
  91. ws_stat.cell(row=2, column=2, value=time.strftime("%Y-%m-%d %H:%M:%S"))
  92. # 3. 占用检测保存循环
  93. while True:
  94. try:
  95. wb.save(output_path)
  96. if status_callback:
  97. status_callback(False, "写入成功")
  98. break
  99. except PermissionError:
  100. msg = "文件被占用,请关闭 Excel"
  101. print(f"[!] {msg}: {output_path}")
  102. if status_callback:
  103. status_callback(True, msg)
  104. time.sleep(3)