Consolas as CMD.EXE (Windows Console) Font

本文介绍如何通过下载并安装Consolas字体、修改注册表及CMD属性等步骤,来改善Windows命令提示符界面的字体显示效果。

1、下载Consolas字体,并安装;

 

2、修改注册表;

 

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont\
Name: 00
Data: Consolas
 

 

3、更改CMD.exe属性

修改默认代码页为"OEM-美国“


 

字体选项卡中设置字体;


4、设置完成;


 

altgraph 0.17.4 bidict 0.23.1 blinker 1.9.0 cffi 1.17.1 click 8.2.1 colorama 0.4.6 dnspython 2.7.0 Flask 3.1.1 flask-cors 6.0.0 Flask-SocketIO 5.5.1 gevent 25.5.1 gevent-websocket 0.10.1 greenlet 3.2.3 h11 0.16.0 itsdangerous 2.2.0 Jinja2 3.1.6 MarkupSafe 3.0.2 Nuitka 2.7.6 ordered-set 4.1.0 packaging 25.0 pefile 2023.2.7 pip 22.0.4 portalocker 3.1.1 pyarmor 9.1.7 pyarmor.cli.core 7.6.7 pycparser 2.22 pyinstaller 6.14.0 pyinstaller-hooks-contrib 2025.4 python-engineio 4.12.2 python-socketio 5.13.0 pywin32 310 pywin32-ctypes 0.2.3 setuptools 58.1.0 simple-websocket 1.1.0 waitress 3.0.2 Werkzeug 3.1.3 wsproto 1.2.0 zope.event 5.0 zope.interface 7.2 zstandard 0.23.0以及打包软件的代码import tkinter as tk from tkinter import ttk, filedialog, messagebox import subprocess import threading import os import sys import shutil import json class PackerApp: def __init__(self, root): self.root = root root.title("EXE打包专家 v4.0") root.geometry("1800x900") self.running = False # 初始化变量 self.app_path = tk.StringVar() self.static_dir = tk.StringVar() self.data_path = tk.StringVar() self.icon_path = tk.StringVar() self.safe_pack = tk.BooleanVar(value=True) # 创建界面 self.create_widgets() # DPI适配 self.dpi_scaling() # 初始化日志系统 self.log_buffer = [] def dpi_scaling(self): """处理高DPI显示""" if sys.platform == "win32": try: from ctypes import windll windll.shcore.SetProcessDpiAwareness(1) except: pass def create_widgets(self): # 主框架 main_frame = ttk.Frame(self.root, padding=15) main_frame.pack(fill=tk.BOTH, expand=True) # 输入区域 input_frame = ttk.LabelFrame(main_frame, text="文件选择", padding=10) input_frame.pack(fill=tk.X, pady=5) self.create_file_row(input_frame, "主程序(.py):", self.app_path, "选择文件", self.select_app) self.create_file_row(input_frame, "静态目录:", self.static_dir, "选择目录", self.select_static_dir) self.create_file_row(input_frame, "数据文件(.json):", self.data_path, "选择文件", self.select_data) self.create_file_row(input_frame, "程序图标(.ico):", self.icon_path, "选择图标", self.select_icon) # 设置区域 options_frame = ttk.LabelFrame(main_frame, text="打包选项", padding=10) options_frame.pack(fill=tk.X, pady=5) ttk.Checkbutton(options_frame, text="单文件模式", variable=tk.BooleanVar(value=True)).grid(row=0, column=0, padx=5) ttk.Checkbutton(options_frame, text="无控制台窗口", variable=tk.BooleanVar(value=True)).grid(row=0, column=1, padx=5) ttk.Checkbutton(options_frame, text="安全混淆打包(防逆向)", variable=self.safe_pack).grid(row=0, column=2, padx=5) # 操作按钮 btn_frame = ttk.Frame(main_frame) btn_frame.pack(pady=10) ttk.Button(btn_frame, text="开始打包", command=self.start_pack).grid(row=0, column=0, padx=5) ttk.Button(btn_frame, text="清除日志", command=self.clear_log).grid(row=0, column=1, padx=5) # 日志区域 log_frame = ttk.LabelFrame(main_frame, text="打包日志", padding=10) log_frame.pack(fill=tk.BOTH, expand=True) self.log_text = tk.Text(log_frame, wrap=tk.WORD, state=tk.DISABLED, font=('Consolas', 20)) vsb = ttk.Scrollbar(log_frame, orient=tk.VERTICAL, command=self.log_text.yview) self.log_text.configure(yscrollcommand=vsb.set) self.log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) vsb.pack(side=tk.RIGHT, fill=tk.Y) def create_file_row(self, parent, label, var, btn_text, command): """创建统一文件选择行""" frame = ttk.Frame(parent) frame.pack(fill=tk.X, pady=10) ttk.Label(frame, text=label, width=20).pack(side=tk.LEFT) entry = ttk.Entry(frame, textvariable=var, width=30) entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True) ttk.Button(frame, text=btn_text, command=command).pack(side=tk.LEFT) def select_app(self): path = filedialog.askopenfilename(filetypes=[("Python文件", "*.py")]) if path: self.app_path.set(path) self.log(f"选择主程序: {path}") def select_static_dir(self): path = filedialog.askdirectory() if path: self.static_dir.set(path) self.log(f"选择静态目录: {path}") def select_data(self): path = filedialog.askopenfilename(filetypes=[("JSON文件", "*.json")]) if path: self.data_path.set(path) self.log(f"选择数据文件: {path}") def select_icon(self): path = filedialog.askopenfilename(filetypes=[("图标文件", "*.ico")]) if path: if self.validate_icon(path): self.icon_path.set(path) self.log(f"选择图标文件: {path}") else: messagebox.showerror("错误", "无效的ICO文件格式") def validate_icon(self, path): """验证ICO文件有效性""" try: with open(path, "rb") as f: header = f.read(4) return header == b'\x00\x00\x01\x00' except: return False def validate_inputs(self): """输入验证""" errors = [] required = [ (self.app_path, "主程序文件", os.path.isfile), (self.static_dir, "静态目录", os.path.isdir), (self.data_path, "数据文件", os.path.isfile) ] for var, name, check in required: path = var.get() if not path: errors.append(f"请选择{name}") elif not check(path): errors.append(f"{name}路径无效: {path}") if self.icon_path.get() and not os.path.isfile(self.icon_path.get()): errors.append("图标文件路径无效") return errors def start_pack(self): if self.running: return if errors := self.validate_inputs(): messagebox.showerror("输入错误", "\n".join(errors)) return self.running = True self.clear_log() self.log("开始打包进程...") threading.Thread(target=self.pack_process, daemon=True).start() def get_pyarmor_cmd(self, obf_dir, main_py): try: import pyarmor version = getattr(pyarmor, '__version__', '7.0.0') except ImportError: version = '7.0.0' if version.startswith('8') or version >= '8.0.0': # PyArmor 8.x 用 python -m pyarmor.cli obfuscate pyarmor_cmd = [ sys.executable, "-m", "pyarmor.cli", "obfuscate", "--output", obf_dir, main_py ] else: # PyArmor 7.x 直接用 pyarmor 命令行 pyarmor_cmd = [ "pyarmor", "pack", "-e", f"--dist {obf_dir}", main_py ] return pyarmor_cmd def pack_process(self): try: if self.safe_pack.get(): obf_dir = os.path.abspath(os.path.join(os.path.dirname(self.app_path.get()))) main_py = os.path.abspath(self.app_path.get()) pyarmor_cmd = self.get_pyarmor_cmd(obf_dir, main_py) self.log(f"执行PyArmor混淆: {' '.join(pyarmor_cmd)}") result = subprocess.run(pyarmor_cmd, capture_output=True, text=True) if result.stdout: self.log(result.stdout) if result.stderr: self.log(result.stderr) if result.returncode != 0: self.log("PyArmor混淆失败,请检查上方错误信息!") messagebox.showerror("PyArmor混淆失败", result.stderr or "未知错误") return # 这里要用原始文件名 py_file_to_pack = os.path.join(obf_dir, os.path.basename(main_py)) else: py_file_to_pack = self.app_path.get() cmd = [ 'pyinstaller', '--onefile', '--noconsole', '--clean', f'--add-data={self.static_dir.get()}{os.pathsep}static', f'--add-data={self.data_path.get()}{os.pathsep}.', f'--distpath={os.path.abspath("dist")}', f'--workpath={os.path.abspath("build")}' ] # 添加 eventlet 及依赖 hidden-import gevent_hidden_imports = [ '--hidden-import=gevent', '--hidden-import=gevent.monkey', '--hidden-import=geventwebsocket', '--hidden-import=geventwebsocket.handler', '--hidden-import=dns', '--hidden-import=dns.rdtypes', '--hidden-import=dns.rdtypes.ANY', '--hidden-import=dns.rdtypes.IN', '--hidden-import=dns.rdtypes.ANY.SOA', '--hidden-import=dns.rdtypes.ANY.SRV', '--hidden-import=dns.rdtypes.ANY.TXT', '--hidden-import=dns.rdtypes.ANY.NS', '--hidden-import=dns.rdtypes.ANY.CNAME', '--hidden-import=dns.rdtypes.ANY.MX', '--hidden-import=dns.rdtypes.ANY.PTR', '--hidden-import=dns.rdtypes.ANY.AAAA', '--hidden-import=dns.rdtypes.ANY.A', '--hidden-import=dns.rdtypes.IN.A', '--hidden-import=dns.rdtypes.IN.AAAA', '--hidden-import=dns.rdtypes.IN.MX', '--hidden-import=dns.rdtypes.IN.NS', '--hidden-import=dns.rdtypes.IN.PTR', '--hidden-import=dns.rdtypes.IN.SOA', '--hidden-import=dns.rdtypes.IN.SRV', '--hidden-import=dns.rdtypes.IN.TXT', '--hidden-import=dns.asyncbackend', '--hidden-import=dns.asyncquery', '--hidden-import=dns.asyncresolver', '--hidden-import=dns.e164', '--hidden-import=dns.namedict', '--hidden-import=dns.tsigkeyring', '--hidden-import=dns.zone', '--hidden-import=dns.dnssec', '--hidden-import=dns.versioned', '--hidden-import=greenlet', ] cmd.extend(gevent_hidden_imports) if self.icon_path.get(): cmd.append(f'--icon={self.icon_path.get()}') cmd.append(py_file_to_pack) self.log(f"执行命令: {' '.join(cmd)}") with subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1, universal_newlines=True ) as proc: for line in iter(proc.stdout.readline, ''): self.log(line.strip()) exit_code = proc.wait() if exit_code == 0: self.log("打包成功完成!") messagebox.showinfo("成功", "EXE文件已生成在dist目录") else: self.log(f"打包失败,错误代码: {exit_code}") messagebox.showerror("错误", f"打包失败,请检查日志\n错误代码: {exit_code}") except Exception as e: self.log(f"发生未预期的错误: {str(e)}") messagebox.showerror("系统错误", str(e)) finally: self.running = False if os.path.exists("build"): shutil.rmtree("build", ignore_errors=True) if hasattr(self, "safe_pack") and self.safe_pack.get(): obf_dir = os.path.abspath(os.path.join(os.path.dirname(self.app_path.get()), "obf_temp")) if os.path.exists(obf_dir): shutil.rmtree(obf_dir, ignore_errors=True) self.log("打包进程结束") def log(self, message): self.log_buffer.append(message) self.update_log_display() def clear_log(self): self.log_text.config(state=tk.NORMAL) self.log_text.delete(1.0, tk.END) self.log_text.config(state=tk.DISABLED) def update_log_display(self): self.log_text.config(state=tk.NORMAL) while self.log_buffer: line = self.log_buffer.pop(0) self.log_text.insert(tk.END, line + "\n") self.log_text.see(tk.END) self.log_text.config(state=tk.DISABLED) if __name__ == "__main__": root = tk.Tk() app = PackerApp(root) root.protocol("WM_DELETE_WINDOW", lambda: root.destroy()) root.mainloop()
06-08
import time import tkinter as tk from tkinter import messagebox, ttk, filedialog 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.webdriver.chrome.service import Service from selenium.webdriver.chrome.options import Options import threading import subprocess import os import tempfile import atexit import json from datetime import datetime import sqlite3 from list import RichTextTableWidget import pandas as pd import chardet import os class ListThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.daemon = True # 设置为守护线程,当主程序退出时,子线程也会退出 def run(self): # 在新线程中启动PyQt5应用 import sys from PyQt5.QtWidgets import QApplication app = QApplication(sys.argv) window = RichTextTableWidget() window.show() sys.exit(app.exec_()) class WebFormFiller: def __init__(self): self.driver = None self.chrome_process = None self.user_data_dir = None self.root = tk.Tk() self.root.title("网页表单自动填充工具") self.root.geometry("1200x800") self.root.resizable(True, True) # 数据库文件路径 self.db_file_path = "richtext_data.db" # 初始化数据库 self.init_database() # 注册退出清理函数 atexit.register(self.cleanup) # 创建主界面 self.create_widgets() def init_database(self): """初始化SQLite数据库""" try: conn = sqlite3.connect(self.db_file_path) cursor = conn.cursor() # 创建富文本数据表 cursor.execute(''' CREATE TABLE IF NOT EXISTS rich_text_items ( id INTEGER PRIMARY KEY AUTOINCREMENT, selected_state INTEGER DEFAULT 0, html_content1 TEXT, html_content2 TEXT, plain_text1 TEXT, plain_text2 TEXT, created_time DATETIME DEFAULT CURRENT_TIMESTAMP, updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ''') conn.commit() conn.close() print("数据库初始化成功") except Exception as e: print(f"数据库初始化失败: {e}") def create_widgets(self): # 创建主框架 main_frame = tk.Frame(self.root) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 标题 title_label = tk.Label(main_frame, text="网页表单自动填充工具", font=("Arial", 18, "bold")) title_label.pack(pady=10) # 创建主水平布局容器 main_container = tk.Frame(main_frame) main_container.pack(fill=tk.BOTH, expand=True) # 左侧区域 - 表单数据和配置 left_frame = tk.Frame(main_container) left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5) # 右侧区域 - 日志和浏览器设置 right_frame = tk.Frame(main_container) right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5) # ========== 左侧区域内容 ========== # URL输入区域 url_frame = tk.LabelFrame(left_frame, text="网页设置", padx=10, pady=10) url_frame.pack(fill=tk.X, pady=5) tk.Label(url_frame, text="目标网页URL:", font=("Arial", 12, "bold")).pack(anchor="w") self.url_entry = tk.Entry(url_frame, width=60) self.url_entry.pack(fill=tk.X, pady=5) self.url_entry.insert(0, "https://jira-phone.mioffice.cn") # 添加文件选择框架(垂直布局) file_frame = tk.LabelFrame(left_frame, text="文件选择", padx=10, pady=10) file_frame.pack(fill=tk.X, pady=10) # 第一个文件选择框(旧文件) file1_frame = tk.Frame(file_frame) file1_frame.pack(fill=tk.X, pady=2) tk.Label(file1_frame, text="旧版本CSV文件:", font=("Arial", 10)).pack(side=tk.LEFT, padx=(0, 5)) self.old_file_entry = tk.Entry(file1_frame, width=40) self.old_file_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5)) tk.Button(file1_frame, text="浏览", command=self.browse_old_file).pack(side=tk.LEFT) file2_frame = tk.Frame(file_frame) file2_frame.pack(fill=tk.X, pady=5) tk.Label(file2_frame, text="新版本CSV文件:", font=("Arial", 10)).pack(side=tk.LEFT, padx=(0, 5)) self.new_file_entry = tk.Entry(file2_frame, width=40) self.new_file_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5)) tk.Button(file2_frame, text="浏览", command=self.browse_new_file).pack(side=tk.LEFT) # 表单数据区域 - 水平布局 tk.Button(file2_frame, text="检索", command=self.start_compare_csv).pack(side=tk.LEFT) # 表单数据区域 - 水平布局 data_frame = tk.LabelFrame(left_frame, text="表单数据", padx=10, pady=10) data_frame.pack(fill=tk.BOTH, expand=True, pady=5) # 序列号选择区域 serial_frame = tk.Frame(data_frame) serial_frame.pack(fill=tk.X, pady=5) tk.Label(serial_frame, text="选择序列号:").pack(side=tk.LEFT, padx=5) self.serial_combo = ttk.Combobox(serial_frame, width=30, state="readonly") self.serial_combo.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True) refresh_button = tk.Button(serial_frame, text="刷新", command=self.refresh_serial_list, bg="#2196F3", fg="white", font=("Arial", 8)) refresh_button.pack(side=tk.LEFT, padx=5) # 绑定下拉框选择事件 self.serial_combo.bind('<<ComboboxSelected>>', self.on_serial_changed) # 文本插入区域 - 水平布局 text_inputs_frame = tk.Frame(data_frame) text_inputs_frame.pack(fill=tk.BOTH, expand=True, pady=5) # 文本插入1 text1_frame = tk.LabelFrame(text_inputs_frame, text="文本插入1", padx=5, pady=5) text1_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5) self.text_input1 = tk.Text(text1_frame, width=40, height=8, font=("Arial", 10)) text1_scrollbar = ttk.Scrollbar(text1_frame, orient="vertical", command=self.text_input1.yview) self.text_input1.configure(yscrollcommand=text1_scrollbar.set) self.text_input1.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) text1_scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.text_input1.insert("1.0", "这是第一个文本插入区域的内容。") # 文本插入2 text2_frame = tk.LabelFrame(text_inputs_frame, text="文本插入2", padx=5, pady=5) text2_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5) self.text_input2 = tk.Text(text2_frame, width=40, height=8, font=("Arial", 10)) text2_scrollbar = ttk.Scrollbar(text2_frame, orient="vertical", command=self.text_input2.yview) self.text_input2.configure(yscrollcommand=text2_scrollbar.set) self.text_input2.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) text2_scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.text_input2.insert("1.0", "这是第二个文本插入区域的内容。") # 配置区域 - 水平布局 config_frame = tk.Frame(left_frame) config_frame.pack(fill=tk.X, pady=5) # 字段映射配置 mapping_frame = tk.LabelFrame(config_frame, text="字段映射配置", padx=10, pady=10) mapping_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5) tk.Label(mapping_frame, text="字段映射:", font=("Arial", 9, "bold")).pack(anchor="w") # 创建字段映射表格 fields = [ ("字段1标识", "text_input1"), ("字段2标识", "text_input2") ] self.field_mappings = {} for i, (field_name, field_key) in enumerate(fields): row_frame = tk.Frame(mapping_frame) row_frame.pack(fill=tk.X, pady=2) tk.Label(row_frame, text=f"{field_name}:", width=12, anchor="w").pack(side=tk.LEFT) entry = tk.Entry(row_frame, width=20) entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True) # 设置默认的映射值 if field_key == "text_input1": entry.insert(0, "请输入内容1") else: entry.insert(0, "请输入内容2") self.field_mappings[field_key] = entry # 富文本编辑器配置 rich_text_frame = tk.LabelFrame(config_frame, text="富文本编辑器设置", padx=10, pady=10) rich_text_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5) # TinyMCE配置 tinymce_frame = tk.Frame(rich_text_frame) tinymce_frame.pack(fill=tk.X, pady=5) self.auto_detect_tinymce = tk.BooleanVar(value=True) tk.Checkbutton(tinymce_frame, text="自动识别TinyMCE编辑器", variable=self.auto_detect_tinymce, font=("Arial", 9)).pack(anchor="w") self.tinymce_content_type = tk.StringVar(value="text") content_type_frame = tk.Frame(rich_text_frame) content_type_frame.pack(fill=tk.X, pady=5) tk.Label(content_type_frame, text="内容类型:", font=("Arial", 9)).pack(side=tk.LEFT) tk.Radiobutton(content_type_frame, text="纯文本", variable=self.tinymce_content_type, value="text", font=("Arial", 8)).pack(side=tk.LEFT, padx=5) tk.Radiobutton(content_type_frame, text="HTML格式", variable=self.tinymce_content_type, value="html", font=("Arial", 8)).pack(side=tk.LEFT, padx=5) # 自定义字符检测区域 char_detection_frame = tk.LabelFrame(config_frame, text="自定义字符检测", padx=10, pady=10) char_detection_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5) # 自定义字符输入 char_input_frame = tk.Frame(char_detection_frame) char_input_frame.pack(fill=tk.X, pady=5) tk.Label(char_input_frame, text="检测字符:").pack(anchor="w") self.char_entry = tk.Entry(char_input_frame, width=30) self.char_entry.pack(fill=tk.X, pady=2) self.char_entry.insert(0, "请填写检测字符") # 默认检测字符 # 检测间隔设置 interval_frame = tk.Frame(char_detection_frame) interval_frame.pack(fill=tk.X, pady=5) tk.Label(interval_frame, text="检测间隔():").pack(side=tk.LEFT) self.interval_entry = tk.Entry(interval_frame, width=10) self.interval_entry.pack(side=tk.LEFT, padx=5) self.interval_entry.insert(0, "60") # 检测控制按钮 button_frame = tk.Frame(char_detection_frame) button_frame.pack(fill=tk.X, pady=5) self.start_detect_button = tk.Button(button_frame, text="开始检测", command=self.start_char_detection, bg="#2196F3", fg="white", font=("Arial", 9)) self.start_detect_button.pack(side=tk.LEFT, padx=2) self.stop_detect_button = tk.Button(button_frame, text="停止检测", command=self.stop_char_detection, bg="#f44336", fg="white", font=("Arial", 9)) self.stop_detect_button.pack(side=tk.LEFT, padx=2) # ========== 右侧区域内容 ========== # 检测日志区域 log_frame = tk.LabelFrame(right_frame, text="检测日志", padx=10, pady=10) log_frame.pack(fill=tk.BOTH, expand=True, pady=5) # 创建日志文本框和滚动条 self.log_text = tk.Text(log_frame, width=60, height=15, font=("Consolas", 9)) log_scrollbar = ttk.Scrollbar(log_frame, orient="vertical", command=self.log_text.yview) self.log_text.configure(yscrollcommand=log_scrollbar.set) self.log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) log_scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 清空日志按钮 clear_log_button = tk.Button(log_frame, text="清空日志", command=self.clear_log, bg="#FF9800", fg="white", font=("Arial", 9)) clear_log_button.pack(side=tk.BOTTOM, pady=5) # 调试模式选项区域 debug_frame = tk.LabelFrame(right_frame, text="浏览器设置", padx=10, pady=10) debug_frame.pack(fill=tk.X, pady=5) # 调试端口设置 port_frame = tk.Frame(debug_frame) port_frame.pack(fill=tk.X, pady=5) tk.Label(port_frame, text="调试端口:").pack(side=tk.LEFT) self.port_entry = tk.Entry(port_frame, width=10) self.port_entry.pack(side=tk.LEFT, padx=5) self.port_entry.insert(0, "9222") # 自动填写选项 auto_options_frame = tk.Frame(debug_frame) auto_options_frame.pack(fill=tk.X, pady=5) self.auto_detect_var = tk.BooleanVar(value=True) tk.Checkbutton(auto_options_frame, text="自动探测表单字段", variable=self.auto_detect_var, font=("Arial", 9)).pack(side=tk.LEFT, padx=10) self.delay_fill_var = tk.BooleanVar(value=True) tk.Checkbutton(auto_options_frame, text="延迟填充(推荐)", variable=self.delay_fill_var, font=("Arial", 9)).pack(side=tk.LEFT, padx=10) # ========== 底部按钮区域 ========== # 按钮区域 button_frame = tk.Frame(main_frame) button_frame.pack(pady=20) # 第一行按钮 button_row1 = tk.Frame(button_frame) button_row1.pack(pady=5) self.start_button = tk.Button(button_row1, text="开始自动填充", command=self.start_filling, bg="#4CAF50", fg="white", font=("Arial", 12, "bold"), width=15, height=2) self.start_button.pack(side=tk.LEFT, padx=15) self.stop_button = tk.Button(button_row1, text="停止", command=self.stop_filling, bg="#f44336", fg="white", font=("Arial", 12, "bold"), width=15, height=2) self.stop_button.pack(side=tk.LEFT, padx=15) # 第二行按钮 button_row2 = tk.Frame(button_frame) button_row2.pack(pady=5) self.launch_browser_button = tk.Button(button_row2, text="启动浏览器", command=self.launch_browser, bg="#FF9800", fg="white", font=("Arial", 10, "bold"), width=10, height=1) self.launch_browser_button.pack(side=tk.LEFT, padx=5) self.test_button = tk.Button(button_row2, text="连接浏览器", command=self.connect_browser, bg="#2196F3", fg="white", font=("Arial", 10), width=10, height=1) self.test_button.pack(side=tk.LEFT, padx=5) self.test_button = tk.Button(button_row2, text="配置文件", command=self.DK, bg="#2196F3", fg="white", font=("Arial", 10), width=10, height=1) self.test_button.pack(side=tk.LEFT, padx=5) self.test_button = tk.Button(button_row2, text="探测表单", command=self.detect_form_fields, bg="#2196F3", fg="white", font=("Arial", 10), width=10, height=1) self.test_button.pack(side=tk.LEFT, padx=5) # 状态显示 self.status_var = tk.StringVar() self.status_var.set("准备就绪") status_label = tk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W, bg="#e0e0e0", font=("Arial", 10)) status_label.pack(fill=tk.X, pady=5) # 进度条 self.progress = ttk.Progressbar(main_frame, mode='indeterminate') self.progress.pack(fill=tk.X, pady=5) # 字符检测控制变量 self.char_detection_running = False self.char_detection_timer = None # 初始化序列号列表 self.refresh_serial_list() def browse_old_file(self): file_path = filedialog.askopenfilename(filetypes=[("CSV文件", "*.csv")]) if file_path: self.old_file_entry.delete(0, tk.END) self.old_file_entry.insert(0, file_path) self.log_message(f"加载OLD CSV 数据路径:{file_path}") def browse_new_file(self): file_path = filedialog.askopenfilename(filetypes=[("CSV文件", "*.csv")]) if file_path: self.new_file_entry.delete(0, tk.END) self.new_file_entry.insert(0, file_path) self.log_message(f"加载NEW CSV 数据路径:{file_path}") def detect_encoding(self,file_path): """检测文件编码格式""" with open(file_path, 'rb') as f: result = chardet.detect(f.read(10000)) return result['encoding'] or 'gbk' def safe_read_csv(self,file_path): """安全读取CSV文件,处理编码问题""" try: encoding = self.detect_encoding(file_path) return pd.read_csv(file_path, encoding=encoding, dtype=str) except UnicodeDecodeError: # 尝试常见中文编码 for enc in ['gbk', 'gb2312', 'gb18030', 'latin1']: try: return pd.read_csv(file_path, encoding=enc, dtype=str) except: continue # 最后尝试忽略错误 return pd.read_csv(file_path, encoding='utf-8', errors='replace', dtype=str) def compare_csv(self,old_file, new_file, key_columns, update_column): """ 比较新旧CSV文件差异并导出完整结果 :param old_file: 老表路径 :param new_file: 新表路径 :param key_columns: 关键列(列表) :param update_column: 更新时间列名 """ # 安全读取文件 try: df_old = self.safe_read_csv(old_file).fillna('') df_new = self.safe_read_csv(new_file).fillna('') except Exception as e: print(f"文件读取错误: {e}") self.log_message(f"文件读取错误: {e}") return # 验证列是否存在 for col in key_columns + [update_column]: if col not in df_old.columns: self.log_message(f"错误: 列 '{col}' 在老表中不存在") return if col not in df_new.columns: self.log_message(f"错误: 列 '{col}' 在新表中不存在") return # 设置联合主键 df_old['composite_key'] = df_old[key_columns].astype(str).apply(tuple, axis=1) df_new['composite_key'] = df_new[key_columns].astype(str).apply(tuple, axis=1) # 创建字典 old_dict = dict(zip(df_old['composite_key'], df_old[update_column])) new_dict = dict(zip(df_new['composite_key'], df_new[update_column])) # 准备结果DataFrame result_df = pd.DataFrame() # 1. 查找更新的记录 (新表中存在但值不同) updated_keys = [] for key in set(new_dict.keys()) & set(old_dict.keys()): if pd.Series(old_dict[key]).equals(pd.Series(new_dict[key])) is False: updated_keys.append(key) if updated_keys: updated_records = df_new[df_new['composite_key'].isin(updated_keys)].copy() updated_records['_change_type'] = '更新' updated_records['old_update'] = updated_records['composite_key'].map(old_dict) result_df = pd.concat([result_df, updated_records]) # 2. 查找新增记录 (只存在于新表) new_keys = set(new_dict.keys()) - set(old_dict.keys()) if new_keys: new_records = df_new[df_new['composite_key'].isin(new_keys)].copy() new_records['_change_type'] = '新增' new_records['old_update'] = '' # 空值占位 result_df = pd.concat([result_df, new_records]) # 3. 查找删除的记录 (只存在于老表) deleted_keys = set(old_dict.keys()) - set(new_dict.keys()) if deleted_keys: deleted_records = df_old[df_old['composite_key'].isin(deleted_keys)].copy() deleted_records['_change_type'] = '删除' # 添加新表有但老表没有的列 for col in set(df_new.columns) - set(df_old.columns): deleted_records[col] = '' result_df = pd.concat([result_df, deleted_records]) if result_df.empty: self.log_message("没有发现差异") return # 添加变更类型列并置首 if '_change_type' in result_df.columns: cols = ['_change_type'] + [col for col in result_df.columns if col != '_change_type'] result_df = result_df[cols] # 保存结果到Excel output_file = "comparison_result.xlsx" try: # 确保包含所有新表列 for col in df_new.columns: if col not in result_df.columns: result_df[col] = '' # 保存Excel result_df.to_excel(output_file, index=False) self.log_message(f"结果已保存到: {os.path.abspath(output_file)}") except Exception as e: self.log_message(f"保存Excel失败: {e}") # 打印问题关键字列数据 if key_columns: self.log_message("问题关键字列数据:") print(result_df[key_columns].to_string(index=False)) self.log_message(f"{result_df[key_columns].to_string(index=False)}") # 打印变更统计 if not result_df.empty: change_counts = result_df['_change_type'].value_counts() self.log_message("变更统计:") for change_type, count in change_counts.items(): self.log_message(f"{change_type}: {count}条") def start_compare_csv(self): old_file = self.old_file_entry.get() new_file = self.new_file_entry.get() key_columns = ["问题关键字"] update_column = "已更新" if not all([old_file, new_file, key_columns, update_column]): messagebox.showerror("输入错误", "请填写完整的输入信息") return threading.Thread(target=self.compare_csv, args=(old_file, new_file, key_columns, update_column)).start() def refresh_serial_list(self): """从数据库刷新序列号下拉框""" self.serial_combo.set('') self.serial_combo['values'] = () try: conn = sqlite3.connect(self.db_file_path) cursor = conn.cursor() cursor.execute("SELECT id, plain_text1, plain_text2 FROM rich_text_items ORDER BY id") records = cursor.fetchall() serials = [] for record in records: record_id, text1, text2 = record preview_text = "" if text1: preview_text = text1[:30] + "..." if len(text1) > 30 else text1 elif text2: preview_text = text2[:30] + "..." if len(text2) > 30 else text2 else: preview_text = "空记录" serial_text = f"ID {record_id}: {preview_text}" serials.append(serial_text) self.serial_combo['values'] = serials self.log_message(f"已从数据库加载 {len(serials)} 个序列号") conn.close() except Exception as e: self.log_message(f"刷新序列号列表时出错: {str(e)}") def on_serial_changed(self, event): """当序列号选择改变时,从数据库加载对应的数据到文本插入框""" selected_index = self.serial_combo.current() if selected_index < 0: return try: conn = sqlite3.connect(self.db_file_path) cursor = conn.cursor() selected_text = self.serial_combo.get() record_id = int(selected_text.split(":")[0].replace("ID ", "")) cursor.execute("SELECT plain_text1, plain_text2 FROM rich_text_items WHERE id = ?", (record_id,)) record = cursor.fetchone() if record: plain_text1, plain_text2 = record self.text_input1.delete("1.0", tk.END) if plain_text1: self.text_input1.insert("1.0", plain_text1) self.text_input2.delete("1.0", tk.END) if plain_text2: self.text_input2.insert("1.0", plain_text2) self.log_message(f"已加载记录 ID {record_id} 的数据") else: self.log_message(f"未找到记录 ID {record_id}") conn.close() except Exception as e: self.log_message(f"加载序列号数据时出错: {str(e)}") def log_message(self, message): """在日志框中添加带时间戳的消息""" timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_entry = f"[{timestamp}] {message}\n" self.log_text.insert(tk.END, log_entry) self.log_text.see(tk.END) self.root.update() def clear_log(self): """清空日志""" self.log_text.delete("1.0", tk.END) self.log_message("日志已清空") def detect_custom_chars(self): """检测网页中的自定义字符""" if not self.driver: self.log_message("错误: 请先连接到浏览器") return [] try: page_text = self.driver.find_element(By.TAG_NAME, "body").text custom_chars = self.char_entry.get().strip() if not custom_chars: self.log_message("警告: 未设置检测字符") return [] chars_to_detect = [char.strip() for char in custom_chars.replace(';', ',').split(',') if char.strip()] found_chars = [] for char in chars_to_detect: if char in page_text: found_chars.append(char) return found_chars except Exception as e: self.log_message(f"检测错误: {str(e)}") return [] def start_char_detection(self): """开始定时检测自定义字符""" try: interval = int(self.interval_entry.get()) if interval <= 0: messagebox.showerror("错误", "间隔时间必须大于0") return if not self.driver: messagebox.showwarning("警告", "请先连接到浏览器") return self.char_detection_running = True self.start_detect_button.config(state=tk.DISABLED) self.stop_detect_button.config(state=tk.NORMAL) self.log_message(f"开始自定义字符检测,间隔: {interval}秒") self.log_message(f"检测字符: {self.char_entry.get()}") self._char_detection_loop() except ValueError: messagebox.showerror("错误", "请输入有效的数字") def stop_char_detection(self): """停止定时检测自定义字符""" self.char_detection_running = False if self.char_detection_timer: self.char_detection_timer.cancel() self.start_detect_button.config(state=tk.NORMAL) self.stop_detect_button.config(state=tk.DISABLED) self.log_message("已停止自定义字符检测") def _char_detection_loop(self): """定时检测自定义字符的循环""" if not self.char_detection_running: return try: interval = int(self.interval_entry.get()) found_chars = self.detect_custom_chars() if found_chars: self.log_message(f"发现匹配字符: {', '.join(found_chars)}") else: self.log_message("未检测到匹配字符") self.char_detection_timer = threading.Timer(interval, self._char_detection_loop) self.char_detection_timer.daemon = True self.char_detection_timer.start() except Exception as e: self.log_message(f"检测循环错误: {str(e)}") if self.char_detection_running: self.char_detection_timer = threading.Timer(interval, self._char_detection_loop) self.char_detection_timer.daemon = True self.char_detection_timer.start() def detect_form_fields(self): """探测网页表单字段""" self.status_var.set("正在探测表单字段...") thread = threading.Thread(target=self._detect_form_fields_thread) thread.daemon = True thread.start() def _detect_form_fields_thread(self): """在新线程中探测表单字段""" try: # 连接到调试浏览器 chrome_options = Options() port = self.port_entry.get().strip() if not port.isdigit(): messagebox.showerror("错误", "请输入有效的端口号") return chrome_options.add_experimental_option("debuggerAddress", f"127.0.0.1:{port}") service = Service() self.driver = webdriver.Chrome(service=service, options=chrome_options) self.status_var.set("已连接到浏览器,开始探测表单字段...") # 探测各种类型的表单字段 detection_results = [] # 探测输入框 inputs = self.driver.find_elements(By.TAG_NAME, "input") detection_results.append(f"找到 {len(inputs)} 个输入框") # 探测文本域 textareas = self.driver.find_elements(By.TAG_NAME, "textarea") detection_results.append(f"找到 {len(textareas)} 个文本域") # 探测下拉选择框 selects = self.driver.find_elements(By.TAG_NAME, "select") detection_results.append(f"找到 {len(selects)} 个下拉选择框") # 探测按钮 buttons = self.driver.find_elements(By.TAG_NAME, "button") detection_results.append(f"找到 {len(buttons)} 个按钮") # 探测特定属性的字段 placeholders = self.driver.find_elements(By.CSS_SELECTOR, "[placeholder]") detection_results.append(f"找到 {len(placeholders)} 个带placeholder的字段") # 探测TinyMCE富文本编辑器 tinymce_frames = self.driver.find_elements(By.CSS_SELECTOR, "iframe.tox-edit-area__iframe") detection_results.append(f"找到 {len(tinymce_frames)} 个TinyMCE富文本编辑器") # 探测其他富文本编辑器 ckeditor_frames = self.driver.find_elements(By.CSS_SELECTOR, "iframe.cke_wysiwyg_frame") detection_results.append(f"找到 {len(ckeditor_frames)} 个CKEditor编辑器") # 显示探测结果 result_text = "\n".join(detection_results) messagebox.showinfo("表单探测结果", f"探测完成:\n\n{result_text}") # 自动更新字段映射建议 self.suggest_field_mappings() except Exception as e: messagebox.showerror("探测错误", f"探测表单字段时发生错误:\n{str(e)}") finally: self.status_var.set("探测完成") def fill_tinymce_editor(self, content, frame_index=0): """填充TinyMCE富文本编辑器""" try: # 查找所有的TinyMCE编辑器iframe tinymce_frames = self.driver.find_elements(By.CSS_SELECTOR, "iframe.tox-edit-area__iframe") if not tinymce_frames: self.status_var.set("未找到TinyMCE编辑器") return False if frame_index >= len(tinymce_frames): self.status_var.set(f"TinyMCE编辑器索引 {frame_index} 超出范围") return False # 切换到指定的iframe self.driver.switch_to.frame(tinymce_frames[frame_index]) # 找到可编辑的body区域 editor_body = self.driver.find_element(By.TAG_NAME, "body") # 清空原有内容 editor_body.clear() # 根据内容类型选择填充方式 if self.tinymce_content_type.get() == "html": # 使用JavaScript设置HTML内容 js_script = f""" arguments[0].innerHTML = `{content}`; """ self.driver.execute_script(js_script, editor_body) else: # 输入纯文本 editor_body.send_keys(content) # 切换回主文档 self.driver.switch_to.default_content() self.status_var.set(f"成功填充第 {frame_index + 1} 个TinyMCE编辑器") return True except Exception as e: print(f"填充TinyMCE编辑器失败: {e}") # 确保切换回主文档 self.driver.switch_to.default_content() return False def fill_tinymce_with_javascript(self, content, frame_selector="iframe.tox-edit-area__iframe"): """使用JavaScript填充TinyMCE编辑器""" try: js_script = f""" var iframes = document.querySelectorAll('{frame_selector}'); for (var i = 0; i < iframes.length; i++) {{ try {{ var iframe = iframes[i]; var iframeDoc = iframe.contentDocument || iframe.contentWindow.document; var body = iframeDoc.querySelector('body'); if (body) {{ body.innerHTML = `{content}`; // 触发内容变化事件 var event = new Event('input', {{ bubbles: true }}); body.dispatchEvent(event); }} }} catch(e) {{ console.log('填充iframe ' + i + ' 失败: ' + e); }} }} return iframes.length; """ filled_count = self.driver.execute_script(js_script) self.status_var.set(f"使用JS成功填充 {filled_count} 个TinyMCE编辑器") return filled_count > 0 except Exception as e: print(f"使用JS填充TinyMCE失败: {e}") return False def auto_detect_and_fill_rich_text(self, form_data): """自动检测并填充富文本编辑器""" success_count = 0 # 检测TinyMCE编辑器 if self.auto_detect_tinymce.get(): tinymce_frames = self.driver.find_elements(By.CSS_SELECTOR, "iframe.tox-edit-area__iframe") if tinymce_frames: self.status_var.set(f"检测到 {len(tinymce_frames)} 个TinyMCE编辑器,正在填充...") # 使用文本插入1的内容填充第一个TinyMCE编辑器 if form_data["text_input1"]: if self.fill_tinymce_editor(form_data["text_input1"], 0): success_count += 1 time.sleep(1) # 给编辑器一些时间处理 # 如果有多个编辑器和数据,可以继续填充 if len(tinymce_frames) > 1 and form_data["text_input2"]: if self.fill_tinymce_editor(form_data["text_input2"], 1): success_count += 1 time.sleep(1) return success_count def suggest_field_mappings(self): """根据探测结果建议字段映射""" try: # 这里可以添加更智能的字段映射建议逻辑 # 例如根据placeholder文本自动匹配 messagebox.showinfo("提示", "字段映射建议功能已运行,请检查字段映射配置") except Exception as e: print(f"字段映射建议出错: {e}") def auto_fill_form(self, form_data): """自动填写表单的智能方法""" success_count = 0 # 首先尝试填充富文本编辑器 rich_text_success = self.auto_detect_and_fill_rich_text(form_data) success_count += rich_text_success # 然后填充普通表单字段 - 使用多种策略 for field_key, field_value in form_data.items(): if not field_value: continue mapping_text = self.field_mappings[field_key].get().strip() if not mapping_text: continue filled = False # 尝试多种填充策略 filled = self.fill_by_placeholder(mapping_text, field_value) if not filled: filled = self.fill_by_name(mapping_text, field_value) if not filled: filled = self.fill_by_id(mapping_text, field_value) if not filled: filled = self.fill_by_label(mapping_text, field_value) if filled: success_count += 1 if self.delay_fill_var.get(): time.sleep(0.5) # 延迟填充,避免被检测为机器人 return success_count def fill_by_placeholder(self, placeholder_text, value): """通过placeholder属性填充""" try: # 尝试input elements = self.driver.find_elements(By.CSS_SELECTOR, f"input[placeholder*='{placeholder_text}']") # 尝试textarea if not elements: elements = self.driver.find_elements(By.CSS_SELECTOR, f"textarea[placeholder*='{placeholder_text}']") for element in elements: try: element.clear() element.send_keys(value) return True except: continue except: pass return False def fill_by_name(self, name_text, value): """通过name属性填充""" try: elements = self.driver.find_elements(By.CSS_SELECTOR, f"[name*='{name_text}']") for element in elements: try: element.clear() element.send_keys(value) return True except: continue except: pass return False def fill_by_id(self, id_text, value): """通过id属性填充""" try: element = self.driver.find_element(By.ID, id_text) element.clear() element.send_keys(value) return True except: return False def fill_by_label(self, label_text, value): """通过label文本填充""" try: # 找到label元素 labels = self.driver.find_elements(By.XPATH, f"//label[contains(text(), '{label_text}')]") for label in labels: # 尝试找到关联的输入字段 field_id = label.get_attribute("for") if field_id: try: element = self.driver.find_element(By.ID, field_id) element.clear() element.send_keys(value) return True except: continue # 如果没有for属性,尝试在父级中找输入字段 parent = label.find_element(By.XPATH, "..") inputs = parent.find_elements(By.TAG_NAME, "input") textareas = parent.find_elements(By.TAG_NAME, "textarea") for element in inputs + textareas: try: element.clear() element.send_keys(value) return True except: continue except: pass return False def find_chrome_path(self): """查找Chrome浏览器的安装路径""" possible_paths = [ "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", os.path.expanduser("~\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe") ] for path in possible_paths: if os.path.exists(path): return path return None def launch_browser(self): """单独启动调试模式的Chrome浏览器""" thread = threading.Thread(target=self._launch_browser_thread) thread.daemon = True thread.start() def _launch_browser_thread(self): """在新线程中启动浏览器""" try: self.launch_browser_button.config(state=tk.DISABLED) self.status_var.set("正在启动Chrome浏览器...") self.progress.start(10) chrome_path = self.find_chrome_path() if not chrome_path: messagebox.showerror("错误", "未找到Chrome浏览器安装路径") return # 创建临时用户数据目录 self.user_data_dir = tempfile.mkdtemp(prefix="chrome_debug_") port = self.port_entry.get().strip() # 构建启动命令 cmd = [ chrome_path, f"--remote-debugging-port={port}", f"--user-data-dir={self.user_data_dir}", "--no-first-run", "--no-default-browser-check", "--start-maximized" ] # 添加URL参数(如果用户提供了) url = self.url_entry.get().strip() if url and url.startswith(('http://', 'https://')): cmd.append(url) # 启动Chrome进程 self.chrome_process = subprocess.Popen(cmd) self.status_var.set("Chrome浏览器已启动,请点击连接浏览器按钮连接浏览器调试...") # 自动连接到调试浏览器 # self._auto_connect_to_browser() except Exception as e: messagebox.showerror("错误", f"启动Chrome浏览器失败: {str(e)}") self.status_var.set(f"启动浏览器失败: {str(e)}") finally: self.progress.stop() self.launch_browser_button.config(state=tk.NORMAL) def connect_browser(self): """单独启动调试模式的Chrome浏览器""" thread = threading.Thread(target=self._auto_connect_to_browser) thread.daemon = True thread.start() def _auto_connect_to_browser(self): """自动连接到调试浏览器""" try: self.status_var.set("Chrome浏览器已启动,正在连接调试端口,请最好等待5分钟...") self.progress.start(10) port = self.port_entry.get().strip() if not port.isdigit(): messagebox.showerror("错误", "请输入有效的端口号") return # 设置Chrome选项 chrome_options = Options() chrome_options.add_experimental_option("debuggerAddress", f"127.0.0.1:{port}") # 连接到浏览器 service = Service() self.driver = webdriver.Chrome(service=service, options=chrome_options) # 获取当前页面信息 current_url = self.driver.current_url page_title = self.driver.title self.status_var.set(f"已成功连接到浏览器 - {page_title}") self.log_message(f"浏览器连接成功 - 页面: {page_title}") # 如果URL为空,则导航到目标URL if not current_url or current_url == "data:,": url = self.url_entry.get().strip() if url and url.startswith(('http://', 'https://')): self.driver.get(url) self.status_var.set(f"正在打开网页: {url}") self.log_message(f"正在打开网页: {url}") WebDriverWait(self.driver, 10).until( EC.presence_of_element_located((By.TAG_NAME, "body")) ) self.status_var.set(f"已成功打开网页: {url}") self.log_message(f"网页打开成功: {url}") messagebox.showinfo("成功", "浏览器已启动并自动连接!\n\n" f"当前页面: {page_title}\n" f"当前URL: {current_url}\n\n" "您现在可以:\n" "1. 使用'探测表单'分析页面结构\n" "2. 使用'分析页面'查看详细信息\n" "3. 点击'开始自动填充'填写表单\n" "4. 使用自定义字符检测功能") except Exception as e: messagebox.showerror("连接错误", f"自动连接浏览器失败:\n{str(e)}\n\n" "请确保:\n" "1. Chrome浏览器已正确启动\n" "2. 调试端口设置正确\n" "3. 没有其他程序占用该端口") self.status_var.set(f"连接失败: {str(e)}") self.log_message(f"浏览器连接失败: {str(e)}") finally: self.progress.stop() self.launch_browser_button.config(state=tk.NORMAL) def DK(self): self.list_thread = ListThread() self.list_thread.start() def cleanup(self): """清理资源""" self.stop_char_detection() if self.chrome_process: try: self.chrome_process.terminate() self.chrome_process.wait(timeout=5) except: try: self.chrome_process.kill() except: pass self.chrome_process = None if self.user_data_dir and os.path.exists(self.user_data_dir): try: import shutil shutil.rmtree(self.user_data_dir, ignore_errors=True) except: pass def start_filling(self): # 检查URL格式 url = self.url_entry.get().strip() if not url or not url.startswith(('http://', 'https://')): messagebox.showerror("错误", "请输入有效的URL地址(以http://或https://开头)") return # 检查是否已连接浏览器 if not self.driver: messagebox.showwarning("警告", "请先启动并连接浏览器") return self.start_button.config(state=tk.DISABLED) self.progress.start(10) self.status_var.set("自动填充模式:准备填写表单...") thread = threading.Thread(target=self.fill_form) thread.daemon = True thread.start() def stop_filling(self): if self.driver: self.driver.quit() self.driver = None if self.chrome_process: self.chrome_process.terminate() self.chrome_process = None self.progress.stop() self.start_button.config(state=tk.NORMAL) self.status_var.set("已停止") def fill_form(self): try: self.status_var.set("自动填充模式:准备填写表单...") current_url = self.driver.current_url self.status_var.set(f"自动填充模式:当前页面 - {current_url}") # 如果URL为空,则导航到目标URL if not current_url or current_url == "data:,": url = self.url_entry.get().strip() if url and url.startswith(('http://', 'https://')): self.driver.get(url) self.status_var.set(f"自动填充模式:正在打开网页: {url}") WebDriverWait(self.driver, 10).until( EC.presence_of_element_located((By.TAG_NAME, "body")) ) # 获取表单数据 form_data = { "text_input1": self.text_input1.get("1.0", tk.END).strip(), "text_input2": self.text_input2.get("1.0", tk.END).strip() } self.status_var.set("开始自动填充表单...") # 使用智能自动填充方法(现在包含富文本编辑器支持) success_count = self.auto_fill_form(form_data) if success_count > 0: self.status_var.set(f"自动填充完成!成功填充 {success_count} 个字段") self.log_message(f"自动填充完成!成功填充 {success_count} 个字段") messagebox.showinfo("完成", f"自动填充完成!成功填充 {success_count} 个字段") else: self.status_var.set("自动填充失败,请检查字段映射和填写策略") self.log_message("自动填充失败,请检查字段映射和填写策略") messagebox.showwarning("警告", "未能成功填充任何字段,请检查字段映射配置和填写策略") except Exception as e: self.status_var.set(f"发生错误: {str(e)}") self.log_message(f"自动填充错误: {str(e)}") messagebox.showerror("错误", f"自动填充表单时发生错误:\n{str(e)}") finally: self.progress.stop() self.start_button.config(state=tk.NORMAL) # def run(self): # self.root.mainloop() # if __name__ == "__main__": # app = WebFormFiller() # app.run() 这个界面对数据库的读取也改成上面的数据库结构,下拉框改成模糊搜索Case ID来选择内容
11-27
import tkinter as tk from tkinter import messagebox import subprocess import tkinter.filedialog as filedialog import sys import os import tkinter.messagebox as messagebox # 创建主窗口 root = tk.Tk() root.title("主动温控日志") root.geometry("600x600") # 设置窗口大小 # 配置网格布局权重 root.columnconfigure(0, weight=1) # 使列0可扩展 # 文件路径标签和输入框 - 使用grid布局 tk.Label(root, text="路径:", font=("微软雅黑", 10), anchor="w").grid( row=0, column=0, padx=20, pady=(20, 5), sticky="w" ) entry = tk.Entry(root, width=80, font=("Consolas", 10)) entry.grid(row=1, column=0, padx=20, pady=(0, 20), sticky="ew") entry.insert(0, r"C:\Users\LWX1147523\Desktop\暂存\Datalog_20251106_16.log") # 设置默认路径 # 创建文件路径输入框和浏览按钮的容器 file_frame = tk.Frame(root) file_frame.grid(row=3, column=0, padx=20, pady=(10, 20), sticky="ew") file_frame.columnconfigure(0, weight=1) # 输入框列可扩展 # 添加浏览文件按钮 def browse_file(): """打开文件选择对话框""" file_path1 = filedialog.askopenfilename( title="选择日志文件", filetypes=(("日志文件", "*.log"), ("所有文件", "*.*")), initialdir=r"C:\Users\lWX1147523\Desktop\暂存" # 默认打开位置 ) file_path1 = os.path.normpath(file_path1) if file_path1: entry.delete(0, tk.END) entry.insert(0, file_path1) browse_file_button = tk.Button( file_frame, text="选择文件", command=browse_file, font=("微软雅黑", 9), width=8 ) browse_file_button.grid(row=0, column=1, padx=(5, 0), sticky="e") # 温控器通道选择 - 使用grid布局 tk.Label(root, text="选择温控器通道:", font=("微软雅黑", 10), anchor="w").grid( row=2, column=0, padx=20, pady=(10, 5), sticky="w" ) # 创建单选按钮组变量 var_lang = tk.StringVar(value="Ctrl_3") # 默认选择Ctrl_3 # 单选按钮列表 languages = [ ("Ctrl_3", "Ctrl_3"), ("Ctrl_1", "Ctrl_1"), ("Ctrl_2", "Ctrl_2"), ("Ctrl_4", "Ctrl_4"), ("Ctrl_5", "Ctrl_5"), ("Ctrl_6", "Ctrl_6"), ("Ctrl_7", "Ctrl_7"), ("Ctrl_8", "Ctrl_8") ] # 使用grid布局创建单选按钮 for i, (text, value) in enumerate(languages): tk.Radiobutton( root, text=text, variable=var_lang, value=value, font=("微软雅黑", 9), anchor="w" ).grid( row=2 + i, column=3, padx=45, pady=(0,3), sticky="w" ) # 创建图表类型单选按钮组变量 var_chart_type = tk.StringVar(value="pressure_valve") # 默认选择压力和阀门 # 图表类型单选按钮列表 chart_types = [ ("压力和阀门", "pressure_valve"), ("温度和阀门", "temperature_valve") ] # 创建图表类型单选按钮 for i, (text, value) in enumerate(chart_types): rb = tk.Radiobutton( root, text=text, variable=var_chart_type, value=value, font=("微软雅黑", 9), ).grid( row=9 + i, column=0, padx=45, pady=(0, 5), sticky="w" ) def get_resource_path(relative_path): """ 获取资源路径(兼容开发环境和打包环境) """ try: # 打包后的资源路径 base_path = sys._MEIPASS except AttributeError: # 开发环境路径 base_path = os.path.abspath(".") return os.path.join(base_path, relative_path) # 分析按钮 - 使用grid布局 def run_test4(): """获取输入框内容并传递给test4.py""" file_path = entry.get() selected_channel = var_lang.get() # 获取当前选择的通道值 # 路径格式转换(确保兼容性) normalized_path = file_path.replace("\\", "/") # 调用test4.py并传递路径参数 try: # result = subprocess.run( # ["python", "test4.py", normalized_path, selected_channel], # capture_output=True, # text=True, # check=True # ) # 动态获取test4.py路径 test4_path = get_resource_path("test4.py") # 调用test4.py(兼容打包环境) result = subprocess.run( [sys.executable, test4_path, normalized_path, selected_channel], capture_output=True, text=True, encoding='utf-8', # 显式指定编码 check=True ) except FileNotFoundError: messagebox.showerror("脚本错误", "找不到test4.py文件") except subprocess.CalledProcessError as e: messagebox.showerror("执行错误", f"错误信息:\n{e.stderr}") # 分析按钮 - 使用grid布局 def run_oldadvance(): """获取输入框内容并传递给test4.py""" file_path = entry.get() selected_channel = var_lang.get() # 获取当前选择的通道值 # 路径格式转换(确保兼容性) normalized_path = file_path.replace("\\", "/") # 调用test4.py并传递路径参数 try: result = subprocess.run( ["python", "oldadvance.py", normalized_path, selected_channel], capture_output=True, text=True, check=True ) # messagebox.showinfo( # "执行结果", # f"文件读取成功!\n" # f"▸ 选择的通道: {selected_channel}\n" # f"▸ 输出结果:\n{result.stdout}" # ) except FileNotFoundError: messagebox.showerror("脚本错误", "找不到test4.py文件") except subprocess.CalledProcessError as e: messagebox.showerror("执行错误", f"错误信息:\n{e.stderr}") # 分析按钮 - 使用grid布局 def run_test7(): """获取输入框内容并传递给test4.py""" file_path = entry.get() selected_channel = var_lang.get() # 获取当前选择的通道值 # 路径格式转换(确保兼容性) normalized_path = file_path.replace("\\", "/") # 调用test4.py并传递路径参数 try: result = subprocess.run( ["python", "MHTEMP.py", normalized_path, selected_channel], capture_output=True, text=True, check=True ) # messagebox.showinfo( # "执行结果", # f"文件读取成功!\n" # f"▸ 选择的通道: {selected_channel}\n" # f"▸ 输出结果:\n{result.stdout}" # ) except FileNotFoundError: messagebox.showerror("脚本错误", "找不到test7.py文件") except subprocess.CalledProcessError as e: messagebox.showerror("执行错误", f"错误信息:\n{e.stderr}") # 分析按钮 - 使用grid布局 def run_Chiller(): """获取输入框内容并传递给test4.py""" file_path = entry.get() selected_channel = var_chart_type.get() # 获取当前选择的通道值 print(selected_channel) if selected_channel == "pressure_valve": runchillerpy = "test10.py" else: runchillerpy = "TEST11.py" # 路径格式转换(确保兼容性) normalized_path = file_path.replace("\\", "/") # 调用test4.py并传递路径参数 try: result = subprocess.run( ["python", runchillerpy, normalized_path], capture_output=True, text=True, encoding='utf-8', # 显式指定UTF-8编码 errors='replace', # 替换无法解码的字符 check=True ) # messagebox.showinfo( # "执行结果", # f"文件读取成功!\n" # f"▸ 选择的通道: {selected_channel}\n" # f"▸ 输出结果:\n{result.stdout}" # ) except FileNotFoundError: messagebox.showerror("脚本错误", "找不到test7.py文件") except subprocess.CalledProcessError as e: messagebox.showerror("执行错误", f"错误信息:\n{e.stderr}") # 按钮容器 button_frame = tk.Frame(root) button_frame.grid(row=7, column=0, pady=(20, 10)) # 运行按钮 run_button = tk.Button( button_frame, text="新版本主动温控", command=run_test4, bg="#4CAF50", fg="white", font=("微软雅黑", 12), width=15 ) run_button.grid(row=0, column=0, padx=(0, 10)) # 旧版本主动温控 buttonoldadvance_frame = tk.Frame(root) buttonoldadvance_frame.grid(row=11, column=0, pady=(0,10)) runoldadvancebutton = tk.Button( buttonoldadvance_frame, text="旧版本主动温控", command=run_oldadvance, bg="#4CAF50", fg="white", font=("微软雅黑", 12), width=15 ) runoldadvancebutton.grid(row=0, column=0, padx=(0, 10)) # 运行mH按钮 buttonMH_frame = tk.Frame(root) buttonMH_frame.grid(row=8, column=0, pady=(10,0)) runMH_button = tk.Button( buttonMH_frame, text="MH温控器数据", command=run_test7, bg="#4CAF50", fg="white", font=("微软雅黑", 12), width=15 ) runMH_button.grid(row=0, column=0, padx=(0, 10)) # 运行mH冷媒机压力和阀门按钮 buttonChillerForce_frame = tk.Frame(root) buttonChillerForce_frame.grid(row=9, column=0, pady=(10,0)) runMChillerForce_button = tk.Button( buttonChillerForce_frame, text="Chiller数据", command=run_Chiller, bg="#4CAF50", fg="white", font=("微软雅黑", 12), width=15 ) runMChillerForce_button.grid(row=0, column=0, padx=(0, 10)) # 退出按钮 exit_button = tk.Button( button_frame, text="退出程序", command=root.destroy, bg="#F44336", fg="white", font=("微软雅黑", 12), width=10 ) exit_button.grid(row=0, column=1) # 状态栏 # status_bar = tk.Label( # root, # text="就绪 | 选择文件路径和通道后点击'分析数据'", # bd=1, # relief=tk.SUNKEN, # anchor=tk.W, # font=("微软雅黑", 9), # bg="#e0e0e0" # ) # status_bar.grid(row=8, column=0, sticky="ew", padx=0, pady=(20, 0)) # 启动主循环 root.mainloop() 打包gui.py
12-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值