作为独霸江湖数年的天下第一大剑客,python已经拥有太多的小弟-子模块了,pypi上有几十万个!
我们使用中,经常使用固定的一些模块,但是进场进行更新电脑,移机,重新安装等各种情况下的非个人意愿操作,这时候重新一个一个进行模块安装,尤其是进行对应模块版本的安装就比较麻烦,比如,断网了,不如新服务器未联网,比如网卡坏了,比如在深山里面和心爱的朋友度假(当然没有网络了),。。。。。。这时候唯一的方法就是进行模块的离线安装!
没错,今天的主题就是离线处理我们的轮子们! 什么,你不知道轮子,汽车总见过吧,对就是这个轮子,python中也叫做脱机模块安装包。
- 获取当前环境的模块配置:至少有2中方式可以获得模块信息列表
pip list >>d:\requirements.txt 或者
pip freeze >>d:\requirements.txt
这样,我们得到了当前环境的所有模块列表,以及当前的版本号
打开文件requirements.txt,主要内容如下所示:
opcua-client0.8.4
opcua-widgets0.6.1
opencv-contrib-python4.5.5.64
opencv-python4.5.4.60
opencv-python-headless4.5.4.60
openpyxl3.0.9
opt-einsum3.3.0
outcome1.1.0
packaging21.3
paddle-bfloat0.1.7
paddlepaddle2.3.1
pandas1.4.1
` - 下载轮子们(脱机安装包):
根据requirements文件内容,我们可以进行本地化下载模块。执行命令
pip download pandas==1.4.1
将会下载脱机安装包(我们的轮子)到当前目录下。 - 进行安装,最好直接切换到轮子所在的目录下,执行指令:
pip install pandas==1.4.1
即可进行脱机安装 - 问题来了,如果有900个模块,是不是要累死了?累不死的话,至少关节炎肯定跑不掉的。我们该怎样避免自我伤害呢? 我们可以自动化…
- 我们使用python来实现自我迭代的自动化,就像是银行收到我们的存款,然后再贷给我们一样的骚操作。
- 新建一个程序,就像爱护我们的女票一样,给她一个美好的名字,比如operatePythonModulesAutomation.py,是不是很骚气?有长又大小写的…
- 给心目中的女票operatePythonModulesAutomation.py添加漂亮花哨的操作代码,主要分为三部分:主程序,操作部分,自动升级部分,另外的 fi __name__不算在里面,因为这个和女票的包包一样,是必不可少的。
- 主程序可以简单进行交互,如下示例,完成参数的输入:
def main():
'''
生成requirement.txt文件;
根据requirement文件下载安装包/轮子到当前目录下;
并且可以进行自动安装(.whl,.tar.gz,.zip),升级等奥做。
'''
print('运行本程序前,需要已经安装python,并且设置好python的path路径。只针对安装包进行操作。')
print('isDownload=True,根据输入的文件列表,将下载的离线安装包/轮子保存到当前目录下。后续可以手动安装。')
print('isAutoInstall=True,根据输入的文件列表,将自动从固定的站点("https://pypi.douban.com/simple")安装包/轮子。需要手动执行生成的bat文件')
print('isUpgrade=True,根据输入的文件列表,将自动从固定站点("https://pypi.douban.com/simple")安装包/轮子的升级包。需要手动执行生成的bat文件')
print('支持 pip freeze > requirements.txt 或者 pip list >>e:\piplist.txt 输出的模块列表文件格式')
print('自动生成.bat文件,直接执行该文件即可进行自动安装/下载/升级,也可以使用autoExecuteBat参数进行生成bat后的自动执行')
print('下面开始输入需要的参数:')
choice,right=getChoice()
while not right:
choice,right=getChoice()
infile=r'e:\piplist.txt'
outfile=r'e:\requirements.bat'
auto='n' #自动执行生成的bat文件
if(choice>=0 and choice<=4):
file=input(r"输入模块列表文件路径和文件名称(default='e:\piplist.txt'):")
if file=='':
file=infile
infile=file
file=input(r"输入.bat文件的路径和文件名称(default='e:\requirements.bat'):")
if file=='':
file=outfile
outfile=file
auto=input(r"自动执行生成的bat文件?y/n:")
elif (choice==5):
file=input(r"输入需要安装的python模块离线包文件的路径(default='e:\packages'):")
if file=='':
file='e:\packages'
infile=file
elif (choice>=6 and choice <=7):
file=input(r"输入需要保存的当前计算机python模块列表文件的路径和文件名称(default='e:\requirements.txt'):")
if file=='':
file='e:\requirements.txt'
outfile=file
if(auto.lower()=='y'):
isAutoRunBat=True
else:
isAutoRunBat=False```
9. 操作部分是核心,进行自动项目的执行,如下:
```csharp
def OperateOfflinePythonModules(inputFile='requirements.txt',outputfile="./downloadofflinemodules.bat" \
,operate=0,autoExecuteBat=False):
'''根据选择自动生成python模块的批处理下载/安装/升级程序'''
global requirementFile,modulesSource
'''请输入选择的操作:
0. 生成手动下载python模块的批处理
1. 生成自动下载python模块的批处理
2. 生成自动下载python模块的批处理,并进行模块升级
3. 生成自动升级python模块的批处理
4. 生成手动下载指定版本python模块的批处理
5. 自动安装指定路径下的离线包
6. 生成本地计算机的pthon离线包文件:pip list >>file
7. 生成本地计算机的pthon离线包文件:pip freeze >>file
8.
'''
if operate==0:
isDownload=True;isAutoInstall=False;isUpgrade=False
elif operate==1:
isDownload=False;isAutoInstall=True;isUpgrade=False
elif operate==2:
isDownload=False;isAutoInstall=True;isUpgrade=True
elif operate==3:
isDownload=False;isAutoInstall=False;isUpgrade=True
elif operate==4:
isDownload=True;isAutoInstall=False;isUpgrade=False
elif operate==5:
return instalModules(inputFile)
elif (operate>=6 and operate <=7):
if(operate==6):
exe=f'pip list >>{outputfile}'
elif(operate==7):
exe=f'pip freeze >>{outputfile}'
ret=os.system(exe)
return ret,True
if inputFile=='':
inputFile=requirementFile
if outputfile=='':
outputfile=outputFile
lines=[]
with open(inputFile,'rt',encoding='utf-8') as file:
firstline=file.readline()
if(firstline.find('==')<0): #使用的时pip list >>e:\piplist.txt 命令得到的模块列表
for line in file:
sa=line.split()
if(sa[1].replace(".","").isdigit()):
lines.append('=='.join(sa))
else:
lines=file.readlines() #使用pip freeze > requirements.txt 得到模块列表
for i in range(0,len(lines),1):
if(isDownload):
if(operate==0):
newline='pip download '+lines[i].split('==')[0] +f' -i {modulesSource} \n'
if(operate==4):
newline='pip download '+lines[i].removesuffix('\r').removesuffix('\n') +f' -i {modulesSource} \n'
lines[i]=newline
else:
if(isAutoInstall):
newline='pip install '+lines[i] +f' -i {modulesSource} \n'
if(isUpgrade):
newline=newline +'pip install '+lines[i].split('==')[0] +f' --upgrade -i {modulesSource} \n'
lines[i]=newline
else:
if(isUpgrade):
lines[i]='pip install '+lines[i].split('==')[0] +f' --upgrade -i {modulesSource} \n'
with open(outputfile,'wt',encoding='utf-8') as file:
file.writelines(lines)
if(autoExecuteBat):
if(outputfile.endswith('.bat')):
os.system(outputfile)
return True
- 自动升级部分 ,可以减少我们的手动操作,实现脱机安装的自动化,如下示例:
- 看到这里,施主和我肯定很有缘分了,至少我们又共同的目标和理想,还有共同的兴趣爱好。我们也都会进行抛砖引玉,希望我们的一点点努力,能够让这个世界更加美好一点点,然后聚沙成塔,集腋成裘,使得我们,我们的未来,充满憧憬和希冀,然后明天周一进行努力搬砖的动力,就会更加多一点点,没错,就是那个点点.
- 综合以上,我们实现一个整体的简单自动化模块脱机安装程序,基本完整代码如下:
#coding=utf-8
'''
author: lc.addverb
date:2022-07-17
version: vscode+python3.10
target:根据requirement.txt文件自动生成手动下载离线安装包
status:ok
注意:opencv版本要求opencv-python-headless<=4.5.4.60 :pip install opencv-python==4.5.4.60
若出现模块安装完毕但是不能使用时,需要uninstall模块后再次重新安装
从https://gitcode.net/mirrors/JaidedAI/EasyOCR?utm_source=csdn_github_accelerator 下载zip包,解压后在cmd中切换到当前路径,执行Python setup.py install 进行自动安装。然后可以使用。
使用pip install 模块名称,模块名称来安装缺乏的模块,建议使用国内源 -i https://pypi.douban.com/simple -i https://pypi.tuna.tsinghua.edu.cn/simple
生成exe程序,请执行: pyinstaller -F -i logo.ico PythonModulesOperate.py 。在当前目录下的dist文件夹中生成一个文件的exe程序,使用指定的icon图标
'''
import os,sys,shutil
import zipfile,gzip,tarfile,rarfile
requirementFile='requirements.txt'
outputFile="./downloadofflinemodules.bat"
modulesSource='https://pypi.douban.com/simple'
def OperateOfflinePythonModules(inputFile='requirements.txt',outputfile="./downloadofflinemodules.bat" \
,operate=0,autoExecuteBat=False):
'''根据选择自动生成python模块的批处理下载/安装/升级程序'''
global requirementFile,modulesSource
'''请输入选择的操作:
0. 生成手动下载python模块的批处理
1. 生成自动下载python模块的批处理
2. 生成自动下载python模块的批处理,并进行模块升级
3. 生成自动升级python模块的批处理
4. 生成手动下载指定版本python模块的批处理
5. 自动安装指定路径下的离线包
6. 生成本地计算机的pthon离线包文件:pip list >>file
7. 生成本地计算机的pthon离线包文件:pip freeze >>file
8.
'''
if operate==0:
isDownload=True;isAutoInstall=False;isUpgrade=False
elif operate==1:
isDownload=False;isAutoInstall=True;isUpgrade=False
elif operate==2:
isDownload=False;isAutoInstall=True;isUpgrade=True
elif operate==3:
isDownload=False;isAutoInstall=False;isUpgrade=True
elif operate==4:
isDownload=True;isAutoInstall=False;isUpgrade=False
elif operate==5:
return instalModules(inputFile)
elif (operate>=6 and operate <=7):
if(operate==6):
exe=f'pip list >>{outputfile}'
elif(operate==7):
exe=f'pip freeze >>{outputfile}'
ret=os.system(exe)
return ret,True
if inputFile=='':
inputFile=requirementFile
if outputfile=='':
outputfile=outputFile
lines=[]
with open(inputFile,'rt',encoding='utf-8') as file:
firstline=file.readline()
if(firstline.find('==')<0): #使用的时pip list >>e:\piplist.txt 命令得到的模块列表
for line in file:
sa=line.split()
if(sa[1].replace(".","").isdigit()):
lines.append('=='.join(sa))
else:
lines=file.readlines() #使用pip freeze > requirements.txt 得到模块列表
for i in range(0,len(lines),1):
if(isDownload):
if(operate==0):
newline='pip download '+lines[i].split('==')[0] +f' -i {modulesSource} \n'
if(operate==4):
newline='pip download '+lines[i].removesuffix('\r').removesuffix('\n') +f' -i {modulesSource} \n'
lines[i]=newline
else:
if(isAutoInstall):
newline='pip install '+lines[i] +f' -i {modulesSource} \n'
if(isUpgrade):
newline=newline +'pip install '+lines[i].split('==')[0] +f' --upgrade -i {modulesSource} \n'
lines[i]=newline
else:
if(isUpgrade):
lines[i]='pip install '+lines[i].split('==')[0] +f' --upgrade -i {modulesSource} \n'
with open(outputfile,'wt',encoding='utf-8') as file:
file.writelines(lines)
if(autoExecuteBat):
if(outputfile.endswith('.bat')):
os.system(outputfile)
return True
def instalModules(inPath=''):
filenames=[name for name in os.listdir(inPath)
if(os.path.isfile(os.path.join(inPath,name)))]
for name in filenames:
if(name.lower().endswith('.whl')):
cmd='pip install '+os.path.join(inPath,name)
os.system(cmd)
print(f"指定的安装包/轮子{name}已经安装完毕。")
pass
elif(name.lower().endswith('.tar.gz')):
ext='.tar.gz'
f_name =os.path.join(inPath,os.path.splitext(name)[0].replace(".",""))# 获取输出文件路径和名称
#os.mkdir(f_name)
tar_file = tarfile.open(os.path.join(inPath,name)) # 创建gzip对象
tmp=os.path.join(inPath) #,name.removesuffix('.zip')
tar_file.extractall(path=tmp)
tar_file.close()
setup=os.path.join(tmp,name.replace(ext,""),'setup.py')
#i=os.system(' cd ' +os.path.join(tmp,os.path.splitext(name)[0]))
dirOld=os.getcwd()
tmp=os.path.join(tmp,name.replace(ext,""))
os.chdir(tmp) #切换到解压后的目录中
dir=os.getcwd()
cmd=f'python {setup} install'
os.system(cmd)
os.chdir(dirOld)
shutil.rmtree(tmp)
print(f"指定的安装包/轮子{name}已经安装完毕。")
pass
elif(name.lower().endswith('.gz')):# 尚且不完善
ext='.gz'
f_name =os.path.join(inPath,os.path.splitext(name)[0].replace(".",""))# 获取输出文件路径和名称
#os.mkdir(f_name)
g_file = gzip.GzipFile(os.path.join(inPath,name)) # 创建gzip对象
g_file.filename
open(f_name, "wb+").write(g_file.read()) # gzip对象用read()打开后,写入open()建立的文件中。
g_file.close() # 关闭gzip对象
dirOld=os.getcwd()
setup=os.path.join(f_name,'setup.py')
cmd=f'python {setup} install'
os.system(cmd)
os.chdir(dirOld)
shutil.rmtree(tmp)
print(f"指定的安装包/轮子{name}已经安装完毕。")
pass
elif(name.lower().endswith('.zip')):
ext='.zip'
zf=zipfile.ZipFile(os.path.join(inPath,name))
tmp=os.path.join(inPath) #,name.removesuffix('.zip')
zf.extractall(path=tmp)
zf.close()
#info=[lambda:os.path.split(n.lower()) for n in zf.filelist() ]
#if(not info.index('setup.py')>=0):#没有setup.py文件
# continue
setup=os.path.join(tmp,os.path.splitext(name)[0],'setup.py')
#i=os.system(' cd ' +os.path.join(tmp,os.path.splitext(name)[0]))
dirOld=os.getcwd()
tmp=os.path.join(tmp,name.lower().replace(ext,""))
os.chdir(tmp) #切换到解压后的目录中
dir=os.getcwd()
cmd=f'python {setup} install'
os.system(cmd)
os.chdir(dirOld)
shutil.rmtree(tmp)
print(f"指定的安装包/轮子{name}已经安装完毕。")
pass
print("指定的安装包/轮子已经全部安装完毕。")
return
def un_gzfile(gz_path):
# 异常处理
try:
# 压缩文件解压
for f in os.listdir(gz_path):
if ".gz" in f:
g = gzip.GzipFile(mode="rb", fileobj=open(gz_path+"\\"+f, 'rb'))
open(gz_path+"\\"+f.replace(".gz",""), "wb").write(g.read())
except Exception as e:
print(e)
else:
print("文件解压成功!")
def getChoice():
choice=input('''请输入选择的操作:
0. 根据requirements.txt,生成手动下载python模块的批处理
1. 根据requirements.txt,生成自动下载python模块的批处理
2. 根据requirements.txt,生成自动下载python模块的批处理,并进行模块升级到最新版本
3. 根据requirements.txt,生成自动升级python模块的批处理,升级到最新版本的批处理
4. 根据requirements.txt,生成手动下载指定版本python模块的批处理
5. 自动安装指定路径下已经下载的轮子/zip/gz离线包
6. 生成本地计算机的pthon离线包模块文件列表:pip list >>file
7. 生成本地计算机的pthon离线包模块文件列表:pip freeze >>file
-1. 中断退出操作(默认输入)
''')
maxChoice= 7
if(choice==''):
choice=-1
choice=int(choice)
if(choice==-1):
print('选择退出操作。')
sys.exit()
if(choice>=0 and choice <=maxChoice):
return choice,True
else:
return 0,False
def main():
'''
生成requirement.txt文件;
根据requirement文件下载安装包/轮子到当前目录下;
并且可以进行自动安装(.whl,.tar.gz,.zip),升级等奥做。
'''
print('运行本程序前,需要已经安装python,并且设置好python的path路径。只针对安装包进行操作。')
print('isDownload=True,根据输入的文件列表,将下载的离线安装包/轮子保存到当前目录下。后续可以手动安装。')
print('isAutoInstall=True,根据输入的文件列表,将自动从固定的站点("https://pypi.douban.com/simple")安装包/轮子。需要手动执行生成的bat文件')
print('isUpgrade=True,根据输入的文件列表,将自动从固定站点("https://pypi.douban.com/simple")安装包/轮子的升级包。需要手动执行生成的bat文件')
print('支持 pip freeze > requirements.txt 或者 pip list >>e:\piplist.txt 输出的模块列表文件格式')
print('自动生成.bat文件,直接执行该文件即可进行自动安装/下载/升级,也可以使用autoExecuteBat参数进行生成bat后的自动执行')
print('下面开始输入需要的参数:')
choice,right=getChoice()
while not right:
choice,right=getChoice()
infile=r'e:\piplist.txt'
outfile=r'e:\requirements.bat'
auto='n' #自动执行生成的bat文件
if(choice>=0 and choice<=4):
file=input(r"输入模块列表文件路径和文件名称(default='e:\piplist.txt'):")
if file=='':
file=infile
infile=file
file=input(r"输入.bat文件的路径和文件名称(default='e:\requirements.bat'):")
if file=='':
file=outfile
outfile=file
auto=input(r"自动执行生成的bat文件?y/n:")
elif (choice==5):
file=input(r"输入需要安装的python模块离线包文件的路径(default='e:\packages'):")
if file=='':
file='e:\packages'
infile=file
elif (choice>=6 and choice <=7):
file=input(r"输入需要保存的当前计算机python模块列表文件的路径和文件名称(default='e:\requirements.txt'):")
if file=='':
file='e:\requirements.txt'
outfile=file
if(auto.lower()=='y'):
isAutoRunBat=True
else:
isAutoRunBat=False
OperateOfflinePythonModules(inputFile=infile,outputfile=outfile,operate=choice,autoExecuteBat=isAutoRunBat)
if __name__=='__main__':
main()
```
‘’‘
14. 以上程序,已经程序粗略调试通过,作者本人不对代码承担任何承诺和风险,请各位自行斟酌。这个是本人的一个抛砖引玉,希望与各位大神可以一起把我们的工作和生活处理得更加丝滑顺畅,就像是我女票想要一个100平得小房子,我一点手就在浦东来个小别墅一样,那是不是真能把人从梦中幸福醒来?
好了,不多说,各位珍重,奋斗得路上我们风雨同行。(回头还是丢在git上,c站得开放性略显保守,就像是18上世纪得女人,总感觉怪怪的,但是又说不出什么来)
2022-7-17
’‘’