【问题标题】:How to make an exe for python script that uses weasyprint?如何为使用 weasyprint 的 python 脚本制作 exe?
【发布时间】:2020-08-28 13:35:53
【问题描述】:

我想为我的小项目制作一个 exe 文件。但它根本不运行。

我试过PyInstaller does not include dependency file 但它会抛出

Traceback (most recent call last):
  File "C:\Program Files\Python37\Scripts\pyinstaller-script.py", line 11, in <module>
    load_entry_point('PyInstaller==3.4', 'console_scripts', 'pyinstaller')()
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\__main__.py", line 111, in run
    run_build(pyi_config, spec_file, **vars(args))
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\__main__.py", line 63, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\building\build_main.py", line 838, in main
    build(specfile, kw.get('distpath'), kw.get('workpath'), kw.get('clean_build'))
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\building\build_main.py", line 784, in build
    exec(text, spec_namespace)
  File "<string>", line 8, in <module>
IndexError: list index out of range

如果我只是执行“pyinstaller --clean --onefile Start.py”,它会说:

  File "Start.py", line 5, in <module>
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "Modules\HTMLToPDF.py", line 1, in <module>
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\weasyprint\__init__.py", line 20, in <module>
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\cssselect2\__init__.py", line 20, in <module>
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\cssselect2\compiler.py", line 7, in <module>
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\tinycss2\__init__.py", line 10, in <module>
  File "pathlib.py", line 1189, in read_text
  File "pathlib.py", line 1176, in open
  File "pathlib.py", line 1030, in _opener
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\Daniel\\AppData\\Local\\Temp\\_MEI100202\\tinycss2\\VERSION'
[12796] Failed to execute script Start

我该如何解决?我只是想要一种很好的方式来分发我的代码。

【问题讨论】:

标签: python pyinstaller weasyprint


【解决方案1】:

老实说,您的项目很大,并且有许多复杂的库,因此 PyInstaller 无法单独处理所有这些库。在这里我告诉你一些解决方法。

首先,当 PyInstaller 抱怨缺少文件时,这意味着您需要手动输入该文件。例如,在您的错误中,它抱怨缺少一个名为 VERSION 的文件,该文件应该存在于 C:\\Users\\Daniel\\AppData\\Local\\Temp\\_MEI100202\\tinycss2 中,但事实并非如此。您需要自己将其添加为数据文件。

其次,如果你需要带一些外部依赖,比如cairo,你需要用Tree函数带上整个依赖目录。你可以找到更多关于here的信息。

我构建了项目并修复了其中一些依赖项,因此它不再显示有关丢失这些文件的错误,我还在整个项目中添加了 try/except 以便能够跟踪丢失的文件,这可能会有所帮助。 我刚刚将丢失的文件和一些 hiddenimports 添加到规范文件中,所以你需要处理这些。

Start.py:

import traceback
try:
    """
    Whole Start.py script
    """
except Exception:
    traceback.print_exc()
    while(True):
        pass

Start.spec:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['Start.py'],
             pathex=['C:\\Users\\Daniel\\Desktop\\SOAPUIReportingTool-master\\soap'],
             binaries=[],
             datas=[
                 ("C:\\Program Files\\Python37\\Lib\\site-packages\\tinycss2\\VERSION", "tinycss2"),
                 ("C:\\Program Files\\Python37\\Lib\\site-packages\\cairocffi\\VERSION", "cairocffi"),
                 ("C:\\Program Files\\Python37\\Lib\\site-packages\\\weasyprint\\VERSION", ".")
                     ],
             hiddenimports=["tinycss2", "matplotlib", "weasyprint"],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='Start',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=False,
          runtime_tmpdir=None,
          console=True )

【讨论】:

  • 我必须添加我的配置文件和一些额外的库,但它现在可以工作了。 ("C:\\Program Files\\Python37\\Lib\\site-packages\\weasyprint\\css\\html5_ua.css", "css"), ("C:\\Program Files\\Python37\\ Lib\\site-packages\\weasyprint\\css\\html5_ph.css", "css") shutil.copyfile('config.cfg', '{0}/config.cfg'.format(DISTPATH))跨度>
【解决方案2】:

对于将来试图让 WeasyPrint 在 WINDOWS 10 上与 PyInstaller 一起工作的任何人;我发现以下方法非常有用:

  • 创建一个将使用 pyinstaller 构建的调试脚本
import sys,traceback
try:
    import weasyprint
    print(weasyprint.__version__)
except:
    print(sys.exc_info())
    print(traceback.format_exc())
finally:
    input('Press enter to exit the program: ')

现在尝试构建:

pyinstaller main.py --name=test --log-level ERROR --clean

它可能会抱怨缺少模块。这是我在数小时的反复试验中混合和匹配方法的地方,我将提供如何包含这些缺失模块的解决方案,然后是我的最终规格表和方法。

  • 钩子:要包含那些缺失的模块,请创建以下“钩子”文件夹:
\main.py
\hooks

在此文件夹中,您将使用以下脚本引入 python 文件,您将其命名为 'hook-{NAMEOFMISSINGMODULE}.py'

from PyInstaller.utils.hooks import collect_data_files


def hook(hook_api):
    hook_api.add_datas(collect_data_files(hook_api.__name__))

因此:

\main.py
\hooks
  \hook-cssselect2.py
  \...

您将在 PyInstaller 命令中包含这些文件:

pyinstaller main.py --name=test--log-level ERROR --clean --additional-hooks-dir=hooks
  • 附加数据:我发现当它抱怨在 weasyprint 的特定文件夹中找不到 VERSION 或特定文件时;我将导航到我的 Python 安装中丢失的数据,然后将地址复制到它并在 PyInstaller 命令中使用分号后跟文件夹名称来实现它:
pyinstaller main.py --name=test--log-level ERROR --clean --add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\weasyprint\css\html5_ph.css;css --additional-hooks-dir=hooks

如果您遇到无法在您的 _MEIXXXXX 文件夹中找到 VERSION 文件的投诉;它正在您的 weasyprint 包中寻找 VERSION 文件。正确的 --add-data 行如下:

--add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\weasyprint\VERSION;.

注意分号后跟“.”。这告诉 PyInstaller 在您打开始终称为 _MEI{somerandomnumbers} 的 exe 时将该文件包含在 PyInstaller 创建的临时文件夹中。

使用这些方法,您最终应该会成功,并会看到 weasyprint 的版本号。 我的最终工作命令行如下:

pyinstaller main.py --name=test--log-level ERROR --clean --add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\pyphen;pyphen\dictionaries --add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\weasyprint\css\html5_ph.css;css --add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\weasyprint\css\html5_ua.css;css --add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\weasyprint\VERSION;. --add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\cairocffi;cairocffi  --additional-hooks-dir=hooks

带有以下钩子:

\main.py
\hooks
  \hook-cairocffi.py
  \hook-cssselect2.py
  \hook-tinycss2.py

这也适用于 onefile 模式。

我很清楚我可能对 hooks 和 add-data 做同样的事情;就像我说的那样,我正在混合和匹配方法,直到最终奏效。我相当有信心仅使用其中一种方法就可以达到相同的效果,但我认为在我已经花费了太多时间的情况下浪费时间进行调查是不值得的。

感谢所有其他 stackoverflow 用户和 weasyprint 创建者多年来在多个帖子中提供的答案,我最终能够为自己积累成一个工作版本。

如果这有助于 +1 或发表评论,因为这是谷歌搜索“Pyinstaller weasyprint”时出现的第一个答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-23
    • 2015-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多