抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >
L
O
A
D
I
N
G

在工作和生活中,我们常常遇到一些简单重复的任务,如果手动处理这些任务,会枯燥乏味且耗费时间。为了解决这个问题,我们可以使用Python编写一些小工具来自动化完成这些任务,提高效率并减轻工作负担。在本文中,我们将介绍如何使用Python编写个性化需求的小工具集合,以解决特定问题。

一、引言

编写个性化需求的小工具不仅可以解决实际问题,还带来了许多额外的好处。以下是一些编写小工具的好处:

迭代改进和自我满足

编写小工具是一个迭代的过程。通过不断改进和完善工具,我们可以逐渐实现我们想要的效果。每一次迭代都让工具更加强大和灵活,让我们能够更好地满足自己的需求。这种持续的改进过程不仅能带来成就感和自我满足,还能提升我们的编程能力和创造力。

同学需求和学习正反馈

编写小工具不仅可以满足个人需求,还可以帮助其他同学解决类似的问题。当我们的小工具能够帮助他人解决实际问题时,我们会收到学习正反馈。其他同学的反馈和感激不仅能够增加我们的学习动力,还能促使我们不断改进和提升工具的功能和性能。

提升问题分析与解决能力

编写小工具的过程涉及到对问题进行分析和解决的能力。我们需要仔细分析问题的本质和需求,设计合适的解决方案,并考虑边界情况和异常情况。通过不断面对和解决各种问题,我们的问题分析与解决能力会得到提升,成为更好的问题解决者。

增强逻辑处理和边界考虑能力

编写小工具需要我们进行逻辑处理和边界考虑。我们需要思考如何处理各种情况和异常,以及如何设计合理的流程和算法。这种练习不仅提升了我们的逻辑思维能力,还培养了我们考虑问题全面性和细致性的能力。这些能力在日常的编程工作和解决实际问题中也会得到充分的应用。

二、小工具的实现

1. 了解需求

首先,我们需要明确自己的需求。
在文章中,你提到了两个例子:将PDF文件中的表格数据提取为Excel文件,以及将Excel文件中的学生成绩转换为JSON格式的data.js文件。这些都是常见的需求,我们将以此为例来介绍如何编写相应的小工具。

2. 寻找合适的库

Python 拥有众多优秀的第三方库,可以帮助我们快速处理各种问题。
在解决特定问题之前,我们需要先根据上面的需求分析来寻找适合的库来支持我们的工具开发。

在 Python 中找到适合你的项目的库,可以通过以下几种方法:

  • PyPI(Python Package Index):PyPI是Python的官方软件包索引,拥有大量的开源库。你可以在https://pypi.org/ 上搜索相关关键字,查找与你的项目需求匹配的库。每个库都有详细的文档和用法示例,可以帮助你确定是否适合你的项目。

使用 Python 的tkinter库:tkinter 是 Python 的一个官方库,用于创建图形用户界面(GUI)。你可以使用 tkinter 来创建一个小工具,该工具可以在 GUI 中输入一些参数,然后执行相应的操作。

3. 编写小工具

在了解需求和选择适合的库之后,我们可以开始编写小工具了。

对于将PDF中的表格数据提取为Excel文件的问题,可以按照以下步骤编写小工具:

  • 安装tabula-py库:使用pip install tabula-py命令安装该库。
  • 导入库:在Python脚本中导入tabula-py库。
  • 使用read_pdf()函数:使用read_pdf()函数读取PDF文件中的表格数据,并将其转换为DataFrame格式。
  • 使用to_excel()函数:使用to_excel()函数将DataFrame数据导出为Excel文件。

对于将Excel文件中的学生成绩转换为JSON格式的data.js文件的问题,可以按照以下步骤编写小工具:

  • 安装pandas库:使用pip install pandas命令安装该库。
  • 导入库:在Python脚本中导入pandas库。
  • 使用read_excel()函数:使用read_excel()函数读取Excel文件中的学生成绩数据,并将其转换为DataFrame格式。
  • 使用to_json()函数:使用to_json()函数将DataFrame数据导出为JSON格式。

4. 定制化

有时候,我们可能无法找到完全符合需求的现成工具,或者需要对现有工具进行定制化。在这种情况下,我们可以结合多个库和自己的编程能力,根据需求编写定制化的小工具。

可以使用Python的文件操作功能、字符串处理功能等,结合所需的第三方库,编写满足个性化需求的小工具。例如,你可以使用os库来处理文件路径和文件操作,使用json库来处理JSON数据的生成和解析,以及使用其他适合的库来满足特定需求。

4.1 实战案例一

ExcelToJsonFile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import pandas as pd
import orjson
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
print(pd.__version__)
print(orjson.__version__)

class YTools():
excelSourcePath = None

def __init__(self):
window = self.root = tk.Tk() # 创建窗口类
window.title('小工具')
window.geometry('600x300')
window.maxsize(1200,1200)
self.excelSourcePath = tk.StringVar()
self.createUI()
window.mainloop()

def createUI(self):
self.excelToJsonFile()
pass

def excelToJsonFile(self):
row_num = 0
frame_file = tk.Frame(self.root).grid(row=row_num)
label_file = tk.Label(frame_file,text="Excel: ")
label_file.grid(row=row_num,column=0,sticky="w")
entry_file = tk.Entry(frame_file, width=50, state= 'readonly',textvariable=self.excelSourcePath)
entry_file.grid(row=row_num, column=1, padx=5, pady=5)
button1_file = tk.Button(frame_file,text='选择文件',command=self.selectExcelFileDlg)
button1_file.grid(row=row_num, column=2, padx=5, pady=5)
button2_file = tk.Button(frame_file,text='保存为js文件',command=self.saveExcelFileDlg)
button2_file.grid(row=row_num, column=3, padx=5, pady=5)
pass

def selectExcelFileDlg(self):
excelPath = filedialog.askopenfilename(filetypes=[("Excel",".xlsx")])
self.excelSourcePath.set(excelPath)

def saveExcelFileDlg(self):
path = self.excelSourcePath.get()
if path:
print(path)
save_path = filedialog.asksaveasfilename(defaultextension='.js',
filetypes=[('JavaScript Files', '*.js')],
title='Save JavaScript File')
if save_path:
df = pd.read_excel(path)
data = df.to_dict(orient='records')
json_data = orjson.dumps(data).decode('utf-8')
print(json_data)
# 写入data.js文件
with open(save_path, 'w', encoding='utf-8') as file:
file.write(f'var jsonData = {json_data}')
messagebox.showinfo(title='提示', message='保存成功')
else:
print("未选择文件")
else:
messagebox.showerror("提示", "请选择文件")
pass

def main():
YTools()

if __name__ == "__main__":
main()

4.2 实战案例二

BiliTool.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import os
import json
import shutil
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
from tkinter import ttk

class BiliRename() :
fileSourcePath = None
cpFilePath = None
old_new_filename_dist = {}
def __init__(self):
self.root = tk.Tk()
self.root.title('B站视频批处理')
self.root.geometry('680x200')
self.root.maxsize(1200,1200)
self.fileSourcePath = tk.StringVar()
self.cpFilePath = tk.StringVar()
self.createUI()

def run(self):
self.root.mainloop()

def createUI(self):
self.selectFilePathUI()
self.operateFileUI()
pass

def selectFilePathUI(self):
row_num = 0
frame_file = tk.Frame(self.root).grid(row=row_num)
label_file = tk.Label(frame_file,text="文件路径: ")
label_file.grid(row=row_num,column=0,sticky="w")
entry_file = tk.Entry(frame_file, width=50, state= 'readonly',textvariable=self.fileSourcePath)
entry_file.grid(row=row_num, column=1, padx=5, pady=5)
select_dir_btn = tk.Button(frame_file,text='选择路径',command=lambda: self.selectFilePathDlg(1))
select_dir_btn.grid(row=row_num, column=2, padx=5, pady=5)
preview_btn = tk.Button(frame_file,text='预览文件',command=self.previewFileName)
preview_btn.grid(row=row_num, column=3, padx=5, pady=5)
pass

def operateFileUI(self):
row_num = 1
frame_file = tk.Frame(self.root).grid(row=row_num)
label_file = tk.Label(frame_file,text="拷贝全部视频到指定路径: ")
label_file.grid(row=row_num,column=0,sticky="w")
entry_file = tk.Entry(frame_file, width=50, state= 'readonly',textvariable=self.cpFilePath)
entry_file.grid(row=row_num, column=1, padx=5, pady=5)
select_dir_btn = tk.Button(frame_file,text='选择路径',command=lambda: self.selectFilePathDlg(2))
select_dir_btn.grid(row=row_num, column=2, padx=5, pady=5)
cp_file_btn = tk.Button(frame_file,text='确认拷贝',command=self.CPFileWithProgress)
cp_file_btn.grid(row=row_num, column=3, padx=5, pady=5)
pass

def previewFileName(self):
path = self.fileSourcePath.get()
if path:
self.readData(path)
# 创建一个新的窗口,用于显示所有文件名
top = tk.Toplevel(self.root)
top.geometry('800x400')
top.resizable(True, True)
top.title('文件列表')
frame1 = tk.Frame(top)
frame2 = tk.Frame(top)
# 在新窗口中创建一个 Listbox 对象,并显示所有文件名
label1 = tk.Label(frame1, text='原文件名称列表:')
lb1 = tk.Listbox(frame1)
label2 = tk.Label(frame2, text='预修改文件名称列表:')
lb2 = tk.Listbox(frame2)
btn = tk.Button(top,text='确认修改',command=self.confirmNameChange)
old_filenames = self.old_new_filename_dist.keys()
new_filenames = self.old_new_filename_dist.values()
for name in old_filenames:
lb1.insert(tk.END, name)
for name in new_filenames:
lb2.insert(tk.END, name)
label1.pack(side=tk.TOP)
lb1.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
label2.pack(side=tk.TOP)
lb2.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
frame1.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
frame2.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
btn.pack(side=tk.BOTTOM)
else:
messagebox.showerror("提示", "请选择文件路径")
pass

def selectFilePathDlg(self,index):
filePath = filedialog.askdirectory()
if index == 1:
self.fileSourcePath.set(filePath)
elif index == 2:
self.cpFilePath.set(filePath)
else:
raise ValueError("Invalid index")
pass

def CPFileWithProgress(self):
src_path = self.fileSourcePath.get()
dst_path = self.cpFilePath.get()
if not src_path or not dst_path:
messagebox.showerror("错误", "请选择源路径和目标路径")
return
file_list = self.getVideoList(src_path)
if not file_list:
messagebox.showerror("错误", "源路径中不存在任何视频文件")
return
progress_window = tk.Toplevel(self.root)
progress_window.title("拷贝进度")
progress_label = tk.Label(progress_window, text="正在拷贝文件,请稍候...")
progress_label.pack(padx=10, pady=10)
progress_bar = ttk.Progressbar(progress_window, orient=tk.HORIZONTAL, mode='determinate', length=300)
progress_bar.pack(padx=10, pady=10)

progress_bar['maximum'] = len(file_list)
progress_bar['value'] = 0
for i, file in enumerate(file_list):
try:
shutil.copy(file, dst_path)
except Exception as e:
messagebox.showerror("错误", f"拷贝文件 {file} 失败:{str(e)}")
progress_window.destroy()
return
progress_bar['value'] = str(i + 1)
progress_window.update()
progress_window.destroy()
messagebox.showinfo("提示", "视频文件拷贝完成")
pass

def readData(self,path):
for root, dirs, files in os.walk(path):
old_name = ""
new_name = ""
for file in files:
if file.endswith(".mp4"): # 获取当前视频文件名
old_name = file
elif file.endswith(".info"): # 获取信息文件中名称
new_name = self.getPartName(os.path.join(root, file))+".mp4"
# 使用字典记录文件名前后信息
if old_name and new_name:
self.old_new_filename_dist[f"{os.path.join(root, old_name)}"] = f"{os.path.join(root, new_name)}"

def confirmNameChange(self):
# 修改文件名
for key, value in self.old_new_filename_dist.items():
try:
os.rename(key,value)
except Exception as e:
messagebox.showerror("错误", f"修改文件名错误:{str(e)}")
continue
# 关闭窗口
top = self.root.winfo_children()[-1] # 获取最上层的 Toplevel 窗口
top.destroy()
messagebox.showinfo("提示","文件名修改完成")
self.old_new_filename_dist.clear()

# 抽取info文件中的有效信息
def getPartName(self,info):
with open(info, 'r', encoding='UTF-8') as todos:
str = todos.read()
str_dict = json.loads(str)
return str_dict["PartName"]

def getVideoList(self,path):
# 视频文件的扩展名列表
video_exts = ['.mp4', '.avi', '.mkv', '.flv']
file_list = []
for root, dirs, files in os.walk(path):
for file in files:
_, ext = os.path.splitext(file)
if ext.lower() in video_exts:
file_list.append(os.path.join(root, file))
return file_list

def main():
app = BiliRename()
app.run()

if __name__ == "__main__":
main()

评论