python 从 zip 文件 import 包 zipimport

创建日期: 2024-04-16 15:00 | 作者: 风波 | 浏览次数: 16 | 分类: Python

参考: - https://docs.python.org/zh-cn/3/library/zipimport.html - zipimport --- 从 Zip 存档中导入模块 - https://stackoverflow.com/questions/30032686/how-to-run-a-python-script-from-a-password-protected-zip - 从加密 zip 文件中 import 文件 - https://github.com/Dakkaron/ArchiveImporter/tree/master - 从加密 zip 文件中 import 文件

1. 创建一个可导入的 zip 文件

1.1 目录结构

例如 code 目录是一个 package 目录

code/
code/__init__.py
code/hello.py

1.2 创建压缩包

创建一个加密的 zip 压缩包

cd code &&
zip -r -e ../xxx.zip *

方法一:使用 ArchiveImporter import zip 包(可能有缺陷)

不太搞的懂 ArchiveImporter,貌似有缺陷

import sys
from ArchiveImporter import addZip

addZip(sys.argv[1], password='Hello@World')

import hello

hello.say()

方法二:使用 zipimport

参考:https://learnku.com/docs/pymotw/zipimport-load-python-code-from-zip-archives/3494

需要把官方的 zipimport 包中的 _get_data 函数替换掉,以便有办法使用密码解密文件。

import zipimport
import zipfile

pwd = 'Hello@World'

def _get_data(archive, toc_entry, fullname=None):
    datapath, compress, data_size, file_size, file_offset, time, date, crc = toc_entry
    fullpath = datapath[len(archive) + 1:] 
    #logger.debug(f"archive: {archive} , toc_entry: {toc_entry} , fullpath: {fullpath}")

    with zipfile.ZipFile(archive) as arch:
        with arch.open(fullpath, pwd=pwd.encode()) as file:
            data = file.read()
            #logger.debug(str(data))
            return data
zipimport._get_data = _get_data


importer = zipimport.zipimporter('./service.zip')
module = importer.load_module('syncapi')

app.register_blueprint(module.app, url_prefix='/api')

方法三:从字符串导入包 loader hooks(未验证)

来源:https://stackoverflow.com/questions/65009309/dynamically-import-module-from-memory-in-python-3-using-hooks

import importlib
import sys
import types


class StringLoader(importlib.abc.Loader):

    def __init__(self, modules):
        self._modules = modules

    def has_module(self, fullname):
        return (fullname in self._modules)

    def create_module(self, spec):
        if self.has_module(spec.name):
            module = types.ModuleType(spec.name)
            exec(self._modules[spec.name], module.__dict__)
            return module

    def exec_module(self, module):
        pass


class StringFinder(importlib.abc.MetaPathFinder):

    def __init__(self, loader):
        self._loader = loader

    def find_spec(self, fullname, path, target=None):
        if self._loader.has_module(fullname):
            return importlib.machinery.ModuleSpec(fullname, self._loader)


if __name__ == '__main__':
    modules = {
        'my_module': """
    BAZ = 42

    class Foo:
        def __init__(self, *args: str):
            self.args = args
        def bar(self):
            return ', '.join(self.args)
    """}

    finder = StringFinder(StringLoader(modules))
    sys.meta_path.append(finder)

    import my_module
    foo = my_module.Foo('Hello', 'World!')
    print(foo.bar())
    print(my_module.BAZ)
16 浏览
13 爬虫
0 评论