python - scrapy上的Pyinstaller错误?
问题描述
我正在使用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 不包含在运行 Pyinstaller 时产生的最终 .exe (Windows)、.app (macOS)、文件夹等中找不到的模块或文件。
所以,这就是发生的事情:
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/_MEIbxALM3/scrapy/VERSION'
您运行了冻结/独立程序。一旦你这样做了,你的程序就会被“解压”到你计算机上一个新的临时文件夹中/temp/_MEIbxALM3/
。该文件夹包含 Python 解释器、程序的源代码和 Pyinstaller 设法找到的模块(以及一些其他必要的文件)。
Scrapy 模块不仅仅是一个模块。它是一个完整的框架。它有自己使用的纯文本文件(Python 文件除外)。而且,它本身会导入很多模块。
Scrapy 框架尤其不能与 Pyinstaller 相处,因为它使用许多方法来导入 Pyinstaller 无法“看到”的模块。此外,Pyinstaller 基本上不会尝试在最终构建中包含不是 .py 文件的文件,除非您告诉它.
那么,究竟发生了什么?
存在于您计算机上的“普通”scrapy 模块(您使用 pip 或 pipenv 安装)中的文本文件“VERSION”未包含在程序构建中的山寨 scrapy 模块中。Scrapy 需要这个文件;Python 为您提供了,FileNotFoundError
因为它从未被包含在内。因此,您必须使用 Pyinstaller 将该文件包含在程序的构建中。
你如何告诉 Pyinstaller 在哪里可以找到模块和文件?
这个人说只需将丢失的文件从计算机上的安装位置复制到从 Pyinstaller 吐出的构建文件夹中。这确实有效。但是,有一个更好的方法,Pyinstaller 可以为你做更多的工作(防止你可能得到更多ImportError
的 s 和s)。FileNotFoundError
见下文:
build.spec
文件是你的朋友
spec
文件只是 Pyinstaller 使用的 Python 文件,就像配置文件一样告诉它如何构建程序。在此处阅读有关它们的更多信息。下面是一个真实build.spec
文件的示例,我最近使用 Windows 的 GUI 构建了一个 Scrapy 程序(我的项目名称是BOT 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 的钩子功能的更多信息。在该hooks/
目录中有一个 Scrapy 的挂钩文件。这将告诉 Pyinstaller 包含许多模块和文件,否则如果您不使用文件,它会丢失.spec
。这是迄今为止我在这里写的最重要的东西。如果不执行此步骤,ImportError
每次尝试运行使用 Pyinstaller 构建的 Scrapy 程序时,都会不断收到 s。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
文件后,你需要做的就是在你的 shell 提示符下运行 Pyinstaller:
pyinstaller build.spec
然后,Pyinstaller 应该会吐出一个可以正常工作的程序的正确构建。问题解决了。
那些在谷歌上寻找这个问题的答案或 Pyinstaller 或 Scrapy 的任何问题的人,祈祷你找到我的答案。
推荐阅读
- excel - 当只有 1 行数据可见时出现运行时错误
- javascript - 单个画布上的多个 WebGLRenderer
- laravel-5 - 如何执行具有默认输入的变量函数
- javascript - 如何在 Component 中使用 StyledComponents 主题
- python - 如何使用 list_objects_v2 从 S3 获取超过 1000 个对象?
- sh - 如何将命令行参数传递给 kdb 函数
- perl - Perl:正确引用所有特殊字符
- dart - onTap 不适用于 ListWheelScrollView 子项 - Flutter
- python - 如何将 Numpy ndarray 分成块
- r - 使用 R 根据指定条件将日期转换为日期范围