python 编写的各种常用工具【持续优化ing】

因需要用到工具且偶尔会出现电脑没网的情况,则自己想写一个工具,方便调试,也是学习下python,代码写的比较赘余
主要分为以下六类工具。

1.主界面如下所示:

在这里插入图片描述

主界面代码如下:

#main.py
import tkinter as tk
from tkinter import ttk
from crc_tool import open_crc_tool
from file_to_hex import open_file_to_hex
from conversion_tool import create_number_conversion_tool
from base64_tool import base64_encode_decode_tool
from timestamp_tool import timestamp_convert_tool
from json_tool import json_parse_tool
from picture_tool import picture_download_tool

root = tk.Tk()
root.title("常用工具")
root.geometry("250x350")
root.resizable(False, False)  # 禁止调整窗口大小

crc_button = ttk.Button(root, text="CRC计算工具", command=open_crc_tool)
crc_button.pack(pady=10)

file_to_hex_button = ttk.Button(root, text="文件转Hex字符串", command=open_file_to_hex)
file_to_hex_button.pack(pady=10)

conversion_button = ttk.Button(root, text="进制转换工具", command=create_number_conversion_tool)
conversion_button.pack(pady=10)

base64_button = ttk.Button(root, text="Base64编码/解码", command=base64_encode_decode_tool)
base64_button.pack(pady=10)

timestamp_button = ttk.Button(root, text="时间戳转换工具", command=timestamp_convert_tool)
timestamp_button.pack(pady=10)

timestamp_button = ttk.Button(root, text="json解析工具", command=json_parse_tool)
timestamp_button.pack(pady=10)

picture_download_button = ttk.Button(root, text="图片批量下载工具", command=picture_download_tool)
picture_download_button.pack(pady=10)


root.mainloop()


主要分为七大类工具。

2.CRC计算工具的界面如下所示:

在这里插入图片描述

这里只添加了自己常用的四种crc计算方式,如自己有需要,则可将其他类crc算法添加,相关代码如下:

import tkinter as tk
from tkinter import messagebox, ttk, filedialog
import binascii
import threading
import os

def calculate_crc32(input_text, is_hex):
    if is_hex:
        input_data = input_text.replace(" ", "").replace("\n", "")
        # 更新输入数据长度
        input_length_label_var.set(f"数据长度: {len(input_data)}")
        if len(input_data) % 2 != 0:
            messagebox.showerror("错误", "输入数据长度必须为偶数!")
            return
        if not is_hex_string(input_data):
            messagebox.showerror("错误", "请输入有效的十六进制字符串!")
            return
        data = bytes.fromhex(input_data)
    else:
        # 更新输入数据长度
        input_length_label_var.set(f"数据长度: {len(input_text)}")
        data = input_text.encode()
    
    crc = binascii.crc32(data) & 0xFFFFFFFF  # 使用binascii库计算CRC32值
    crc_output = f"CRC32: {crc:08X}"
    result_label.config(text=crc_output)

def calculate_crc32_file(input_data):
    crc = binascii.crc32(input_data) & 0xFFFFFFFF  # 使用binascii库计算CRC32值
    crc_output = f"CRC32: {crc:08X}"
    result_label.config(text=crc_output)

# CRC-16-MODBUS
def calculate_crc16_modbus(data):
    crc = 0xFFFF
    for byte in data:
        crc ^= byte
        for _ in range(8):
            if crc & 0x0001:
                crc = (crc >> 1) ^ 0xA001
            else:
                crc = crc >> 1
    return crc

def calculate_crc16_xmodem(data):
    crc = 0
    for byte in data:
        crc = crc ^ (byte << 8)
        for _ in range(8):
            if crc & 0x8000:
                crc = (crc << 1) ^ 0x1021
            else:
                crc <<= 1
            crc &= 0xFFFF
    return crc

def calculate_crc16_ccitt_false(data):
    crc = 0xFFFF
    for byte in data:
        crc ^= byte << 8
        for _ in range(8):
            if crc & 0x8000:
                crc = (crc << 1) ^ 0x1021
            else:
                crc <<= 1
            crc &= 0xFFFF
    return crc

def is_hex_string(s):
    try:
        int(s, 16)
        return True
    except ValueError:
        return False

def calculate_crc16(input_text, is_hex):
    algorithm = algorithm_combobox.get()
    if is_hex:
        input_data = input_text.replace(" ", "").replace("\n", "")
        # 更新输入数据长度
        input_length_label_var.set(f"数据长度: {len(input_data)}")
        if len(input_data) % 2 != 0:
            messagebox.showerror("错误", "输入数据长度必须为偶数!")
            return
        if not is_hex_string(input_data):
            messagebox.showerror("错误", "请输入有效的十六进制字符串!")
            return
        data = bytes.fromhex(input_data)
    else:
        # 更新输入数据长度
        input_length_label_var.set(f"数据长度: {len(input_text)}")
        data = input_text.encode()
    
    if algorithm == "CRC-16/MODBUS (x16+x15+x2+1)":
        crc = calculate_crc16_modbus(data)
    elif algorithm == "CRC-16/CCITT-FALSE (x16+x12+x5+1)":
        crc = calculate_crc16_ccitt_false(data)
    elif algorithm == "CRC-16/XMODEM (x16+x12+x5+1)":
        crc = calculate_crc16_xmodem(data)
    else:
        crc = "Unknown Algorithm"

    crc_output = f"{algorithm}: {crc:04X}"
    result_label.config(text=crc_output)


def calculate_crc16_from_file(file_path):
    with open(file_path, 'rb') as file:
        file_content = file.read()

        # 检查文件内容是否为十六进制字符串,如果不是,则转换为十六进制字符串
        try:
            input_data = binascii.unhexlify(file_content)
        except binascii.Error:
            input_data = file_content
            messagebox.showinfo("提示", "文件内容不为hex格式,将转换后的十六进制字符串保存到本地文件并计算CRC")
            # 将转换后的十六进制字符串保存到本地文件
            save_hex_file(file_path, binascii.hexlify(file_content))

        algorithm = algorithm_combobox.get()

        if algorithm == "CRC-32 (x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1)":
             calculate_crc32_file(input_data)
             return
        elif algorithm == "CRC-16/MODBUS (x16+x15+x2+1)":
            crc = calculate_crc16_modbus(input_data)
        elif algorithm == "CRC-16/CCITT-FALSE (x16+x12+x5+1)":
            crc = calculate_crc16_ccitt_false(input_data)
        elif algorithm == "CRC-16/XMODEM (x16+x12+x5+1)":
            crc = calculate_crc16_xmodem(input_data)
        else:
            crc = "Unknown Algorithm"

        crc_output = f"{algorithm} for file {file_path}: {crc:04X}"
        result_label.config(text=crc_output)

def save_hex_file(original_file_path, hex_data):
    # 构造新文件名,添加 '_hex' 后缀
    new_file_path = os.path.splitext(original_file_path)[0] + "_hex.txt"

    with open(new_file_path, 'wb') as new_file:
        new_file.write(hex_data)

    print(f"转换后的Hex文件已保存至: {new_file_path}")


def open_file():
    global input_text

    file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt"), ("Binary files", "*.bin"), ("Hex files", "*.hex")])
    if file_path:
        file_size = os.path.getsize(file_path)
        if file_size > 4096:  # 文件大小超过2KB
            result = messagebox.showinfo("提示", "文件大小超过2KB,不在输入框内显示hex字符串,将直接计算crc!")
            calculate_crc16_from_file(file_path)
        else:
            with open(file_path, 'rb') as file:
                file_content = file.read()
                if is_hex_string(file_content.replace(b" ", b"").replace(b"\n", b"")):
                    input_text.delete(1.0, tk.END)
                    input_text.insert(tk.END, file_content.decode("utf-8"))
                else:
                    input_text.delete(1.0, tk.END)
                    input_text.insert(tk.END, binascii.hexlify(file_content).decode("utf-8"))

def calculate_crc16_thread():
    threading.Thread(target=calculate_crc16, daemon=True).start()

def open_crc_tool():
    global input_text
    global input_length_label_var
    global result_label
    global algorithm_combobox
    global input_format_var

    crc_tool_window = tk.Toplevel()
    crc_tool_window.title("CRC 计算工具")
    crc_tool_window.geometry("700x480")

    input_label = ttk.Label(crc_tool_window, text="输入数据: ")
    input_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")

    input_text = tk.Text(crc_tool_window, height=22, width=80)
    input_text.grid(row=0, column=1, padx=5, pady=5, sticky="w")
    input_text.bind("<Key>", limit_input_length)  # 绑定键盘事件,限制输入长度
    input_text.bind("<Control-v>", paste_event)  # 绑定粘贴事件

    input_length_label_var = tk.StringVar()
    input_length_label_var.set("数据长度: 0")
    input_length_label = ttk.Label(crc_tool_window, textvariable=input_length_label_var)
    input_length_label.grid(row=1, column=1, padx=5, pady=5, sticky="e")

    input_format_var = tk.IntVar()
    hex_radio = ttk.Radiobutton(crc_tool_window, text="十六进制", variable=input_format_var, value=0)
    hex_radio.grid(row=2, column=0, padx=5, pady=5, sticky="w")
    ascii_radio = ttk.Radiobutton(crc_tool_window, text="ASCII", variable=input_format_var, value=1)
    ascii_radio.grid(row=2, column=1, padx=5, pady=5, sticky="w")
    input_format_var.set(0)  # 默认选择十六进制

    algorithm_label = ttk.Label(crc_tool_window, text="选择算法: ")
    algorithm_label.grid(row=3, column=0, padx=5, pady=5, sticky="w")

    algorithms = [
    "CRC-16/MODBUS (x16+x15+x2+1)",
    "CRC-16/CCITT-FALSE (x16+x12+x5+1)",
    "CRC-16/XMODEM (x16+x12+x5+1)",
    "CRC-32 (x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1)"
    ]
    max_length = max(len(alg) for alg in algorithms)
    
    # 设置Combobox的宽度为最长字符串的长度加上一些额外的空白
    algorithm_combobox = ttk.Combobox(crc_tool_window, values=algorithms, state="readonly", width=max_length + 5)
    algorithm_combobox.current(0)
    algorithm_combobox.grid(row=3, column=1, padx=5, pady=5, sticky="w")

    open_file_button = ttk.Button(crc_tool_window, text="打开文件", command=open_file)
    open_file_button.grid(row=4, column=0, padx=5, pady=5)

    calculate_button = ttk.Button(crc_tool_window, text="计算 CRC", command=calculate_crc)
    calculate_button.grid(row=4, column=1, padx=5, pady=5)

    result_label = ttk.Label(crc_tool_window, text="")
    result_label.grid(row=5, column=0, columnspan=2, padx=5, pady=5)

    crc_tool_window.mainloop()

def calculate_crc():
    input_data = input_text.get("1.0", "end-1c")
    is_hex = input_format_var.get() == 0
    algorithm = algorithm_combobox.get()

    input_length_label_var.set(f"数据长度: {len(input_data)}")

    if algorithm == "CRC-32 (x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1)":
        calculate_crc32(input_data, is_hex)
    else:
        calculate_crc16(input_data, is_hex)

def limit_input_length(event):
    global input_text
    max_length = 2048  # 设置最大输入长度
    input_length = len(input_text.get("1.0", "end-1c"))  # 获取当前输入的字符长度
    if input_length > max_length:
        # 如果输入长度超过最大长度,则禁止输入
        input_text.delete("end-1c", "end")
        show_error(f"输入数据过长!当前数据长度: {input_length},目前支持最大长度: {max_length}")

def paste_event(event):
    global input_text
    clipboard_content = root.clipboard_get()
    max_length = 2048
    input_length = len(input_text.get("1.0", "end-1c")) + len(clipboard_content)  # 获取当前输入的字符长度
    if input_length > max_length:
        show_error(f"粘贴的数据过长!当前数据长度: {input_length},目前支持最大长度: {max_length}")
        return "break"  # 阻止粘贴事件继续进行
    return None

def show_error(message):
    error_window = tk.Toplevel(root)
    error_window.title("提示")
    error_window.geometry("420x80")
    error_label = ttk.Label(error_window, text=message)
    error_label.pack(padx=10, pady=10)
    ok_button = ttk.Button(error_window, text="确定", command=error_window.destroy)
    ok_button.pack()

if __name__ == "__main__":
    open_crc_tool()

3.hex字符串互转工具的界面如下:

在这里插入图片描述

实现代码如下所示:

import tkinter as tk
from tkinter import messagebox, ttk, filedialog
import binascii
import threading
import os

def is_hex_string(s):
    try:
        int(s, 16)
        return True
    except ValueError:
        return False

def open_file_hex_deal():
    file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt"), ("Binary files", "*.bin"), ("Hex files", "*.hex")])
    if file_path:
        # 创建一个线程来处理文件读取和处理操作
        file_process_thread = threading.Thread(target=process_file, args=(file_path,))
        file_process_thread.start()

def process_file(file_path):
    global input_convert_text

    try:
        with open(file_path, 'rb') as file:
            file_size = os.path.getsize(file_path)
            if file_size > 2048:  # 文件大小超过1KB
                output_file_path = os.path.splitext(file_path)[0] + "_converted.txt"
                with open(output_file_path, 'w') as output_file:
                    for line in file:
                        if is_hex_string(line.replace(b" ", b"").replace(b"\n", b"")):
                            result = messagebox.askquestion("警告", "文件内容已经是十六进制字符串")
                            input_convert_text.delete(1.0, tk.END)
                            input_convert_text.insert(tk.END, line.decode("utf-8"))
                            return  # 直接返回,不再继续处理文件
                        else:
                            output_file.write(binascii.hexlify(line).decode("utf-8"))
                messagebox.showinfo("提示", f"文件大小超过1KB,已将转换后的数据保存到 {output_file_path}")
            else:
                for line in file:
                    if is_hex_string(line.replace(b" ", b"").replace(b"\n", b"")):
                        result = messagebox.askquestion("警告", "文件内容已经是十六进制字符串")
                        input_convert_text.delete(1.0, tk.END)
                        input_convert_text.insert(tk.END, line.decode("utf-8"))
                        return  # 直接返回,不再继续处理文件
                    else:
                        input_convert_text.insert(tk.END, binascii.hexlify(line).decode("utf-8"))
    except Exception as e:
        messagebox.showerror("错误", f"处理文件时发生错误:{e}")


def convert_to_hex():
    global input_convert_text
    global input_convert_length_label_var
    global convert_result_label
    global convert_algorithm_combobox
    
    input_data = input_convert_text.get("1.0", "end-1c")
    if is_hex_string(input_data):
        messagebox.showerror("提示", "输入内容已经为hex字符串!")
        return

    hex_data = binascii.hexlify(input_data.encode()).decode("utf-8")

    input_convert_text.delete(1.0, tk.END)
    input_convert_text.insert(tk.END, hex_data)

def convert_to_str():
    global input_convert_text

    input_data = input_convert_text.get("1.0", "end-1c")
    try:
        byte_data = bytes.fromhex(input_data).decode("utf-8")  # 将16进制字符串转换为字节串
        input_convert_text.delete(1.0, tk.END)
        input_convert_text.insert(tk.END, byte_data)
    except ValueError:
        messagebox.showerror("错误", "输入内容不是有效的十六进制字符串!")


def open_file_to_hex():
    global input_convert_text
    global input_convert_length_label_var

    convert_tool_window = tk.Toplevel()
    convert_tool_window.title("hex字符串互转工具")
    convert_tool_window.geometry("700x450")

    input_convert_label = ttk.Label(convert_tool_window, text="输入需要转换的数据: ")
    input_convert_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")

    input_convert_text = tk.Text(convert_tool_window, height=20, width=97)
    input_convert_text.grid(row=1, column=0, padx=5, pady=5, sticky="w")

    open_file_button = ttk.Button(convert_tool_window, text="打开文件[只能将文件转换为16进制字符串]", command=open_file_hex_deal)
    open_file_button.grid(row=2, column=0, padx=5, pady=5)

    set_hex_button = ttk.Button(convert_tool_window, text="字符串转16进制", command=convert_to_hex)
    set_hex_button.grid(row=3, column=0, padx=5, pady=5)

    set_str_button = ttk.Button(convert_tool_window, text="16进制转换为字符串", command=convert_to_str)
    set_str_button.grid(row=4, column=0, padx=5, pady=5)

    convert_tool_window.mainloop()

if __name__ == "__main__":
    open_file_to_hex()

4.进制转换工具界面如下所示:

在这里插入图片描述

实现代码如下:

import tkinter as tk
from tkinter import messagebox, ttk, filedialog
import binascii
import threading
import os

def convert_number(num_input_data, original_format, target_format):
    result = None
    try:
        if original_format == "二进制":
            if target_format == "八进制":
                result = oct(int(num_input_data, 2))[2:]
            elif target_format == "十进制":
                result = str(int(num_input_data, 2))
            elif target_format == "16进制":
                result = hex(int(num_input_data, 2))[2:]
        elif original_format == "八进制":
            if target_format == "二进制":
                result = bin(int(num_input_data, 8))[2:]
            elif target_format == "十进制":
                result = str(int(num_input_data, 8))
            elif target_format == "16进制":
                result = hex(int(num_input_data, 8))[2:]
        elif original_format == "十进制":
            if target_format == "二进制":
                result = bin(int(num_input_data))[2:]
            elif target_format == "八进制":
                result = oct(int(num_input_data))
            elif target_format == "16进制":
                result = hex(int(num_input_data))[2:]
        elif original_format == "16进制":
            if target_format == "二进制":
                result = bin(int(num_input_data, 16))[2:]
            elif target_format == "八进制":
                result = oct(int(num_input_data, 16))[2:]
            elif target_format == "十进制":
                result = str(int(num_input_data, 16))
    except ValueError:
        raise ValueError("输入的数据格式与选择的进制不匹配或无效。")
    return result

def display_result(result, num_result_text):
    num_result_text.delete("1.0", tk.END)
    num_result_text.insert(tk.END, str(result))

def on_convert_button_click(number_conversion, original_format_combobox, target_format_combobox, num_result_text):
    global number_conversion_input_text
    num_input_data = number_conversion_input_text.get().strip()
    original_format = original_format_combobox.get()
    target_format = target_format_combobox.get()

    try:
        result = convert_number(num_input_data, original_format, target_format)
        display_result(result, num_result_text)
    except ValueError as e:
        messagebox.showerror("错误", str(e))

def create_number_conversion_tool():
    number_conversion_tool_window = tk.Toplevel()
    number_conversion_tool_window.title("进制互转工具")
    number_conversion_tool_window.geometry("700x450")

    num_algorithms = ["二进制", "八进制", "十进制", "16进制"]

    original_format_label = ttk.Label(number_conversion_tool_window, text="选择当前数据的格式: ")
    original_format_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")

    original_format_combobox = ttk.Combobox(number_conversion_tool_window, values=num_algorithms, state="readonly")
    original_format_combobox.current(0)
    original_format_combobox.grid(row=0, column=1, padx=5, pady=5, sticky="w")

    target_format_label = ttk.Label(number_conversion_tool_window, text="选择需要转换的格式: ")
    target_format_label.grid(row=1, column=0, padx=5, pady=5, sticky="w")

    target_format_combobox = ttk.Combobox(number_conversion_tool_window, values=num_algorithms, state="readonly")
    target_format_combobox.current(0)
    target_format_combobox.grid(row=1, column=1, padx=5, pady=5, sticky="w")

    input_num_label = ttk.Label(number_conversion_tool_window, text="输入需要转换的数据: ")
    input_num_label.grid(row=2, column=0, padx=5, pady=5, sticky="w")

    global number_conversion_input_text
    number_conversion_input_text = ttk.Entry(number_conversion_tool_window, width=50)
    number_conversion_input_text.grid(row=2, column=1, padx=5, pady=5, sticky="w")

    convert_button = ttk.Button(number_conversion_tool_window, text="转换", command=lambda: on_convert_button_click(number_conversion_input_text, original_format_combobox, target_format_combobox, num_result_text))
    convert_button.grid(row=2, column=2, padx=5, pady=5, sticky="w")

    num_result_label = ttk.Label(number_conversion_tool_window, text="转换结果: ")
    num_result_label.grid(row=3, column=0, padx=5, pady=5, sticky="w")

    num_result_text = tk.Text(number_conversion_tool_window, height=20, width=50)
    num_result_text.grid(row=3, column=1, padx=5, pady=5, sticky="w")

    number_conversion_tool_window.mainloop()

if __name__ == "__main__":
    create_number_conversion_tool()

5.base64编码解码工具界面如下所示:

在这里插入图片描述

相关实现代码如下:

import tkinter as tk
from tkinter import messagebox, ttk, filedialog
import binascii
import threading
import os
import base64

def is_base64(s):
    try:
        # 尝试解码
        base64.b64decode(s, validate=True)
        return True
    except ValueError:
        return False

def base64_encode():
    input_data = input_base64_text.get("1.0", "end-1c")

    # 进行 base64 编码
    encoded_data = base64.b64encode(input_data.encode("utf-8")).decode("utf-8")

    # 将编码结果显示在结果文本框中
    base64_result_text.delete("1.0", "end")
    base64_result_text.insert("1.0", encoded_data)

def base64_decode():
    input_data = input_base64_text.get("1.0", "end-1c")

    try:
        # 进行 base64 解码
        decoded_bytes = base64.b64decode(input_data)

        # 将解码后的二进制数据解码为 UTF-8 字符串
        decoded_data = decoded_bytes.decode("utf-8")

        # 将解码结果显示在结果文本框中
        base64_result_text.delete("1.0", "end")
        base64_result_text.insert("1.0", decoded_data)
    except base64.binascii.Error:
        # Base64 解码错误,提示用户输入正确的 Base64 编码内容
        messagebox.showerror("错误", "输入的内容不是有效的 Base64 编码。请重新输入。")
    except UnicodeDecodeError:
        # UTF-8 解码错误,说明解码后的二进制数据无法转换为 UTF-8 字符串
        # 可以选择以其他方式处理,比如显示十六进制表示或者直接显示二进制数据
        messagebox.showerror("错误", "解码后的数据无法转换为 UTF-8 字符串。")

def base64_open_file():
    # 创建一个弹窗询问用户选择编码还是解码
    operation = messagebox.askyesno("选择操作", "您想要进行编码操作吗?\n\n选择'是'进行编码,选择'否'进行解码", icon='question')

    # 打开文件选择对话框,让用户选择一个文件
    file_path = filedialog.askopenfilename(
        title="选择文件",
        filetypes=(("所有文件", "*.*"), ("文本文件", "*.txt"), ("JPEG 图片", "*.jpg;*.jpeg"), ("PNG 图片", "*.png"))
    )
    
    # 检查用户是否真的选择了一个文件
    if file_path:
        try:
            # 获取文件大小
            file_size = os.path.getsize(file_path)

            if file_size < 2 * 1024:  # 如果文件大小小于 2KB
                # 直接读取文件内容
                with open(file_path, 'rb') as file:
                    file_data = file.read()

                if operation == 'yes':  # 如果用户选择了编码操作
                    # 将二进制数据编码成 base64 字符串
                    base64_encoded_data = base64.b64encode(file_data).decode('utf-8')

                    # 清空输入文本框并显示文件的 base64 编码
                    input_base64_text.delete("1.0", tk.END)
                    input_base64_text.insert("1.0", base64_encoded_data)

                else:  # 如果用户选择了解码操作
                    # 将二进制数据解码成文本字符串
                    decoded_data = file_data.decode('utf-8')

                    # 清空输入文本框并显示文件的原始内容
                    input_base64_text.delete("1.0", tk.END)
                    input_base64_text.insert("1.0", decoded_data)

            else:  # 如果文件大小大于等于 2KB
                # 构造保存文件的文件名
                file_name = os.path.basename(file_path)
                if operation == 'yes':  # 如果用户选择了编码操作
                    encoded_file_name = file_name.split('.')[0] + '_base64.txt'
                else:  # 如果用户选择了解码操作
                    encoded_file_name = file_name.split('.')[0] + '_decoded.txt'
                save_file_path = os.path.join(os.getcwd(), encoded_file_name)

                # 读取文件内容并编码或解码为 base64 字符串或原始文本
                with open(file_path, 'rb') as src_file:
                    file_data = src_file.read()
                    if operation == 'yes':  # 如果用户选择了编码操作
                        base64_encoded_data = base64.b64encode(file_data).decode('utf-8')
                    else:  # 如果用户选择了解码操作
                        decoded_data = file_data.decode('utf-8')

                if operation == 'yes':  # 如果用户选择了编码操作
                    # 将编码后的数据写入新文件
                    with open(save_file_path, 'w') as dest_file:
                        dest_file.write(base64_encoded_data)

                    # 显示保存文件的路径
                    messagebox.showinfo("文件已保存", f"文件已编码并保存到当前目录下:\n{save_file_path}")
                else:  # 如果用户选择了解码操作
                    # 将解码后的数据写入新文件
                    with open(save_file_path, 'w') as dest_file:
                        dest_file.write(decoded_data)

                    # 显示保存文件的路径
                    messagebox.showinfo("文件已保存", f"文件已解码并保存到当前目录下:\n{save_file_path}")

        except Exception as e:
            # 如果在尝试读取或处理文件时出错,显示一个错误消息
            messagebox.showerror("错误", f"无法处理文件:{e}")



def base64_encode_decode_tool():
    global input_base64_text
    global base64_result_text

    base64_encode_decode_tool_window = tk.Toplevel()
    base64_encode_decode_tool_window.title("base64编码/解码工具")
    base64_encode_decode_tool_window.geometry("700x670")

    input_base64_label = ttk.Label(base64_encode_decode_tool_window, text="输入需要转换的数据: ")
    input_base64_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")

    input_base64_text = tk.Text(base64_encode_decode_tool_window, height=20, width=97)
    input_base64_text.grid(row=1, column=0, padx=5, pady=5, sticky="w", columnspan=3)

    base64_encode_button = ttk.Button(base64_encode_decode_tool_window, text="base64编码", command=base64_encode)
    base64_encode_button.grid(row=2, column=0, padx=5, pady=5, sticky="e")

    base64_decode_button = ttk.Button(base64_encode_decode_tool_window, text="base64解码", command=base64_decode)
    base64_decode_button.grid(row=2, column=1, padx=5, pady=5, sticky="w")

    base64_open_file_button = ttk.Button(base64_encode_decode_tool_window, text="打开文件", command=base64_open_file)
    base64_open_file_button.grid(row=2, column=2, padx=5, pady=5, sticky="w")
    
    base64_result_label = ttk.Label(base64_encode_decode_tool_window, text="转换结果: ")
    base64_result_label.grid(row=3, column=0, padx=5, pady=5, sticky="w")

    base64_result_text = tk.Text(base64_encode_decode_tool_window, height=20, width=97)
    base64_result_text.grid(row=4, column=0, padx=5, pady=5, sticky="w", columnspan=3)

    base64_encode_decode_tool_window.mainloop()

if __name__ == "__main__":
    base64_encode_decode_tool()

6.时间戳转换工具界面如下所示:

在这里插入图片描述

实现相关代码如下:

import tkinter as tk
from tkinter import messagebox, ttk, filedialog
import binascii
import threading
import os
import datetime
import time
import pyperclip

update_interval = 1000  # 更新时间戳的间隔(毫秒)
running = True  # 记录时间戳是否正在运行
paused_time = None  # 记录暂停时的时间戳

def pause_time():
    global running, paused_time
    running = False
    paused_time = None
    if time_unit.get() == "毫秒":
        paused_time = int(round(time.time() * 1000))
    elif time_unit.get() == "秒":
        paused_time = int(time.time())

def activate_time():
    global running, paused_time
    running = True
    paused_time = None

def copy_time():
    global paused_time
    if paused_time:
        print(paused_time)
        pyperclip.copy(str(paused_time))

def detect_timestamp_precision(timestamp):
    timestamp_length = len(str(timestamp))
    if timestamp_length == 10:
        return "秒"
    elif timestamp_length == 13:
        return "毫秒"
    else:
        return "未知"


def update_time_labels():
    if running:
        if time_unit.get() == "毫秒":
            curr_time = datetime.datetime.now()
            timestamp = int(round(time.time() * 1000))
            current_time_label.config(text="当前时间: " + str(curr_time) + " 毫秒")
            timestamp_label.config(text="时间戳: " + str(timestamp) + " 毫秒")
        elif time_unit.get() == "秒":
            curr_time = datetime.datetime.now()
            timestamp = int(time.time())
            # 不显示毫秒部分
            current_time_label.config(text="当前时间: " + str(curr_time.strftime('%Y-%m-%d %H:%M:%S')) + " 秒")
            timestamp_label.config(text="时间戳: " + str(timestamp) + " 秒")
    # 每隔一秒更新一次
    timestamp_convert_tool_window.after(update_interval, update_time_labels)

def convert_timestamp():
    # 获取输入的时间戳字符串
    timestamp_str = input_timestamp_text.get("1.0", "end").strip()
    try:
        timestamp = int(timestamp_str)

        if timestamp < 0:
            raise ValueError("时间戳不能为负数")
        
        # 转换为 datetime 对象
        if time_unit.get() == "毫秒":
            if detect_timestamp_precision(timestamp) == "毫秒":
                converted_time = datetime.datetime.fromtimestamp(timestamp / 1000.0)
                # 更新输出框的内容
                output_timestamp_text.delete("1.0", "end")
                output_timestamp_text.insert("1.0", str(converted_time))
            elif determine_timestamp_format(timestamp) == "秒":
                messagebox.showerror("错误", "当前选择为毫秒,输入格式错误!")
        elif time_unit.get() == "秒":
            if detect_timestamp_precision(timestamp) == "秒":
                converted_time = datetime.datetime.fromtimestamp(timestamp)
                # 更新输出框的内容
                output_timestamp_text.delete("1.0", "end")
                output_timestamp_text.insert("1.0", str(converted_time))
            elif determine_timestamp_format(timestamp) == "毫秒":
                messagebox.showerror("错误", "当前选择为秒,输入格式错误!")
    except ValueError:
        output_timestamp_text.delete("1.0", "end")
        output_timestamp_text.insert("1.0", "无效的时间戳")


def convert_time_to_timestamp():
    # 获取输入的时间
    input_time = input_time_text.get("1.0", "end").strip()

    # 尝试将输入的时间转换为 datetime 对象
    try:
        time_obj = datetime.datetime.strptime(input_time, "%Y-%m-%d %H:%M:%S")
    except ValueError:
        output_time_text.delete("1.0", "end")
        output_time_text.insert("1.0", "无效的时间格式,请输入正确的时间格式:YYYY-MM-DD HH:MM:SS")
        return

    # 将时间对象转换为时间戳
    if time_unit.get() == "毫秒":
        timestamp = int(time_obj.timestamp()* 1000)
    elif time_unit.get() == "秒":
        timestamp = int(time_obj.timestamp())

    # 将时间戳显示在输出框中
    output_time_text.delete("1.0", "end")
    output_time_text.insert("1.0", str(timestamp))

def timestamp_convert_tool():
    global timestamp_convert_tool_window, current_time_label, timestamp_label, time_unit, input_timestamp_text, output_timestamp_text, input_time_text, output_time_text

    timestamp_convert_tool_window = tk.Toplevel()
    timestamp_convert_tool_window.title("时间戳转换工具")
    timestamp_convert_tool_window.geometry("650x200")

    button_frame = tk.Frame(timestamp_convert_tool_window)
    button_frame.pack()

    time_unit = tk.StringVar()
    time_unit.set("毫秒")

    # 创建选项菜单
    unit_option = tk.OptionMenu(button_frame, time_unit, "毫秒", "秒")
    unit_option.pack(side=tk.LEFT, padx=5)

    # 添加暂停按钮
    pause_button = tk.Button(button_frame, text="暂停", command=pause_time)
    pause_button.pack(side=tk.LEFT, padx=5)

    # 添加启动按钮
    pause_button = tk.Button(button_frame, text="启动", command=activate_time)
    pause_button.pack(side=tk.LEFT, padx=5)

    # 添加复制按钮
    copy_button = tk.Button(button_frame, text="复制时间戳", command=copy_time)
    copy_button.pack(side=tk.LEFT, padx=5)

    current_time_label = tk.Label(timestamp_convert_tool_window, text="当前时间: ")
    current_time_label.pack()

    timestamp_label = tk.Label(timestamp_convert_tool_window, text="时间戳: ")
    timestamp_label.pack()


    # 启动定时更新
    update_time_labels()

    input_stamp_frame = ttk.Frame(timestamp_convert_tool_window)
    input_stamp_frame.pack(pady=(10, 10))

    #转换时间戳
    input_timestamp_label = ttk.Label(input_stamp_frame, text="输入需要转换的时间戳: ")
    input_timestamp_label.pack(side="left")

    input_timestamp_text = tk.Text(input_stamp_frame, height=2, width=30)
    input_timestamp_text.pack(side="left",padx=10)

    convert_stamp_button = tk.Button(input_stamp_frame, text="转换", command=convert_timestamp)
    convert_stamp_button.pack(side="left")

    output_timestamp_text = tk.Text(input_stamp_frame, height=2, width=30)
    output_timestamp_text.pack(side="left",padx=20)

    #转换时间
    input_time_frame = ttk.Frame(timestamp_convert_tool_window)
    input_time_frame.pack(pady=(10, 0))

    input_time_label = ttk.Label(input_time_frame, text="输入需要转换的时间: ")
    input_time_label.pack(side="left")

    input_time_text = tk.Text(input_time_frame, height=2, width=30)
    input_time_text.pack(side="left", padx=20)

    convert_time_button = tk.Button(input_time_frame, text="转换", command=convert_time_to_timestamp)
    convert_time_button.pack(side="left")

    output_time_text = tk.Text(input_time_frame, height=2, width=32)
    output_time_text.pack(side="left", padx=20)

    timestamp_convert_tool_window.mainloop()

if __name__ == "__main__":
    timestamp_convert_tool()

7.json解析工具界面如下所示:

在这里插入图片描述

其实现代码如下:

import tkinter as tk
from tkinter import ttk
import json

def validate_json(json_str):
    try:
        json.loads(json_str)
        return True
    except ValueError as e:
        return False

def format_json(json_str):
    try:
        parsed = json.loads(json_str)
        formatted = json.dumps(parsed, indent=4)
        return formatted
    except ValueError as e:
        return "不正确的 JSON 格式: " + str(e)

def compress_json(json_str):
    try:
        parsed = json.loads(json_str)
        compressed = json.dumps(parsed, separators=(',', ':'))
        return compressed
    except ValueError as e:
        return "不正确的 JSON 格式: " + str(e)

def escape_json(json_str):
    escaped_json_str = json.dumps(json_str, ensure_ascii=False)  # 设置 ensure_ascii=False
    escaped_json_str = escaped_json_str.replace('\n', '')  # 去掉转义后的换行符
    return escaped_json_str

def unescape_json(json_str):
    unescaped = json_str.encode('utf-8').decode('unicode_escape')
    return unescaped

def json_parse_tool():
    def validate():
        json_str = json_entry.get("1.0", tk.END).strip()
        result = "正确的 JSON 格式" if validate_json(json_str) else "不正确的 JSON 格式"
        result_label.config(text=result)

    def format():
        json_str = json_entry.get("1.0", tk.END).strip()
        formatted_json = format_json(json_str)
        json_entry.delete("1.0", tk.END)
        json_entry.insert(tk.END, formatted_json)

    def compress():
        json_str = json_entry.get("1.0", tk.END).strip()
        compressed_json = compress_json(json_str)
        json_entry.delete("1.0", tk.END)
        json_entry.insert(tk.END, compressed_json)

    def escape():
        json_str = json_entry.get("1.0", tk.END).strip()
        compressed_json = compress_json(json_str)
        escaped_json = escape_json(compressed_json)
        escaped_json = escaped_json.replace('\\n', '\n')  # 将转义后的换行符替换为实际的换行
        # 删去开头和结尾的双引号
        if escaped_json.startswith('"') and escaped_json.endswith('"'):
            escaped_json = escaped_json[1:-1]
        json_entry.delete("1.0", tk.END)
        json_entry.insert(tk.END, escaped_json)

    def unescape():
        json_str = json_entry.get("1.0", tk.END).strip()
        unescaped_json = unescape_json(json_str)
        json_entry.delete("1.0", tk.END)
        json_entry.insert(tk.END, unescaped_json)

    json_window = tk.Toplevel()
    json_window.title("JSON转换工具")
    json_window.geometry("500x500")
    json_window.resizable(False, False)  # 禁止调整窗口大小

    json_label = ttk.Label(json_window, text="输入JSON:")
    json_label.pack(pady=2)

    json_entry = tk.Text(json_window, width=60, height=25)
    json_entry.pack(pady=2)

    result_label = ttk.Label(json_window, text="")
    result_label.pack(pady=2)

    validate_button = ttk.Button(json_window, text="校验JSON", command=validate)
    validate_button.pack(side="left", padx=5)

    format_button = ttk.Button(json_window, text="格式化JSON", command=format)
    format_button.pack(side="left", padx=5)

    compress_button = ttk.Button(json_window, text="压缩JSON", command=compress)
    compress_button.pack(side="left", padx=5)

    escape_button = ttk.Button(json_window, text="转义JSON", command=escape)
    escape_button.pack(side="left", padx=5)

    unescape_button = ttk.Button(json_window, text="去转义JSON", command=unescape)
    unescape_button.pack(side="left", padx=5)

    json_window.mainloop()


if __name__ == "__main__":
    json_parse_tool()

8.图片下载工具(有bug)

在这里插入图片描述
实现代码如下:

import os
import json
import requests
import time
import tkinter as tk
from tkinter import messagebox, ttk, filedialog
from urllib import parse

selected_directory = None

class BaiduImageSpider(object):
    def __init__(self):
        self.json_count = 0
        self.url = 'https://image.baidu.com/search/acjson?tn=resultjson_com&logid=10769109559702891286&ipn=rj&ct'\
                   '=201326592&is=&fp=result&queryWord={' \
                   '}&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=&copyright=&word={' \
                   '}&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&expermode=&nojc=&isAsync=&pn={' \
                   '}&rn=30&gsm=78&1713341718095= '
        self.directory = ""
        self.header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.30 '
        }

    def create_directory(self, name):
        self.directory = name
        if not os.path.exists(self.directory):
            os.makedirs(self.directory)

    def get_image_link(self, url):
        list_image_link = []
        strhtml = requests.get(url, headers=self.header)
        jsonInfo = json.loads(strhtml.text)
        for index in range(30):
            list_image_link.append(jsonInfo['data'][index]['thumbURL'])
        return list_image_link

    def save_image(self, img_link, filename):
        res = requests.get(img_link, headers=self.header)
        if res.status_code == 404:
            messagebox.showinfo("提示", f"图片{img_link}下载出错------->")
        with open(filename, "wb") as f:
            f.write(res.content)
            print("存储路径:" + filename)

    def run(self, searchName, image_count, save_directory):
        searchName_parse = parse.quote(searchName)
        self.create_directory(save_directory)
        pic_number = 0
        while pic_number < image_count:
            pn = (pic_number // 30 + 1) * 30
            request_url = self.url.format(searchName_parse, searchName_parse, str(pn))
            list_image_link = self.get_image_link(request_url)
            if not list_image_link:
                print(f"No more images found for {searchName}")
                break
            for link in list_image_link:
                pic_number += 1
                if pic_number > image_count:
                    print(f"{searchName} ---- Reached image count limit ----")
                    break
                self.save_image(link, os.path.join(save_directory, str(pic_number) + '.jpg'))
                time.sleep(0.2)
        print(f"{searchName} ---- Image download completed ----")
        messagebox.showinfo("提示", f"{searchName} 图像下载完成\n\n保存路径:{save_directory}")


def select_save_directory():
    global selected_directory
    selected_directory = tk.filedialog.askdirectory()


def picture_download_deal():
    global selected_directory
    search_name = picture_entry.get("1.0", tk.END).strip()
    image_count = image_count_entry.get("1.0", tk.END).strip()

    if not search_name or not image_count:
        messagebox.askquestion("警告", "搜索名称和图片数量不能为空")
        return

    try:
        image_count = int(image_count)
        if image_count <= 0:
            messagebox.askquestion("警告", "图片数量必须是大于零的整数")
            return
    except ValueError:
        messagebox.askquestion("警告", "图片数量必须是整数")
        return

    # 检查是否选择了保存目录,如果没有选择,则使用当前工作目录
    if selected_directory:
        save_directory = os.path.abspath(selected_directory)
    else:
       messagebox.showinfo("提示", "未选择目录,则保存到当前目录下")
       save_directory = os.getcwd()

    spider = BaiduImageSpider()
    spider.json_count = 1
    spider.run(search_name, image_count, save_directory)

def picture_download_tool():
    picture_download = tk.Toplevel()
    picture_download.title("图片批量下载工具")
    picture_download.geometry("450x150")
    picture_download.resizable(False, False)

    picture_label = ttk.Label(picture_download, text="输入需要搜索的图片:")
    picture_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")

    global picture_entry
    picture_entry = tk.Text(picture_download, width=30, height=2)
    picture_entry.grid(row=0, column=1, padx=5, pady=5)

    image_count_label = ttk.Label(picture_download, text="输入需要下载的数量:")
    image_count_label.grid(row=1, column=0, padx=5, pady=5, sticky="w")

    global image_count_entry
    image_count_entry = tk.Text(picture_download, width=30, height=2)
    image_count_entry.grid(row=1, column=1, padx=5, pady=5)

    select_directory_button = ttk.Button(picture_download, text="选择保存目录", command=select_save_directory)
    select_directory_button.grid(row=2, column=0, padx=5, pady=5)

    ok_button = ttk.Button(picture_download, text="确认", command=picture_download_deal)
    ok_button.grid(row=2, column=1, padx=5, pady=5)

    picture_download.mainloop()

if __name__ == "__main__":
    picture_download_tool()

9.打包

之前的代码是放在一个文件夹中,则通过打包指令将其包装成exe文件就可以使用了,打包指令如下:

pyinstaller -F crc_test.py -w

现在的代码是将其根据模块分别放置在不同的python文件中,如下图所示:
在这里插入图片描述

因此,创建一个打包脚本.py,代码如下:

import sys
from PyInstaller.__main__ import run

if __name__ == '__main__':
    opts = ['main.py', '-F', '--noconsole']  # 添加 --noconsole 参数,不显示命令行
    sys.exit(run(opts))

之后只需在命令行运行打包脚本,则可对其进行exe打包

python 打包脚本.py

两者运行后都会在dist文件夹下生成exe文件
在这里插入图片描述

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落淼喵_G

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值