因需要用到工具且偶尔会出现电脑没网的情况,则自己想写一个工具,方便调试,也是学习下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=©right=&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文件