原程序运行良好,Pyinstaller封装后运行出错 的分析

前言

昨天决定分享一下最近写的exhentai爬虫程序,参考了这篇文章,看了下里面几个常见打包软件的简介表格(可惜没nuitka)
因为是给小白用户使用,做成单个文件形式,只能在Pyinstaller和py2exe之间选择
去各自官网看了下,发现py2exe很久没更新了,对python3新版本的支持也不是太好,就决定用Pyinstaller来封装/打包
这里略过Pyinstaller的安装和使用,重点说明症状,分析过程,解决办法和教训

症状

  1. 打包成功

  2. 运行程序时出现如下报错

C:\Users\xoxo\PycharmProjects\Hentai_Spider>main
Traceback (most recent call last):
  File "main.py", line 6, in <module>
    from config import args
  File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
  File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1200, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 1129, in _exec
  File "C:\Python34\lib\site-packages\PyInstaller\loader\pyimod03_importers.py",
 line 631, in exec_module
    exec(bytecode, module.__dict__)
  File "config.py", line 11, in <module>
    parser.add_argument('-sd', '--savedir', default=config['ARGS']['SAVEDIR'])
  File "configparser.py", line 936, in __getitem__
KeyError: 'ARGS'
[7836] Failed to execute script main

C:\Users\xoxo\PycharmProjects\Hentai_Spider>

分析过程

0 . StackOverflow搜了下发现没啥经验可供参考……
1 . main.py程序是完全可以跑通的,从未出现过这个报错,所以确定问题出在封装过程中
2 . 报错信息上看,是(封装后的程序)执行config.py时出了问题
3 . 通过控制变量排除法(过程比较繁琐,不一一列举),确定是在读取config.ini时出的错,把赋值config_path这里改成确定的路径即可正常运行

代码如下:

config = configparser.ConfigParser()
config_path = os.path.join(os.path.dirname(__file__), CONFIG_FILE)
config.read(config_path)

顺便解释一下,我的设计意图是让config.py去读取其所在目录下的配置文件,main.py和config.py在同一目录

4 . 由于CONFIG_FILE是常量(文件名),那最终就怀疑到os.path.dirname(__file__)部分
5 . 在赋值config_path =这句后加上print(os.path.dirname(__file__),看看封装后这里的file会到哪个目录,发现变成了C:\Users\xoxo\AppData\Local\Temp\_MEI92882

C:\Users\xoxo\PycharmProjects\Hentai_Spider>main
C:\Users\xoxo\AppData\Local\Temp\_MEI92882
Traceback (most recent call last):
  File "main.py", line 6, in <module>
    from config import args
  File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
  File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1200, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 1129, in _exec
  File "C:\Python34\lib\site-packages\PyInstaller\loader\pyimod03_importers.py",
 line 631, in exec_module
    exec(bytecode, module.__dict__)
  File "config.py", line 12, in <module>
    parser.add_argument('-sd', '--savedir', default=config['ARGS']['SAVEDIR'])
  File "configparser.py", line 936, in __getitem__
KeyError: 'ARGS'
[9296] Failed to execute script main

C:\Users\xoxo\PycharmProjects\Hentai_Spider>

6 . 可以看到config.py虽然封装前和main.py在一个文件夹下,但被封装后,执行时就处于临时文件夹,这时候取其自身所在目录的动作就有问题

解决方案

main.py来抓目录信息,再传给config.py(中函数)

教训

  1. 封装程序没有聪明到能理解设计意图,所以写代码的得更聪明点

  2. 如果某项目可能会被封装,让被封装的那个程序来抓取目录信息并传递

    原文作者:阿薛
    原文地址: https://segmentfault.com/a/1190000011966631
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞