近日幫朋友寫了個python小程序,從互聯網上抓取一些需要的文章到本地。為了運行方便,希望能轉換成exe程序在windows下定期執行。從百度上找了些文章,發現py2exe的應用比較多,遂使用之。
1. 下載py2exe
官網:http://www.py2exe.org/index.cgi/FrontPage
我使用的是py2exe-0.6.9.win32-py2.7.exe
直接安裝即可。
安裝完成以后,python的Lib/site-packages目錄下會多出py2exe目錄和egg-info文件。
2. 編寫setup.py
py2exe的用法非常簡單,寫好setup.py文件以后,執行python setup.py py2exe即可。
最簡單的示例可以參考官網Tutorial的示例:http://www.py2exe.org/index.cgi/Tutorial
此處我的setup.py文件如下:
# coding=utf8 from distutils.core import setup import py2exe extra_modules = ["bs4"] options = {"py2exe": {"compressed": 1, "optimize": 2, "bundle_files": 1, # 表示把所有文件打包進exe可執行程序 "packages": extra_modules, #"includes": extra_modules } } setup( version = "1.0.0", description = "test for py2exe", name = "Py2exeTest", options = options, zipfile = None, console = [{"script": "app_main.py"}] )
其中幾個重要的參數:
console = [{"script": "app_main.py"}] 表示這是個控制台程序,希望把app_main.py打包成exe程序。我的工程中有多個py源文件,此處只需要指定入口py文件即可,py2exe會把其它py文件自動導入。
zipfile = None 默認py2exe會生成一個library.zip的庫文件;此處為None,則不生成改文件,把它打包到exe文件。
"packages": extra_modules 指定依賴的其它模塊。我用到的beautifulsoup,所以這里指定bs4。這里我用"includes": extra_modules也沒問題,沒有細究二者的區別。
"bundle_files": 1 表示要把所有文件打包成一個 exe可執行程序
3. 生成exe文件
在setup.py目錄,執行python setup.py py2exe命令即可。
執行成功會在同目錄下生成build和dist兩個目錄。build是py2exe執行的中間過程,可以刪掉。dist是生成的exe文件,如下:
其中app_main.exe是我的程序,執行即可。w9xpopen.exe是py2exe自動生成。
4. 問題
(1)ImportError: No module named bs4
打包過程中碰到一個問題"ImportError: No module named bs4",后來上網一查發現問題比較普遍。但解決過程還是小有波折,因此記錄一下。
現象:打包成exe過程順利,但是執行過程中出現ImportError問題,bs4模塊找不到。
上網找解決方案,有一篇文章說是需要在app_main.py中顯示指定import bs4,否則py2exe會被"欺騙",誤以為用不到bs4模塊,不會打包。嘗試了該方法,問題依舊,沒有解決。
之后再找,說是需要在setup.py中指定這種額外的依賴模塊,"includes":["bs4"]。遂修改setup.py,不僅用了includes參數,還用了packages參數。出現新的問題,打包過程中就出現"ImportError: No module named bs4"問題。問題仍無法解決。
后來再找,看到一網友的回帖,感覺可能是beautifulsoup的安裝py2exe不識別。我發現python的Lib/site-packages下安裝的是egg文件,beautifulsoup4-4.4.0-py2.7.egg。用winrar將其解壓,把bs4目錄直接放到Lib/site-packages下,再打包並執行,一切正常。問題解決。
可見,py2exe無法識別egg文件,需要解壓使用。
(2)NameError: name '__file__' is not defined
工程中使用了os.path.dirname(os.path.realpath(__file__))來找到py文件所在目錄的絕對路徑。但是打包成exe以后執行,出現“NameError: name '__file__' is not defined”的問題。上網查找,stackoverflow中有人提到:“Scripts running under py2exe do not have a __file__
global. Detect this and use sys.argv[0]
instead”。因此使用os.path.dirname(os.path.abspath(sys.argv[0]))替代__file__,打包以后使用正常。