scrapy 上的 Pyinstaller 错误?

Pyinstaller error on scrapy?

我正在使用 scrapy 导入它。我使用 pyinstaller 构建了 python 文件。构建后我 运行 文件 ./new.py。但是错误弹出:

 FileNotFoundError: [Errno 2] No such file or directory: '/tmp/_MEIbxALM3/scrapy/VERSION'
[23450] Failed to execute script new

您在构建独立程序时没有正确使用 Pyinstaller。这是 Pyinstaller 工作原理的简短外行描述:Pyinstaller 捆绑了 Python 解释器、必要的 DLL(对于 Windows)、项目的源代码和 所有它可以找到 的模块到文件夹或自解压可执行文件中。 Pyinstaller 不包含它在最终的 .exe (Windows)、.app (macOS)、文件夹等中找不到的模块或文件,当您 运行 Pyinstaller.

所以,事情是这样的:

 FileNotFoundError: [Errno 2] No such file or directory: '/tmp/_MEIbxALM3/scrapy/VERSION'

你 运行 你的 frozen/stand-alone 程序。一旦你这样做了,你的程序就会 'extracted' 到你计算机上的一个新的临时文件夹 /temp/_MEIbxALM3/。此文件夹包含 Python 解释器、程序的源代码和 Pyinstaller 设法找到的模块(加上其他几个必要的文件)。

Scrapy 模块不仅仅是一个模块。它是一个完整的框架。它有自己使用的纯文本文件(除了 Python 文件)。而且,它自己导入了很多模块。

Scrapy 框架尤其不能与 Pyinstaller 相处,因为它使用许多方法来导入 Pyinstaller 无法导入的模块 'see'。此外,Pyinstaller 基本上不会尝试在最终构建中包含非 .py 文件的文件 ,除非你告诉它

那么,真的发生了什么?

您计算机上的 'normal' scrapy 模块中存在的文本文件 'VERSION'(您使用 pip 或 pipenv 安装的)未包含在您构建的 copycat scrapy 模块中程序。 Scrapy 需要这个文件; Python 给你的是 FileNotFoundError,因为它从未被包括在内。因此,您必须在使用 Pyinstaller 构建程序时包含该文件。

你如何告诉 Pyinstaller 在哪里可以找到模块和文件?

This guy 说只需将丢失的文件从它们在计算机上的安装位置复制到从 Pyinstaller 吐出的构建文件夹中。这确实有效。但是,有一种更好的方法,Pyinstaller 可以为您做更多的工作(防止您可能得到进一步的 ImportErrors 和 FileNotFoundErrors)。见下文:

build.spec 文件是你的朋友

spec 文件只是 Pyinstaller 使用的 Python 文件,就像配置文件一样,告诉它如何构建程序。阅读更多关于它们的信息 here。下面是一个真实的 build.spec 文件的示例,我最近使用它来为 Windows 构建带有 GUI 的 Scrapy 程序(我的项目名称是 B.O.T。Bot):

import gooey
gooey_root = os.path.dirname(gooey.__file__)
gooey_languages = Tree(os.path.join(gooey_root, 'languages'), prefix = 'gooey/languages')
gooey_images = Tree(os.path.join(gooey_root, 'images'), prefix = 'gooey/images')
a = Analysis(['botbotgui.py'],
             pathex=['C:\Users\Colton\.virtualenvs\bot-bot-JBkeVQQB\Scripts', 'C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x86'],
             hiddenimports=['botbot.spiders.spider'],
             hookspath=['.\hooks\'],
             runtime_hooks=None,
             datas=[('.\spiders\','.\spiders\'), ('.\settings.py','.'),
                    ('.\scrapy.cfg','.'), ('.\items.py','.'), ('.\itemloaders.py','.'),
                    ('.\middlewares.py','.'), ('.\pipelines.py','.')
                   ]
             )
pyz = PYZ(a.pure)

options = [('u', None, 'OPTION'), ('u', None, 'OPTION'), ('u', None, 'OPTION')]

exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          options,
          gooey_languages, # Add them in to collected files
          gooey_images, # Same here.
          name='BOT_Bot_GUI',
          debug=False,
          strip=None,
          upx=True,
          console=False,
          windowed=True,
          icon=os.path.join(gooey_root, 'images', 'program_icon.ico'))

#coll = COLLECT(exe,
    #a.binaries,
    #a.zipfiles,
    #a.datas,
    #options,
    #gooey_languages, # Add them in to collected files
    #gooey_images, # Same here.
    #name='BOT_Bot_GUI',
    #debug=False,
    #strip=False,
    #upx=True,
    #console=False,
    #windowed=True,
    #icon=os.path.join(gooey_root, 'images', 'program_icon.ico'))

如果您想构建一个文件夹而不是独立的 .exe,请取消注释最后一个区域。这是一个特定于我的计算机和项目结构的配置文件。因此,在您的文件中,您必须更改一些内容(例如 pathex 告诉 Pyinstaller 在 Windows 10 上的哪里可以找到 DLL。但是,前提是相同的。

我的项目目录如下所示:

botbotgui.py  botbot.py  hooks  images  __init__.py  itemloaders.py  items.py  middlewares.py  pipelines.py  __pycache__  scrapy.cfg  settings.py  spiders

特别注意 hooks/ 目录。使用钩子可以让你免去很多麻烦。阅读更多关于 Pyinstaller 的挂钩功能 here。在 hooks/ 目录中有一个 Scrapy 的钩子文件。这将告诉 Pyinstaller 包含许多模块和文件 如果您不使用 .spec 文件,否则它会错过 这是迄今为止我在这里写的最重要的东西。 如果你不做这一步,你每次尝试 [=106= 时都会得到 ImportErrors ] 使用 Pyinstaller 构建的 Scrapy 程序。 Scrapy 导入了许多 Pyinstaller 遗漏的模块。

hook-scrapy.py(注意:你的钩子文件必须这样命名。):

from PyInstaller.utils.hooks import collect_submodules, collect_data_files

# This collects all dynamically imported scrapy modules and data files.
hiddenimports = (collect_submodules('scrapy') +
                 collect_submodules('scrapy.pipelines') +
                 collect_submodules('scrapy.extensions') +
                 collect_submodules('scrapy.utils')
)
datas = collect_data_files('scrapy')

在你写完一个合适的 build.spec 文件后,你需要做的就是 运行 Pyinstaller 在你的 shell 提示符下这样:

pyinstaller build.spec

Pyinstaller 然后应该吐出一个应该工作的程序的正确构建。问题已解决。