吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2016|回复: 16
收起左侧

[Python 原创] 下载离线包及依赖包并按依赖关系生成安装批处理

[复制链接]
ccber 发表于 2023-10-5 22:16
应用场景:单位的电脑是局域网不能连外网,想要用python还必要通过离线的方式安装各种各样的包,把各种离线文件带过去还需要一个一个install,而且如果依赖关系没有弄清楚还不能一次到位。虽然能用freeze导出requierment的方式批量安装,但是实际操作上会有中途失败、而且有不想要的包的情况。对此自己想着开发一款自己想要什么包就下载什么样的离线文件,同时用一个批处理就能事项一次性install所有依赖包的程序。所以就编写了本代码。

实现原理:根据录入情况离线下载包文件,再通过pip show命令逐个包检查依赖关系,并按依赖深度从深到浅的顺序形成列表,再将列表的包名和离线文件的包名进行匹配,把离线文件的顺序按照依赖关系由深到浅写入批处理文件install.bat。

可以进一步改进的地方:就是递归调用pip show的时候会有阻塞感,但是不懂如何在递归中应用多线程,有大佬的可以提供建议。离线文件名和包名可能会有特殊情况发生会有暴雷的潜在危机。

代码如下:
[Python] 纯文本查看 复制代码
import os
import re
import subprocess

#根据你要下载的包名(packageName),利用pip show命令,递归查找依赖关系,并形成(包名,层次)的列表packageList
def GetDepPackage(packageName,packageList,deepth):
    #执行pip show 命令
    result = subprocess.run("pip show "+packageName, capture_output=True, text=True).stdout
    #根据输出结果截取出requires字段,并将依赖包存到packages列表
    beginString="Requires:"
    beginPos=result.find(beginString)+len(beginString)
    endString="\n"

    requeiresString=result[beginPos:result.find(endString,beginPos)]
    packages = requeiresString.replace(' ', '').split(',')

    #递归查找依赖关系,形成(包名,层次)的列表packageList
    #统一包名的下划线和横杠的设置,避免包名和文件名存在不一致的情况
    if packages[0]=='':
        packageName=packageName.replace("_","-")
        packageList.append((packageName,deepth))
    else:
        for perPackage in packages:
            GetDepPackage(perPackage,packageList,deepth+1)
        packageName=packageName.replace("_", "-")
        packageList.append((packageName,deepth))

#构建install.bat文件
def BuildBatFileFromList(packageList,packageFileList,downPath):
    #设置install.bat文件名
    batFileName=os.path.join(downPath,"install.bat")
    #根据依赖关系的包列表packageList,匹配出依赖先后顺序的离线文件,按依赖先后为顺序写入bat批处理
    for perPackageList in packageList:
        for index,perFileName in enumerate(packageFileList):
            perRepalcedFileName=perFileName.replace("_","-")
            packageName,deepth=perPackageList
            pattern = r"-\d+."
            matched = re.search(pattern, perRepalcedFileName)
            perRepalcedFileName=perRepalcedFileName[:matched.start()]
            if perRepalcedFileName==packageName:
                with open(batFileName,"a") as batFile:
                    batFile.write("pip install "+perFileName+"\n")
                packageFileList.pop(index)
                break

    #如果存在离线包文件没能和包名匹配的上,那么将这些离线文件放置到bat批处理的头部。
    for index,perFileName in enumerate(packageFileList):
        with open(batFileName, "r+") as batFile:
            content=batFile.read()
            content="pip install " + perFileName + "\n"+content
            batFile.seek(0)
            batFile.write(content)
    print(batFileName,"已生成:")
    #输出install.bat的内容
    with open(batFileName, "r") as batFile:
        content = batFile.read()
        print(content)

if __name__ == '__main__':
    while True:
        globalPackageName=input("请输入你要下载的包名:")
        #创建离线安装包的文件夹和下载离线文件
        downPath = os.path.join(u"D:\\测试\\", globalPackageName)
        downPathIsExistsed=False
        if os.path.exists(downPath):
            downPathIsExistsed = True
        command = "pip download " + globalPackageName + " -i https://pypi.tuna.tsinghua.edu.cn/simple/ -d " + downPath
        print("开始执行下载"+globalPackageName+"命令,需要一定的下载时间:\n"+command)
        result = subprocess.run(command, capture_output=True, text=True,encoding="utf-8").stdout
        print(result)
        if result.find("Successfully")==-1:
            print("下载"+globalPackageName+"出现错误")
            if downPathIsExistsed==False:
                os.remove(downPath)
            continue

        #根据指定的包,创建依赖包列表
        packageList = []
        GetDepPackage(globalPackageName,packageList,0)
        #对依赖包列表根据被依赖关系进行前后排序
        packageList.sort(key=lambda x: x[1], reverse=True)
        print(packageList)

        #根据依赖包列表按依赖关系顺序匹配离线文件,并构造批处理文件
        packageFileList = os.listdir(downPath)
        BuildBatFileFromList(packageList,packageFileList,downPath)

免费评分

参与人数 3吾爱币 +9 热心值 +2 收起 理由
hrh123 + 1 + 1 用心讨论,共获提升!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
福多多 + 1 电网上过班,系统名堂多.直接封装系统.

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

罗萨 发表于 2023-10-6 21:57
本帖最后由 罗萨 于 2023-10-6 21:59 编辑
ccber 发表于 2023-10-6 18:46
不能。内部网管策略比较严,同时,内网文件夹贡献是不是也建立在有离线文件的基础上?


没有啊,相当于把东西存在内网一台电脑上,要的时候,从那台电脑拖过来就行了

这个内网共享有啥管的,再不行,内网找台电脑,做个 iis, 开网站就能直接内网下载

那你这软件,还不是相当于下载

你这都内网插U盘设备了,共享有啥问题
 楼主| ccber 发表于 2023-10-6 18:45
lookfeiji 发表于 2023-10-6 12:16
递归加多线程。。。。不得绕晕啊,好像蛮有用的,学习一下

因为我这个程序中的递归要用到pip show命令是需要联网的,会有较大的阻塞。如果能有多线程可能会快一些,但是会有你说的绕晕的。
贝木尼舟 发表于 2023-10-6 10:59
 楼主| ccber 发表于 2023-10-6 11:06

先在venu安装包,再freeze,接着再下载离线包么?
xlinux 发表于 2023-10-6 11:50
不错!!!!!!!!!!!!
lookfeiji 发表于 2023-10-6 12:16
递归加多线程。。。。不得绕晕啊,好像蛮有用的,学习一下
Courser 发表于 2023-10-6 13:13
ccber 发表于 2023-10-6 11:06
先在venu安装包,再freeze,接着再下载离线包么?

venv里面的包都是项目本身要用的包,直接打包整个文件夹就行,不用在安装了
罗萨 发表于 2023-10-6 13:24
不能在内网某台电脑做内网文件夹共享吗?
xaibin 发表于 2023-10-6 16:00
我之前遇到的问题大概相同,不过我当时用了无线网卡临时给连网解决了。
 楼主| ccber 发表于 2023-10-6 18:46
xaibin 发表于 2023-10-6 16:00
我之前遇到的问题大概相同,不过我当时用了无线网卡临时给连网解决了。

我们内部有网管软件不能接无线网卡。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 08:06

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表