tkinter和pyinstaller初尝 : 国自然结题报告下载工具 视窗化改造

Rhilip 2020-07-09 PM 1749℃ 6条

我在今年2月的时候写了个 Rhilip/NSFC_conclusion_downloader 来辅助我从科学基金共享服务网(科技成果信息系统) 下载 国自然结题报告,并生成PDF文件。截至目前也有了12个star,并且在知乎上介绍之后,也开始有其他使用的人。

可毕竟原项目需要一定的python基础(基础到极限了),但使用人(包括我们课题组的同学)多数并不具备编程基础,导致原脚本形式的repo难以被使用。

image-20200709175406546.png

这段时间真好稍空,翻看“知乎”的时候正好看见别人的抱怨。便想着将其写一个GUI出来,方便其他人的使用。

最终形成的软件截图如下:

gui_usage.png

你可以在 Release页面 直接下载,然后解压后直接可以打开使用。

image-20200709213546323.png

!!!后面的,对tkinter和pyinstaller等具体编写过程不感兴趣的可以不用看了!!!

GUI框架编写调查

因为之前写各类脚本的时候并没有考虑过可视化(虽然html写过很多),所以这次对python的gui编程也进行了一定的资料收集。

首先是GUI框架的选取,Python中有名的GUI框架就tkinter和PyQT5。因为本项目是一个小项目,而且也可以算是本人GUI编写入门。经过简单到不能再简单的抉择,选择tkinter作为GUI框架,一方面是因为这个库入手较为简单,很适合作为Python的GUI编写入门,另一方面是因为tkinter是Python的内置库,不需要像PtQt5一样,安装Qt5环境,这对于后续pyinstaller打包较为方便(可以有效的减少打包后的文件体积)。

而从tkinter的具体写法上,也有两种,一种流程式,一种对象式,对比如下:

# 流程式
import tkinter as tk

window = tk.Tk()
window.title('my window')

##窗口尺寸
window.geometry('200x200')

##显示出来
windo.mainloop()

以及

# 对象式
import tkinter as tk

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent

        <create the rest of your GUI here>

if __name__ == "__main__":
    root = tk.Tk()
    MainApplication(root).pack(side="top", fill="both", expand=True)
    root.mainloop()

一些讨论可以见 python - Best way to structure a tkinter application? - Stack Overflow,本处同样鉴于初步尝试,使用“流程式”来进行程序编写。

GUI编写过程

在上述思想的决定下,我写出了 一个gui版本 feat: 写一个GUI出来 · Rhilip/[email protected]

在这个版本,实现了现在的各个控件的基本布局定位,使用grid布局,分成上中下三栏。并通过改写原来的nsfc_downloader.py 文件,使得其能适应GUI环境,而不对原CLI调用产生较大的影响。

但这样的程序在随后的调试中发现了更多问题:

  1. 国自然官网最近经常性报错Internal Server Error。而原来直接返回错误代码500对于小白来说莫名其妙,不如直接返回错误信息好些。

image-20200709223456540.png

  1. 原来点击下载按钮后,因为下载操作涉及大量网络请求,并且内部实现使用id递增,遇到404退出的实现,比较难使用队列+线程形式进行优化。这样就导致下载操作卡住GUI主线程,甚至导致程序被windows系统认为无响应。使用线程的形式进行优化,并再次修改nsfc_downloader的实现,将更多参数抛到对象内部,而不是过程中,主线程使用每1s轮询的形式获取运行时候的参数信息,这样就顺带实现了下载进度的显示。

image-20200709223814569.png

  1. 但是这样改,又引出了一个问题,就是“点击下载”按钮可能被多次点击,所以需要在点击按钮后禁用按钮,并在一个下载任务完成后还原按钮状况,这个和前端防重放一样。

    # 禁用按钮
    input_button.config(state='disabled')
    
    <...下载任务..>
    
    # 下载任务完成后,恢复按钮状态
    input_button.config(state='normal')

Pyinstaller打包发布

而pyinstaller同样在最开始遇到了一些小问题,如果直接使用 pyinstaller gui.py 则出不来exe可执行文件,而加上 -F参数后,虽然生成了exe文件,但是是先出现命令行窗口,之后才有GUI出来。

后来重新查阅pyinstaller的文档,终于知道要增加-w参数来实现只显示GUI窗口。最终确定使用以下命令进行打包发布

(venv) NSFC_conclusion_downloader>pip install pyinstaller
(venv) NSFC_conclusion_downloader>pyinstaller gui.py -n nsfc_downloader -Fw

生成的程序大小在11M左右,但本项目的核心代码就两个nsfc_downloader.py, gui.py ,整体实现不到10KB。这也因为pyinstaller会打包python解释器以及使用了的库的原因。而即使是个空项目(只有hello world),使用pyinstaller打包出来的体积也在10M以上。

就这样,很圆满的完成了整个GUI的编写,如果基金委那边对于目前输出的结构不做更改的话,之后应该不会再来更新这个repo了。

非特殊说明,本博所有文章均为博主原创。

评论啦~



已有 6 条评论


  1. 王真 南京医科大学
    王真 南京医科大学

    最近网站好像出问题啦,大神能帮忙调整下代码吗?

    回复 2021-08-09 21:24
    1. Rhilip
      Rhilip 博主

      如果您指的是知乎里另外一个回答提供的在线网站,那么不好意思。那个不是我写以及维护的。
      如果问题出自NSFC官网,那我就更加无能为力。
      关于给出的脚本和软件,本人目前并未发现其失效。

      回复 2021-08-09 21:35
  2. richard
    richard

    python版本下载出问题如下
    python3 nsfc_downloader.py --ratify cc63ee32edd56a630ac09226083ebff4
    开始获取项目信息,项目编号: cc63ee32edd56a630ac09226083ebff4
    Traceback (most recent call last):
    File "/Users/xiaolaoc/Desktop/NSFC_conclusion_downloader-master/nsfc_downloader.py", line 238, in <module>

    downloader.download(args.ratify)

    File "/Users/xiaolaoc/Desktop/NSFC_conclusion_downloader-master/nsfc_downloader.py", line 192, in download

    ratify_info = self.get_ratify_info(ratify)

    File "/Users/xiaolaoc/Desktop/NSFC_conclusion_downloader-master/nsfc_downloader.py", line 128, in get_ratify_info

    rj = self.get_ratify_info_from_nsfc(ratify)

    File "/Users/xiaolaoc/Desktop/NSFC_conclusion_downloader-master/nsfc_downloader.py", line 116, in get_ratify_info_from_nsfc

    raise e

    File "/Users/xiaolaoc/Desktop/NSFC_conclusion_downloader-master/nsfc_downloader.py", line 109, in get_ratify_info_from_nsfc

    r.raise_for_status()

    File "/usr/local/lib/python3.9/site-packages/requests/models.py", line 943, in raise_for_status

    raise HTTPError(http_error_msg, response=self)

    requests.exceptions.HTTPError: 503 Server Error: Service Unavailable for url: http://output.nsfc.gov.cn/baseQuery/data/conclusionProjectInfo/cc63ee32edd56a630ac09226083ebff4

    回复 2021-08-29 21:12
    1. Rhilip
      Rhilip 博主

      NSFC 官网问题,与我无关

      回复 2021-08-30 12:05
  3. zw
    zw

    能发个能使用的版本吗?

    回复 2021-11-15 21:09
    1. Rhilip
      Rhilip 博主

      不能,错过了就没有了

      回复 2021-11-16 09:20