python实战项目词云生成器(wordcloud+jieba+pyinstaller打包)——词云生成软件【Pyinstaller打包问题解决】

最近学习了python的jieba分词库和wordcloud词云库,诞生了想写个小demo,使用python实现文章的词云图的绘制,然后需要具有交互界面,并且能够在没有python环境的电脑下运行,方便不懂编程的人直接使用。

全部代码实现的打包exe文件:WordCloudTool免安装版

主要使用的库和软件如下:

python3.7.1  实现算法编程语言
jieba 词语分割
wordcloud 绘制云图
matplotlib.pyplot 显示/保存云图
注意,默认上述环境和库以安装完毕!
 

界面结构设计

登录界面如下:

python实战项目词云生成器(wordcloud+jieba+pyinstaller打包)——词云生成软件【Pyinstaller打包问题解决】_第1张图片

注册页面如下:

python实战项目词云生成器(wordcloud+jieba+pyinstaller打包)——词云生成软件【Pyinstaller打包问题解决】_第2张图片

文件选择页面如下:

python实战项目词云生成器(wordcloud+jieba+pyinstaller打包)——词云生成软件【Pyinstaller打包问题解决】_第3张图片

 

完整代码如下:

#_*_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打包问题处理

问题主要是针对pyinstaller对jiebawordcloud库打包时出现的问题。

【打包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文档中解释如下: 

python实战项目词云生成器(wordcloud+jieba+pyinstaller打包)——词云生成软件【Pyinstaller打包问题解决】_第4张图片

也就是说使用__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.txtstopwords以及img文件拷贝到与生成的.exe文件同一目录即可。

Successfully:

python实战项目词云生成器(wordcloud+jieba+pyinstaller打包)——词云生成软件【Pyinstaller打包问题解决】_第5张图片

你可能感兴趣的:(Python实战问题解决,避坑Python实战)