最近学习了python的jieba分词库和wordcloud词云库,诞生了想写个小demo,使用python实现文章的词云图的绘制,然后需要具有交互界面,并且能够在没有python环境的电脑下运行,方便不懂编程的人直接使用。
全部代码实现的打包exe文件:WordCloudTool免安装版
主要使用的库和软件如下:
python3.7.1 实现算法编程语言
jieba 词语分割
wordcloud 绘制云图
matplotlib.pyplot 显示/保存云图
注意,默认上述环境和库以安装完毕!
登录界面如下:
注册页面如下:
文件选择页面如下:
完整代码如下:
#_*_coding:utf-8_*_
from tkinter import filedialog
import tkinter as tk
import jieba
import tkinter.messagebox
import pickle
import wordcloud
import matplotlib
#创建一个窗体
window = tk.Tk() #建立以个窗口
window.title("词云生成器") #命名窗体
window.geometry('450x300') #设置窗体大小
window.resizable(False, False)
# welcome image
canvas = tk.Canvas(window, height=300, width=450)
image_file = tk.PhotoImage(file='bg.gif')
image = canvas.create_image(0,0, anchor='nw', image=image_file)
canvas.pack(side=tk.LEFT)
# user information
#tk.Label(window, text='User name: ').place(x=50, y= 150)
#tk.Label(window, text='Password: ').place(x=50, y= 190)
var_usr_name = tk.StringVar()
var_usr_name.set('[email protected]')
entry_usr_name = tk.Entry(window, textvariable=var_usr_name)
entry_usr_name.place(x=160, y=150)
var_usr_pwd = tk.StringVar()
entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, show='*')
entry_usr_pwd.place(x=160, y=190)
def wordclounds_w():
def Open_file():
try:
filename = filedialog.askopenfilename( \
initialdir='C:', title="Please select txt file", \
filetypes=(("txt文件", "*.txt"), ("所有文件", "*.*")))
except FileNotFoundError:
pass
f = open(filename, "r", encoding="utf-8")
t = f.read()
f.close()
ls = jieba.lcut(t)
txt = " ".join(ls)
w = wordcloud.WordCloud(font_path="msyh.ttf", width=1000, height=700, background_color="white", max_words=15)
w.generate(txt)
#以文件名输出为.png图片
lists = list(reversed(filename))
for i in range(len(lists)):
if lists[i] == "/":
break
w.to_file("".join(reversed(lists[4:i]))+".png")
window_w = tk.Toplevel(window)
window_w.geometry('450x300')
window_w.title('select file window')
window_w.resizable(False, False)
# txt introduction
# welcome image
canvas = tk.Canvas(window_w, height=300, width=450)
image_files = tk.PhotoImage(file='slg.gif')
images = canvas.create_image(0, 0, anchor='nw', image=image_files)
canvas.pack(side=tk.LEFT)
btn_confirm_sign_up = tk.Button(window_w, text='Please open the txt file!', command=Open_file)
btn_confirm_sign_up.place(x=130, y=200)
window_w.mainloop()
#usr_login
def usr_login():
usr_name = var_usr_name.get()
usr_pwd = var_usr_pwd.get()
try:
with open('usrs_info.pickle', 'rb') as usr_file:
usrs_info = pickle.load(usr_file)
except FileNotFoundError:
with open('usrs_info.pickle', 'wb') as usr_file:
usrs_info = {'admin': 'admin'}
pickle.dump(usrs_info, usr_file)
if usr_name in usrs_info:
if usr_pwd == usrs_info[usr_name]:
tk.messagebox.showinfo(title='Welcome', message='Welcome use this tool! ' + usr_name)
wordclounds_w()
else:
tk.messagebox.showerror(message='Error, your password is wrong, try again.')
else:
is_sign_up = tk.messagebox.askyesno('Welcome',
'You have not sign up yet. Sign up today?')
if is_sign_up:
usr_sign_up()
#usr_sign_up
def usr_sign_up():
def sign_to_Mofan_Python():
np = new_pwd.get()
npf = new_pwd_confirm.get()
nn = new_name.get()
with open('usrs_info.pickle', 'rb') as usr_file:
exist_usr_info = pickle.load(usr_file)
if np != npf:
tk.messagebox.showerror('Error', 'Password and confirm password must be the same!')
elif nn in exist_usr_info:
tk.messagebox.showerror('Error', 'The user has already signed up!')
else:
exist_usr_info[nn] = np
with open('usrs_info.pickle', 'wb') as usr_file:
pickle.dump(exist_usr_info, usr_file)
tk.messagebox.showinfo('Welcome', 'You have successfully signed up!')
window_sign_up.destroy()
window_sign_up = tk.Toplevel(window)
window_sign_up.geometry('350x200')
window_sign_up.title('Sign up window')
window_sign_up.resizable(False, False)
new_name = tk.StringVar()
new_name.set('[email protected]')
tk.Label(window_sign_up, text='User name: ').place(x=10, y=10)
entry_new_name = tk.Entry(window_sign_up, textvariable=new_name)
entry_new_name.place(x=150, y=10)
new_pwd = tk.StringVar()
tk.Label(window_sign_up, text='Password: ').place(x=10, y=50)
entry_usr_pwd = tk.Entry(window_sign_up, textvariable=new_pwd, show='*')
entry_usr_pwd.place(x=150, y=50)
new_pwd_confirm = tk.StringVar()
tk.Label(window_sign_up, text='Confirm password: ').place(x=10, y=90)
entry_usr_pwd_confirm = tk.Entry(window_sign_up, textvariable=new_pwd_confirm, show='*')
entry_usr_pwd_confirm.place(x=150, y=90)
btn_confirm_sign_up = tk.Button(window_sign_up, text='Sign up', command=sign_to_Mofan_Python)
btn_confirm_sign_up.place(x=150, y=130)
# login and sign up button
btn_login = tk.Button(window, text='Login', command=usr_login)
btn_login.place(x=170, y=230)
btn_sign_up = tk.Button(window, text='Sign up', command=usr_sign_up)
btn_sign_up.place(x=270, y=230)
window.mainloop()
问题主要是针对pyinstaller对jieba
、wordcloud
库打包时出现的问题。
【打包jieba库时,因提前处理了路径问题,在此没有出现错误!下面仅为jieba库相关问题处理案例!】
1. No such or directory: u’C:\user\LOOP\AppData\Local\Temp\_MEI12~1\jieba\dict.txt’
这是用于jieba中调用了dict.txt文件,而pyinstaller在打包时不会自动把该文件打包,定位到出现错误的文件Lib\site-packages\jieba\_compat.py的8行,可以看到如下:
try:
import pkg_resources
get_module_res = lambda *res: pkg_resources.resource_stream(__name__,
os.path.join(*res))
except ImportError:
get_module_res = lambda *res: open(os.path.normpath(os.path.join(
os.getcwd(), os.path.dirname(__file__), *res)), 'rb')
该方法就是在当前文件 (_compat.py) 目录作为get_module_res的目录,在pyinstaller manual文档中解释如下:
也就是说使用__file__的相对路径在打包完成后会变成绝对路径,并且以_MEIxxxxx文件名存储在缓存文件夹中。并且也给出解决方案,可以使用sys.executable也就是当前的运行目录,就是运行打包好的exe文件目录,如果是在使用python时,就是调用的python路径。
因此,解决方法如下:
try:
import pkg_resources
get_module_res = lambda *res: open(os.path.normpath(os.path.join(
os.getcwd(), os.path.dirname(sys.executable), *res)), 'rb')
except ImportError:
get_module_res = lambda *res: open(os.path.normpath(os.path.join(
os.getcwd(), os.path.dirname(__file__), *res)), 'rb')
同理,在打包wordcloud也会出现相似的问题,定位到相关文件(Lib\site-packages\wordcloud\wordcloud.py)第28、29、30行上下:
FONT_PATH = os.environ.get("FONT_PATH", os.path.join(os.path.dirname(__file__),
"DroidSansMono.ttf"))
STOPWORDS = set([x.strip() for x in open(
os.path.join(os.path.dirname(__file__), 'stopwords')).read().split('\n')])
很明显是__file__问题,修改如下:
FONT_PATH = os.environ.get("FONT_PATH", os.path.join(os.path.dirname(sys.executable),
"DroidSansMono.ttf"))
STOPWORDS = set([x.strip() for x in open(
os.path.join(os.path.dirname(sys.executable), 'stopwords')).read().split('\n')])
注意:以上修改只是针对使用pyinstaller打包时,因为改变了其文件路径,在调试和运行时会出错
最后把dict.txt和stopwords以及img文件拷贝到与生成的.exe文件同一目录即可。
Successfully: