# from selenium import webdriver
# from selenium.webdriver.common.by import By
# from selenium.webdriver.support.ui import WebDriverWait
# from selenium.webdriver.support import expected_conditions as EC
# from selenium.common.exceptions import TimeoutException, NoSuchElementException
# import datetime
# import time
# import sys
# import os
# import glob
#
#
# # ========================================
# # 能源系统登录类
# # ========================================
# class EnergySystemLogin:
# def __init__(self):
# self.login_url = "http://10.11.20.117:7001/energy4/#/login"
# self.credentials = {'username': 'E915285', 'password': '123456'}
# self.driver = None
# self.wait_timeout = 30
#
# def initialize_driver(self):
# """初始化Chrome浏览器(无头模式 + 支持文件下载)"""
# try:
# options = webdriver.ChromeOptions()
# # --- 基础反检测设置 ---
# options.add_argument("--disable-blink-features=AutomationControlled")
# options.add_argument("--start-maximized")
# options.add_argument("--headless=new") # 使用新版无头模式
# options.add_argument("--disable-gpu")
# options.add_argument("--no-sandbox")
# options.add_argument("--disable-dev-shm-usage")
# options.add_argument("--window-size=1920,1080")
# options.add_argument("--log-level=3")
#
# options.add_experimental_option("excludeSwitches", ["enable-automation"])
# options.add_experimental_option("useAutomationExtension", False)
#
# # === 👇 下载配置 ===
# download_dir = r"D:\Class\能管比对\导出文件"
# if not os.path.exists(download_dir):
# os.makedirs(download_dir)
#
# prefs = {
# "download.default_directory": download_dir,
# "download.prompt_for_download": False,
# "download.directory_upgrade": True,
# "safebrowsing.enabled": True,
# "profile.default_content_settings.popups": 0,
# "plugins.always_open_pdf_externally": False,
# }
# options.add_experimental_option("prefs", prefs)
# # === ✅ 配置结束 ===
#
# self.driver = webdriver.Chrome(options=options)
# self.driver.implicitly_wait(10)
#
# # 防止被检测为机器人
# self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => false});")
#
# self.log_action(f"浏览器初始化完成,下载路径: {download_dir}")
# return True
#
# except Exception as e:
# self.log_error(f"浏览器初始化失败: {str(e)}")
# return False
#
# def log_action(self, message):
# timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# print(f"[{timestamp}] {message}")
#
# def log_error(self, message):
# timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
# self.log_action(f"错误: {message}")
# if self.driver:
# try:
# self.driver.save_screenshot(f"error_{timestamp}.png")
# except Exception as e:
# print(f"[{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 截图失败: {str(e)}")
#
# def locate_and_input(self, by, value, text, description):
# try:
# element = WebDriverWait(self.driver, self.wait_timeout).until(
# EC.visibility_of_element_located((by, value))
# )
# element.clear()
# element.send_keys(text)
# self.log_action(f"{description} 输入完成")
# return True
# except Exception as e:
# self.log_error(f"{description} 输入失败: {str(e)}")
# return False
#
# def perform_login(self):
# try:
# self.log_action("访问登录页面")
# self.driver.get(self.login_url)
#
# WebDriverWait(self.driver, self.wait_timeout).until(
# lambda d: d.execute_script("return document.readyState") == "complete"
# )
#
# if not self.locate_and_input(
# By.CSS_SELECTOR,
# "input.el-input__inner[type='text']",
# self.credentials['username'],
# "用户名"
# ):
# return False
#
# if not self.locate_and_input(
# By.CSS_SELECTOR,
# "input.el-input__inner[type='password']",
# self.credentials['password'],
# "密码"
# ):
# return False
#
# try:
# login_btn = WebDriverWait(self.driver, self.wait_timeout).until(
# EC.element_to_be_clickable((By.CSS_SELECTOR, "button.loginBtn"))
# )
# login_btn.click()
# self.log_action("点击登录按钮")
# except Exception as e:
# self.log_error(f"点击登录按钮失败: {str(e)}")
# return False
#
# try:
# WebDriverWait(self.driver, 20).until(
# EC.url_contains("/energy4/#/")
# )
# WebDriverWait(self.driver, 10).until_not(
# EC.presence_of_element_located((By.CLASS_NAME, "login-container"))
# )
# self.log_action("登录成功")
# self.driver.save_screenshot("login_success.png")
# return True
# except TimeoutException:
# self.log_error("登录验证超时,可能未成功登录")
# return False
#
# except Exception as e:
# self.log_error(f"登录过程发生异常: {str(e)}")
# return False
#
# def get_driver(self):
# return self.driver
#
# def cleanup(self):
# if self.driver:
# try:
# self.driver.quit()
# except Exception as e:
# print(f"清理浏览器资源时出错: {str(e)}")
#
#
# # ========================================
# # 菜单导航与文件导出处理类
# # ========================================
# class MenuNavigator:
# def __init__(self, driver, download_dir=r"D:\Class\能管比对\导出文件"):
# self.driver = driver
# self.wait_timeout = 10
# self.click_delay = 3 # 可根据需要调整点击后等待时间
# self.download_dir = download_dir
# def get_timestamp(self):
# return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
#
# def log_action(self, message):
# print(f"[{self.get_timestamp()}] 操作: {message}")
#
# def log_error(self, message):
# print(f"[{self.get_timestamp()}] 错误: {message}")
# try:
# self.driver.save_screenshot(f"error_{int(time.time())}.png")
# except:
# pass
#
# def click_element(self, xpath, description):
# try:
# element = WebDriverWait(self.driver, self.wait_timeout).until(
# EC.visibility_of_element_located((By.XPATH, xpath))
# )
# element.click()
# self.log_action(f"点击成功: {description}")
# time.sleep(self.click_delay) # 固定等待页面响应
# return True
# except Exception as e:
# self.log_error(f"点击失败 ({description}): {str(e)}")
# return False
#
# def get_latest_downloaded_file(self, timeout=30):
# """
# 等待并返回下载目录中最新修改的 .xlsx 文件(排除临时文件)
# """
# start_time = time.time()
# while time.time() - start_time < timeout:
# # 匹配所有非临时的 Excel 文件
# list_of_files = [
# f for f in glob.glob(os.path.join(self.download_dir, "*.xls*"))
# if not os.path.basename(f).startswith("~$")
# ]
# if list_of_files:
# latest_file = max(list_of_files, key=os.path.getmtime)
# # 检查文件是否还在写入(大小是否稳定)
# size1 = os.path.getsize(latest_file)
# time.sleep(1)
# size2 = os.path.getsize(latest_file)
# if size1 == size2:
# return latest_file
# time.sleep(1)
# raise Exception("等待下载超时,未检测到新文件")
#
# def rename_latest_file(self, new_name):
# """
# 将最新下载的文件重命名为指定名字,避免覆盖
# """
# try:
# old_file = self.get_latest_downloaded_file()
# new_file_path = os.path.join(self.download_dir, new_name)
#
# # 如果目标文件已存在,添加序号防止覆盖
# counter = 1
# base_name, ext = os.path.splitext(new_name)
# while os.path.exists(new_file_path):
# new_file_path = os.path.join(self.download_dir, f"{base_name}_{counter}{ext}")
# counter += 1
#
# os.rename(old_file, new_file_path)
# self.log_action(f"文件已重命名: {os.path.basename(old_file)} → {os.path.basename(new_file_path)}")
# return True
# except Exception as e:
# self.log_error(f"文件重命名失败: {str(e)}")
# return False
#
# # ================================
# # 🌟 所有预设的操作路径集中在这里
# # ================================
# OPERATIONS = {
# "1.低温冰水制冷功率": [
# {"xpath": "//span[@slot='title'][text()='能耗统计']", "desc": "能耗统计"},
# {"xpath": "//span[text()='分类统计' and contains(@data-v-11708afe,'')]", "desc": "分类统计"},
# {"xpath": "//div[@role='button' and contains(@class,'el-collapse-item__header')][normalize-space()='系统分组']", "desc": "系统分组"},
# {"xpath": "//span[@data-v-4fe475b6 and @title='空调系统' and normalize-space()='空调系统']", "desc": "空调系统"},
# {"xpath": "//span[@data-v-4fe475b6 and @title='冷热水系统' and normalize-space()='冷热水系统']", "desc": "冷热水系统"},
# {"xpath": "//div[contains(@class, 'el-tree-node__content') and contains(@style, 'padding-left: 36px')]//span[contains(@title, '低温冰水系统')]", "desc": "低温冰水系统"},
# {"xpath": "//span[@class='el-radio-button__inner' and normalize-space()='下级分类']", "desc": "下级分类"},
# {"xpath": "//div[contains(@style, 'padding-left: 54px')]//span[contains(@title, '低温冰水制冷功率') and @data-v-4fe475b6]","desc": "低温冰水制冷功率"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
# ],
# "2.低温冰水电功耗": [
# {"xpath": "//div[@class='el-tree-node__content' and .//span[contains(text(), '低温冰水电功耗')]]","desc": "低温冰水电功耗"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
# ],
#
#
# "3.中温冰水制冷功率": [
# {"xpath": "//div[@class='el-tree-node__content' and .//span[contains(@title, '中温冰水系统')]]","desc": "中温冰水系统"},
# {"xpath": "//span[@title='中温冰水制冷功率']/ancestor::div[@class='el-tree-node__content']","desc": "中温冰水制冷功率"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
# ],
# "4.中温冰水电功率": [
# {"xpath": "//span[@title='中温冰水电功率']/ancestor::div[@class='el-tree-node__content']","desc": "中温冰水电功率"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
# ],
#
# ##跳过高温热水
#
# "5.低温热水系统": [
# {"xpath": "//div[@class='el-tree-node__content' and .//span[contains(@title, '低温热水系统')]]","desc": "低温热水系统"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
# ],
# "6.冷却水系统": [
# {"xpath": "//div[@class='el-tree-node__content' and .//span[contains(@title, '冷却水系统')]]","desc": "冷却水系统"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
# ],
# "7.冰机油泵耗电量": [
# {"xpath": "//div[@class='el-tree-node__content' and .//span[contains(@title, '冰机油泵耗电量')]]","desc": "冰机油泵耗电量"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
# ],
# "8.低10a冷库耗电量": [
# {"xpath": "//div[@class='el-tree-node__content' and .//span[contains(@title, '10a冷库耗电量')]]","desc": "10a冷库耗电量"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
# {"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
# ],
# }
#
# def navigate(self, task_key):
# """
# 根据 task_key 执行对应的操作流并导出文件
# """
# if task_key not in self.OPERATIONS:
# self.log_error(f"未找到名为 '{task_key}' 的操作流程")
# return False
#
# operations = self.OPERATIONS[task_key]
# self.log_action(f"开始执行任务: {task_key}")
#
# for op in operations:
# if not self.click_element(op["xpath"], op["desc"]):
# self.log_error(f"操作中断于: {op['desc']}")
# return False
#
# # === 导出完成后处理文件名 ===
# expected_filename = self.task_file_mapping.get(task_key, f"{task_key}.xlsx")
# self.log_action("正在等待导出文件生成...")
#
# if self.rename_latest_file(expected_filename):
# self.log_action(f"✅ 任务 '{task_key}' 成功,文件已保存为: {expected_filename}")
# return True
# else:
# self.log_error(f"❌ 任务 '{task_key}' 失败:无法获取或重命名导出文件")
# return False
#
# # 主程序入口
# # ========================
# if __name__ == "__main__":
# login = None
# try:
# login = EnergySystemLogin()
#
# if not login.initialize_driver():
# print("❌ 浏览器初始化失败,程序终止")
# sys.exit(1)
#
# if not login.perform_login():
# print("❌ 登录失败,程序终止")
# sys.exit(1)
#
# driver = login.get_driver()
# navigator = MenuNavigator(driver)
#
# # ✅ 自动获取所有定义在 OPERATIONS 中的任务
# tasks_to_run = list(navigator.OPERATIONS.keys())
#
# print(f"📋 共发现 {len(tasks_to_run)} 个待执行任务:")
# for i, task in enumerate(tasks_to_run, 1):
# print(f" {i}. {task}")
#
# success_count = 0
# for task in tasks_to_run:
# print(f"\n🔁 正在执行任务: {task}")
# if navigator.navigate(task):
# print(f"✅ 任务 '{task}' 执行成功")
# success_count += 1
# else:
# print(f"❌ 任务 '{task}' 执行失败")
#
# print(f"\n🎉 总结:{success_count}/{len(tasks_to_run)} 个任务执行成功")
#
# except KeyboardInterrupt:
# print("\n\n🛑 用户手动中断程序")
# except Exception as e:
# print(f"🚨 程序发生未预期异常: {str(e)}")
# finally:
# if login:
# login.cleanup()
# print("🔚 程序结束")
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import datetime
import time
import sys
import os
import glob
import re
# ========================================
# 能源系统登录类
# ========================================
class EnergySystemLogin:
def __init__(self):
self.login_url = "http://10.11.20.117:7001/energy4/#/login"
self.credentials = {'username': 'E915285', 'password': '123456'}
self.driver = None
self.wait_timeout = 30
def initialize_driver(self):
"""初始化Chrome浏览器(无头模式 + 支持文件下载)"""
try:
options = webdriver.ChromeOptions()
# --- 基础反检测设置 ---
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("--start-maximized")
options.add_argument("--headless=new") # 使用新版无头模式
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--window-size=1920,1080")
options.add_argument("--log-level=3")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
# === 👇 下载配置 ===
download_dir = r"D:\Class\能管比对\导出文件"
if not os.path.exists(download_dir):
os.makedirs(download_dir)
prefs = {
"download.default_directory": download_dir,
"download.prompt_for_download": False,
"download.directory_upgrade": True,
"safebrowsing.enabled": True,
"profile.default_content_settings.popups": 0,
"plugins.always_open_pdf_externally": False,
}
options.add_experimental_option("prefs", prefs)
# === ✅ 配置结束 ===
self.driver = webdriver.Chrome(options=options)
self.driver.implicitly_wait(10)
# 防止被检测为机器人
self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => false});")
self.log_action(f"浏览器初始化完成,下载路径: {download_dir}")
return True
except Exception as e:
self.log_error(f"浏览器初始化失败: {str(e)}")
return False
def log_action(self, message):
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"[{timestamp}] {message}")
def log_error(self, message):
timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
self.log_action(f"错误: {message}")
if self.driver:
try:
self.driver.save_screenshot(f"error_{timestamp}.png")
except Exception as e:
print(f"[{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 截图失败: {str(e)}")
def locate_and_input(self, by, value, text, description):
try:
element = WebDriverWait(self.driver, self.wait_timeout).until(
EC.visibility_of_element_located((by, value))
)
element.clear()
element.send_keys(text)
self.log_action(f"{description} 输入完成")
return True
except Exception as e:
self.log_error(f"{description} 输入失败: {str(e)}")
return False
def perform_login(self):
try:
self.log_action("访问登录页面")
self.driver.get(self.login_url)
WebDriverWait(self.driver, self.wait_timeout).until(
lambda d: d.execute_script("return document.readyState") == "complete"
)
if not self.locate_and_input(
By.CSS_SELECTOR,
"input.el-input__inner[type='text']",
self.credentials['username'],
"用户名"
):
return False
if not self.locate_and_input(
By.CSS_SELECTOR,
"input.el-input__inner[type='password']",
self.credentials['password'],
"密码"
):
return False
try:
login_btn = WebDriverWait(self.driver, self.wait_timeout).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "button.loginBtn"))
)
login_btn.click()
self.log_action("点击登录按钮")
except Exception as e:
self.log_error(f"点击登录按钮失败: {str(e)}")
return False
try:
WebDriverWait(self.driver, 20).until(
EC.url_contains("/energy4/#/")
)
WebDriverWait(self.driver, 10).until_not(
EC.presence_of_element_located((By.CLASS_NAME, "login-container"))
)
self.log_action("登录成功")
self.driver.save_screenshot("login_success.png")
return True
except TimeoutException:
self.log_error("登录验证超时,可能未成功登录")
return False
except Exception as e:
self.log_error(f"登录过程发生异常: {str(e)}")
return False
def get_driver(self):
return self.driver
def cleanup(self):
if self.driver:
try:
self.driver.quit()
except Exception as e:
print(f"清理浏览器资源时出错: {str(e)}")
# ========================================
# 菜单导航与文件导出处理类
# ========================================
class MenuNavigator:
def __init__(self, driver, download_dir=r"D:\Class\能管比对\导出文件"):
self.driver = driver
self.wait_timeout = 10
self.click_delay = 3
self.download_dir = download_dir
def get_timestamp(self):
return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
def log_action(self, message):
print(f"[{self.get_timestamp()}] 操作: {message}")
def log_error(self, message):
print(f"[{self.get_timestamp()}] 错误: {message}")
try:
self.driver.save_screenshot(f"error_{int(time.time())}.png")
except:
pass
def click_element(self, xpath, description):
try:
element = WebDriverWait(self.driver, self.wait_timeout).until(
EC.visibility_of_element_located((By.XPATH, xpath))
)
element.click()
self.log_action(f"点击成功: {description}")
time.sleep(self.click_delay)
return True
except Exception as e:
self.log_error(f"点击失败 ({description}): {str(e)}")
return False
def get_latest_downloaded_file(self, timeout=30):
"""
等待并返回最新生成的 .xlsx 文件(排除临时文件)
"""
start_time = time.time()
while time.time() - start_time < timeout:
list_of_files = [
f for f in glob.glob(os.path.join(self.download_dir, "*.xls*"))
if not os.path.basename(f).startswith("~$")
]
if list_of_files:
latest_file = max(list_of_files, key=os.path.getmtime)
size1 = os.path.getsize(latest_file)
time.sleep(1)
size2 = os.path.getsize(latest_file)
if size1 == size2: # 文件大小稳定表示写入完成
return latest_file
time.sleep(1)
raise Exception("等待下载超时,未检测到新文件")
def extract_filename(self, task_key):
"""
从 task_key 中提取文件名,去掉前面的编号(如 "1.", "8.")
示例: "1.低温冰水制冷功率" -> "低温冰水制冷功率.xlsx"
"""
# 移除开头的数字加点格式,例如 "1.", "10."
match = re.match(r'^\d+\.\s*(.+)$', task_key.strip())
if match:
return match.group(1) + ".xlsx"
else:
return task_key + ".xlsx" # fallback
def rename_latest_file(self, new_name):
"""
将最新下载的文件重命名为指定名字,防止覆盖
"""
try:
old_file = self.get_latest_downloaded_file()
new_file_path = os.path.join(self.download_dir, new_name)
# 如果文件已存在,则添加序号避免覆盖
counter = 1
base_name, ext = os.path.splitext(new_name)
while os.path.exists(new_file_path):
new_file_path = os.path.join(self.download_dir, f"{base_name}_{counter}{ext}")
counter += 1
os.rename(old_file, new_file_path)
self.log_action(f"文件已重命名: {os.path.basename(old_file)} → {os.path.basename(new_file_path)}")
return True
except Exception as e:
self.log_error(f"文件重命名失败: {str(e)}")
return False
# ================================
# 🌟 所有预设的操作路径集中在这里
# ================================
OPERATIONS = {
"1.低温冰水制冷功率": [
{"xpath": "//span[@slot='title'][text()='能耗统计']", "desc": "能耗统计"},
{"xpath": "//span[text()='分类统计' and contains(@data-v-11708afe,'')]", "desc": "分类统计"},
{"xpath": "//div[@role='button' and contains(@class,'el-collapse-item__header')][normalize-space()='系统分组']", "desc": "系统分组"},
{"xpath": "//span[@data-v-4fe475b6 and @title='空调系统' and normalize-space()='空调系统']", "desc": "空调系统"},
{"xpath": "//span[@data-v-4fe475b6 and @title='冷热水系统' and normalize-space()='冷热水系统']", "desc": "冷热水系统"},
{"xpath": "//div[contains(@class, 'el-tree-node__content') and contains(@style, 'padding-left: 36px')]//span[contains(@title, '低温冰水系统')]", "desc": "低温冰水系统"},
{"xpath": "//span[@class='el-radio-button__inner' and normalize-space()='下级分类']", "desc": "下级分类"},
{"xpath": "//div[contains(@style, 'padding-left: 54px')]//span[contains(@title, '低温冰水制冷功率') and @data-v-4fe475b6]", "desc": "低温冰水制冷功率"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
],
"2.低温冰水电功耗": [
{"xpath": "//div[@class='el-tree-node__content' and .//span[contains(text(), '低温冰水电功耗')]]", "desc": "低温冰水电功耗"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
],
"3.中温冰水制冷功率": [
{"xpath": "//div[@class='el-tree-node__content' and .//span[contains(@title, '中温冰水系统')]]", "desc": "中温冰水系统"},
{"xpath": "//span[@title='中温冰水制冷功率']/ancestor::div[@class='el-tree-node__content']", "desc": "中温冰水制冷功率"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
],
"4.中温冰水电功率": [
{"xpath": "//span[@title='中温冰水电功率']/ancestor::div[@class='el-tree-node__content']", "desc": "中温冰水电功率"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
],
"5.低温热水系统": [
{"xpath": "//div[@class='el-tree-node__content' and .//span[contains(@title, '低温热水系统')]]", "desc": "低温热水系统"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
],
"6.冷却水系统": [
{"xpath": "//div[@class='el-tree-node__content' and .//span[contains(@title, '冷却水系统')]]", "desc": "冷却水系统"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
],
"7.冰机油泵耗电量": [
{"xpath": "//div[@class='el-tree-node__content' and .//span[contains(@title, '冰机油泵耗电量')]]", "desc": "冰机油泵耗电量"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
],
"8.低10a冷库耗电量": [
{"xpath": "//div[@class='el-tree-node__content' and .//span[contains(@title, '10a冷库耗电量')]]", "desc": "10a冷库耗电量"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '查 询')]", "desc": "查询"},
{"xpath": "//button[contains(@class, 'el-button') and contains(span/text(), '导出Excel')]", "desc": "导出"},
],
}
def navigate(self, task_key):
"""
根据 task_key 执行对应操作流并导出文件
"""
# if task_key not in self.OPERATIONS:
# self.log_error(f"未找到名为 '{task_key}' 的操作流程")
# return False
operations = self.OPERATIONS[task_key]
self.log_action(f"开始执行任务: {task_key}")
for op in operations:
if not self.click_element(op["xpath"], op["desc"]):
self.log_error(f"操作中断于: {op['desc']}")
return False
# === 自动生成文件名(去编号前缀)===
auto_filename = self.extract_filename(task_key)
self.log_action("正在等待导出文件生成...")
if self.rename_latest_file(auto_filename):
self.log_action(f"✅ 任务 '{task_key}' 成功,文件已保存为: {auto_filename}")
return True
# else:
# self.log_error(f"❌ 任务 '{task_key}' 失败:无法获取或重命名导出文件")
# return False
# ========================================
# 主程序入口
# ========================================
if __name__ == "__main__":
login = None
try:
login = EnergySystemLogin()
if not login.initialize_driver():
print("❌ 浏览器初始化失败,程序终止")
sys.exit(1)
if not login.perform_login():
print("❌ 登录失败,程序终止")
sys.exit(1)
driver = login.get_driver()
navigator = MenuNavigator(driver)
tasks_to_run = list(navigator.OPERATIONS.keys())
print(f"📋 共发现 {len(tasks_to_run)} 个待执行任务:")
for i, task in enumerate(tasks_to_run, 1):
print(f" {i}. {task}")
success_count = 0
for task in tasks_to_run:
print(f"\n🔁 正在执行任务: {task}")
if navigator.navigate(task):
print(f"✅ 任务 '{task}' 执行成功")
success_count += 1
else:
print(f"❌ 任务 '{task}' 执行失败")
print(f"\n🎉 总结:{success_count}/{len(tasks_to_run)} 个任务执行成功")
except KeyboardInterrupt:
print("\n\n🛑 用户手动中断程序")
except Exception as e:
print(f"🚨 程序发生未预期异常: {str(e)}")
finally:
if login:
login.cleanup()
print("🔚 程序结束")
——auto_filename对应代码中的什么,详细说明逻辑