惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - *感悟人生*

PDFtoEXCEL批量处理高保真同步格式 JS 逆向与前端安全加固实战指南 批量处理苹果电脑的HEIF格式转成JPG|PNG 邮件群发系统 注册授权--续 独立授权模块 --可以为你的程序或者工具加上一把锁 音频转换合并切割工具 修改文件重命名(1、默认去掉预览和备份,2、默认当前文件路径) AI 平台 SQL语句解析 扣代码中,遇到this 应该怎么处理 AST解OB混淆,适用大部分的混淆 Akamai的形成与风控分析:聚焦Akamai 3.0 执行py3o的重启脚本(包含手动执行,以及自动执行的脚本) reduce与map+filter的复杂计算场景 py3o中汇总的计算:sum reduce map 三种形式来处理对比 py3o中数字金额转大写 加密解密基本概念 uv 在 Python 开发中的常用命令详解 表单和载荷的区别,以及python和js在处理json时的空格问题。 R函数处理异步迭代,在爬虫中的作用。
MJ提示词自动批处理GUI版
*感悟人生* · 2025-05-28 · via 博客园 - *感悟人生*
import tkinter as tk
from tkinter import filedialog, ttk, messagebox
from DrissionPage import ChromiumPage, ChromiumOptions
import pandas as pd
import time
import os
import json
from DrissionPage.common import Keys
from threading import Thread
import random


class MJInputApp:
    def __init__(self, root):
        self.root = root
        self.root.title("MidJourney 提示词输入工具")
        self.root.geometry("600x500")
        self.root.resizable(True, True)

        # 默认配置
        self.config = {
            "chrome_path": r"C:\Users\Administrator\AppData\Local\Google\Chrome\Bin\chrome.exe",
            "debugger_address": "127.0.0.1:9222",
            "excel_path": "data.xlsx",
            "min_wait": 3.5,
            "max_wait": 5.5
        }

        # 尝试加载配置文件
        self.load_config()

        # 创建主框架
        self.main_frame = ttk.Frame(root, padding="10")
        self.main_frame.pack(fill=tk.BOTH, expand=True)

        # 创建浏览器配置指南按钮(醒目的红色按钮)
        self.create_browser_guide_button()

        # 创建设置区域
        self.create_settings_frame()

        # 创建日志区域
        self.create_log_frame()

        # 创建按钮区域
        self.create_button_frame()

        # 运行状态
        self.running = False
        self.thread = None

    def create_browser_guide_button(self):
        """创建一个醒目的浏览器配置指南按钮"""
        guide_frame = ttk.Frame(self.main_frame)
        guide_frame.pack(fill=tk.X, pady=5)
        
        # 使用原生tk按钮代替ttk按钮,确保可以设置颜色
        guide_button = tk.Button(
            guide_frame, 
            text="⚠️ 浏览器配置指南(点击查看) ⚠️", 
            command=self.show_browser_guide,
            bg="red",  # 背景色设为红色
            fg="white",  # 文字设为白色
            font=("Arial", 12, "bold"),
            relief=tk.RAISED,  # 凸起的按钮效果
            bd=3,  # 边框宽度
            padx=10,
            pady=5,
            cursor="hand2"  # 鼠标悬停时显示手型指针
        )
        guide_button.pack(fill=tk.X, pady=5)

    def show_browser_guide(self):
        """显示浏览器配置指南弹窗"""
        guide_window = tk.Toplevel(self.root)
        guide_window.title("Chrome浏览器配置指南")
        guide_window.geometry("600x400")
        guide_window.grab_set()  # 模态窗口
        
        # 添加滚动条
        frame = ttk.Frame(guide_window)
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        scrollbar = ttk.Scrollbar(frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 使用Text控件显示配置指南
        text = tk.Text(frame, wrap=tk.WORD, yscrollcommand=scrollbar.set)
        text.pack(fill=tk.BOTH, expand=True)
        scrollbar.config(command=text.yview)
        
        # 设置文本样式
        text.tag_configure("title", font=("Arial", 14, "bold"), foreground="blue")
        text.tag_configure("subtitle", font=("Arial", 12, "bold"), foreground="dark blue")
        text.tag_configure("normal", font=("Arial", 11))
        text.tag_configure("code", font=("Courier New", 10), background="#f0f0f0")
        text.tag_configure("important", font=("Arial", 11, "bold"), foreground="red")
        
        # 添加配置指南内容
        text.insert(tk.END, "Chrome浏览器配置指南\n\n", "title")
        
        text.insert(tk.END, "步骤 1: 关闭所有Chrome浏览器\n", "subtitle")
        text.insert(tk.END, "在开始之前,请确保关闭所有已经运行的Chrome浏览器窗口。\n\n", "normal")
        
        text.insert(tk.END, "步骤 2: 以调试模式启动Chrome\n", "subtitle")
        text.insert(tk.END, "打开命令提示符(cmd)或PowerShell,输入以下命令:\n", "normal")
        
        cmd = '"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" --remote-debugging-port=9222 --user-data-dir="C:\\ChromeDebug"'
        text.insert(tk.END, f"{cmd}\n\n", "code")
        
        text.insert(tk.END, "注意:请将上面的Chrome路径替换为你电脑上的实际Chrome安装路径。\n", "important")
        text.insert(tk.END, "路径中如果有空格,需要用引号括起来。\n\n", "normal")
        
        text.insert(tk.END, "步骤 3: 打开MidJourney网页\n", "subtitle")
        text.insert(tk.END, "在调试模式启动的Chrome浏览器中:\n", "normal")
        text.insert(tk.END, "1. 登录你的MidJourney账号\n", "normal")
        text.insert(tk.END, "2. 打开MidJourney的web界面\n", "normal")
        text.insert(tk.END, "3. 确保页面上有可输入提示词的输入框\n\n", "normal")
        
        text.insert(tk.END, "步骤 4: 配置本工具\n", "subtitle")
        text.insert(tk.END, "回到本工具,设置以下内容:\n", "normal")
        text.insert(tk.END, "- Chrome路径:选择你的Chrome浏览器可执行文件路径\n", "normal")
        text.insert(tk.END, "- 调试地址:通常保持默认值 127.0.0.1:9222\n", "normal")
        text.insert(tk.END, "- Excel文件:选择包含提示词的Excel文件\n\n", "normal")
        
        text.insert(tk.END, "重要提示\n", "subtitle")
        text.insert(tk.END, "如果连接失败,请检查:\n", "normal")
        text.insert(tk.END, "1. Chrome是否确实以调试模式启动\n", "normal")
        text.insert(tk.END, "2. 调试地址是否正确\n", "normal")
        text.insert(tk.END, "3. 防火墙是否阻止了连接\n", "normal")
        
        # 复制命令按钮
        def copy_command():
            self.root.clipboard_clear()
            self.root.clipboard_append(cmd)
            messagebox.showinfo("成功", "命令已复制到剪贴板")
        
        copy_btn = ttk.Button(guide_window, text="复制启动命令", command=copy_command)
        copy_btn.pack(pady=10)
        
        # 设置文本为只读
        text.config(state=tk.DISABLED)

    def create_settings_frame(self):
        settings_frame = ttk.LabelFrame(self.main_frame, text="设置", padding="10")
        settings_frame.pack(fill=tk.X, pady=5)

        # Chrome路径设置
        chrome_frame = ttk.Frame(settings_frame)
        chrome_frame.pack(fill=tk.X, pady=5)

        ttk.Label(chrome_frame, text="Chrome路径:").pack(side=tk.LEFT)
        self.chrome_path_var = tk.StringVar(value=self.config["chrome_path"])
        chrome_entry = ttk.Entry(chrome_frame, textvariable=self.chrome_path_var, width=50)
        chrome_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)

        chrome_btn = ttk.Button(chrome_frame, text="浏览...", command=self.browse_chrome)
        chrome_btn.pack(side=tk.LEFT)

        # 调试地址设置
        debug_frame = ttk.Frame(settings_frame)
        debug_frame.pack(fill=tk.X, pady=5)

        ttk.Label(debug_frame, text="调试地址:").pack(side=tk.LEFT)
        self.debug_addr_var = tk.StringVar(value=self.config["debugger_address"])
        debug_entry = ttk.Entry(debug_frame, textvariable=self.debug_addr_var)
        debug_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)

        # Excel文件路径设置
        excel_frame = ttk.Frame(settings_frame)
        excel_frame.pack(fill=tk.X, pady=5)

        ttk.Label(excel_frame, text="Excel文件:").pack(side=tk.LEFT)
        self.excel_path_var = tk.StringVar(value=self.config["excel_path"])
        excel_entry = ttk.Entry(excel_frame, textvariable=self.excel_path_var, width=50)
        excel_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)

        excel_btn = ttk.Button(excel_frame, text="浏览...", command=self.browse_excel)
        excel_btn.pack(side=tk.LEFT)

        # 等待时间设置
        wait_frame = ttk.Frame(settings_frame)
        wait_frame.pack(fill=tk.X, pady=5)

        ttk.Label(wait_frame, text="等待时间范围(秒):").pack(side=tk.LEFT)

        self.min_wait_var = tk.StringVar(value=str(self.config["min_wait"]))
        min_wait_entry = ttk.Entry(wait_frame, textvariable=self.min_wait_var, width=5)
        min_wait_entry.pack(side=tk.LEFT, padx=5)

        ttk.Label(wait_frame, text="").pack(side=tk.LEFT)

        self.max_wait_var = tk.StringVar(value=str(self.config["max_wait"]))
        max_wait_entry = ttk.Entry(wait_frame, textvariable=self.max_wait_var, width=5)
        max_wait_entry.pack(side=tk.LEFT, padx=5)

    def create_log_frame(self):
        log_frame = ttk.LabelFrame(self.main_frame, text="运行日志", padding="10")
        log_frame.pack(fill=tk.BOTH, expand=True, pady=5)

        # 创建日志文本框和滚动条
        self.log_text = tk.Text(log_frame, height=10, wrap=tk.WORD)
        scrollbar = ttk.Scrollbar(log_frame, command=self.log_text.yview)
        self.log_text.configure(yscrollcommand=scrollbar.set)

        self.log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # 进度条
        self.progress_frame = ttk.Frame(log_frame)
        self.progress_frame.pack(fill=tk.X, pady=5)

        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(self.progress_frame, variable=self.progress_var, maximum=100)
        self.progress_bar.pack(fill=tk.X)

        self.progress_label = ttk.Label(self.progress_frame, text="0/0")
        self.progress_label.pack(pady=2)

    def create_button_frame(self):
        button_frame = ttk.Frame(self.main_frame)
        button_frame.pack(fill=tk.X, pady=10)

        self.start_button = ttk.Button(button_frame, text="开始运行", command=self.start_process)
        self.start_button.pack(side=tk.LEFT, padx=5)

        self.stop_button = ttk.Button(button_frame, text="停止运行", command=self.stop_process, state=tk.DISABLED)
        self.stop_button.pack(side=tk.LEFT, padx=5)

        save_config_btn = ttk.Button(button_frame, text="保存配置", command=self.save_config)
        save_config_btn.pack(side=tk.RIGHT, padx=5)

    def browse_chrome(self):
        file_path = filedialog.askopenfilename(
            title="选择Chrome浏览器可执行文件",
            filetypes=[("可执行文件", "*.exe")]
        )
        if file_path:
            self.chrome_path_var.set(file_path)

    def browse_excel(self):
        file_path = filedialog.askopenfilename(
            title="选择Excel文件",
            filetypes=[("Excel文件", "*.xlsx *.xls")]
        )
        if file_path:
            self.excel_path_var.set(file_path)

    def log(self, message):
        self.log_text.insert(tk.END, f"{message}\n")
        self.log_text.see(tk.END)
        self.root.update_idletasks()

    def update_progress(self, current, total):
        if total > 0:
            self.progress_var.set((current / total) * 100)
            self.progress_label.config(text=f"{current}/{total}")
            self.root.update_idletasks()

    def save_config(self):
        try:
            self.config["chrome_path"] = self.chrome_path_var.get()
            self.config["debugger_address"] = self.debug_addr_var.get()
            self.config["excel_path"] = self.excel_path_var.get()
            self.config["min_wait"] = float(self.min_wait_var.get())
            self.config["max_wait"] = float(self.max_wait_var.get())

            with open("mj_input_config.json", "w", encoding="utf-8") as f:
                json.dump(self.config, f, indent=4, ensure_ascii=False)

            messagebox.showinfo("成功", "配置已保存")
        except Exception as e:
            messagebox.showerror("错误", f"保存配置失败: {str(e)}")

    def load_config(self):
        try:
            if os.path.exists("mj_input_config.json"):
                with open("mj_input_config.json", "r", encoding="utf-8") as f:
                    loaded_config = json.load(f)
                    # 更新配置,保留默认值
                    for key in loaded_config:
                        if key in self.config:
                            self.config[key] = loaded_config[key]
        except Exception as e:
            print(f"加载配置失败: {str(e)}")

    def start_process(self):
        if self.running:
            return

        # 保存当前配置
        self.save_config()

        # 检查Excel文件是否存在
        excel_path = self.excel_path_var.get()
        if not os.path.exists(excel_path):
            messagebox.showerror("错误", f"Excel文件不存在: {excel_path}")
            return

        # 检查Chrome路径是否存在
        chrome_path = self.chrome_path_var.get()
        if not os.path.exists(chrome_path):
            messagebox.showerror("错误", f"Chrome浏览器路径不存在: {chrome_path}")
            return

        # 更新UI状态
        self.start_button.config(state=tk.DISABLED)
        self.stop_button.config(state=tk.NORMAL)
        self.running = True

        # 清空日志
        self.log_text.delete(1.0, tk.END)

        # 启动处理线程
        self.thread = Thread(target=self.process_excel)
        self.thread.daemon = True
        self.thread.start()

    def stop_process(self):
        if not self.running:
            return

        self.running = False
        self.log("正在停止处理...")

        # 更新UI状态
        self.stop_button.config(state=tk.DISABLED)
        self.start_button.config(state=tk.NORMAL)

    def process_excel(self):
        try:
            # 获取配置
            chrome_path = self.chrome_path_var.get()
            debugger_address = self.debug_addr_var.get()
            excel_path = self.excel_path_var.get()
            min_wait = float(self.min_wait_var.get())
            max_wait = float(self.max_wait_var.get())

            self.log(f"开始处理Excel文件: {excel_path}")
            self.log(f"Chrome路径: {chrome_path}")
            self.log(f"调试地址: {debugger_address}")

            # 初始化浏览器
            try:
                options = ChromiumOptions()
                options.binary_location = chrome_path
                options.debugger_address = debugger_address
                page = ChromiumPage(options)
                self.log("浏览器初始化成功")
            except Exception as e:
                self.log(f"浏览器初始化失败: {str(e)}")
                messagebox.showerror("错误", f"浏览器初始化失败: {str(e)}")
                self.stop_process()
                return

            # 等待输入框加载
            try:
                self.log("等待页面输入框加载...")
                page.wait.eles_loaded('#desktop_input_bar', timeout=10)
                self.log("输入框加载成功")
            except Exception as e:
                self.log(f"等待输入框超时: {str(e)}")
                messagebox.showerror("错误", "等待输入框超时,请确保页面已正确加载")
                self.stop_process()
                return

            # 读取Excel文件
            try:
                df = pd.read_excel(excel_path, header=None)
                total_rows = len(df)
                self.log(f"成功读取Excel文件,共{total_rows}行数据")
                self.update_progress(0, total_rows)
            except Exception as e:
                self.log(f"读取Excel文件失败: {str(e)}")
                messagebox.showerror("错误", f"读取Excel文件失败: {str(e)}")
                self.stop_process()
                return

            # 处理每一行
            processed = 0
            for idx, row in df.iterrows():
                if not self.running:
                    self.log("用户停止了处理")
                    break

                # 检查第一列是否为空
                if pd.isna(row[0]):
                    self.log(f"第{idx + 1}行第一列为空,跳过")
                    processed += 1
                    self.update_progress(processed, total_rows)
                    continue

                try:
                    # 获取输入框元素
                    input_element = page.ele('#desktop_input_bar')
                    if input_element:
                        input_element.clear()
                        prompt_text = str(row[0])  # 取第一列的值
                        input_element.input(prompt_text)
                        time.sleep(1)  # 短暂等待输入完成
                        page.actions.key_down('ENTER')

                        self.log(f"已处理第 {idx + 1} 条提示词: {prompt_text}")
                    else:
                        self.log(f"输入框不存在,跳过第 {idx + 1} 条数据")
                except Exception as e:
                    self.log(f"处理第 {idx + 1} 行时出错: {str(e)}")

                # 更新进度
                processed += 1
                self.update_progress(processed, total_rows)

                # 随机等待时间
                wait_time = random.uniform(min_wait, max_wait)
                self.log(f"等待 {wait_time:.2f} 秒...")

                # 分段等待,以便能够响应停止请求
                wait_segments = int(wait_time * 10)  # 每0.1秒检查一次
                for _ in range(wait_segments):
                    if not self.running:
                        break
                    time.sleep(0.1)

            if self.running:
                self.log("所有提示词处理完成!")
                messagebox.showinfo("完成", "所有提示词处理完成!")

        except Exception as e:
            self.log(f"处理过程中发生错误: {str(e)}")
            messagebox.showerror("错误", f"处理过程中发生错误: {str(e)}")
        finally:
            # 恢复UI状态
            self.running = False
            self.root.after(0, lambda: self.start_button.config(state=tk.NORMAL))
            self.root.after(0, lambda: self.stop_button.config(state=tk.DISABLED))


# 主程序入口
if __name__ == "__main__":
    root = tk.Tk()
    app = MJInputApp(root)
    root.mainloop()