Extracting a .app from a zip file in Python, using ZipFile

冷暖自知 提交于 2019-12-12 10:02:30

问题


I'm trying to extract new revisions of Chromium.app from their snapshots, and I can download the file fine, but when it comes to extracting it, ZipFile either extracts the chrome-mac folder within as a file, says that directories don't exist, etc. I am very new to python, so these errors make little sense to me. Here is what I have so far.

import urllib2
response = urllib2.urlopen('http://build.chromium.org/buildbot/snapshots/chromium-rel-mac/LATEST')
latestRev = response.read()
print latestRev

# we have the revision, now we need to download the zip and extract it
latestZip = urllib2.urlopen('http://build.chromium.org/buildbot/snapshots/chromium-rel-mac/%i/chrome-mac.zip' % (int(latestRev)), '~/Desktop/ChromiumUpdate/%i-update' % (int(latestRev)))
#declare some vars that hold paths n shit
workingDir = '/Users/slehan/Desktop/ChromiumUpdate/'
chromiumZipPath = '%s%i-update.zip' % (workingDir, (int(latestRev)))
chromiumAppPath = 'chrome-mac/' #the path of the chromium executable within the zip file
chromiumAppExtracted = '%s/Chromium.app' % (workingDir) # path of the extracted executable

output = open(chromiumZipPath, 'w') #delete any current file there
output.write(latestZip.read())
output.close()

# we have the .zip now we need to extract the Chromium.app file, it's in ziproot/chrome-mac/Chromium.app
import zipfile, os
zippedFile = open(chromiumZipPath)
zippedChromium = zipfile.ZipFile(zippedFile, 'r')
zippedChromium.extract(chromiumAppPath, workingDir)
#print zippedChromium.namelist()

zippedChromium.close()
#zippedChromium.close()

Any ideas?


回答1:


It seems you have encountered a bug in Python. This other question details the problem and workarounds. You can elect to use one of those workarounds, or update to Python 2.6.5 or 2.7b2.

One of the workarounds suggests copying the patched zipfile.py module from the fixed Python.

Best of luck!




回答2:


This seems to be working for me:

import os
import urllib2
import zipfile
from StringIO import StringIO

response = urllib2.urlopen('http://build.chromium.org/buildbot/snapshots/chromium-rel-mac/LATEST')
latestRev = response.read()
print 'getting revision', latestRev

# we have the revision, now we need to download the zip and extract it
locRef='http://build.chromium.org/buildbot/snapshots/chromium-rel-mac/%i/chrome-mac.zip' % (int(latestRev))
latestZip = StringIO(urllib2.urlopen(locRef).read())

# we have the .zip now we need to extract the Chromium.app file, it's in chrome-mac/Chromium.app/
zippedChromium = zipfile.ZipFile(latestZip)
# find all zip members in chrome-mac/Chromium.app
members = [m for m in zippedChromium.namelist() if m.startswith('chrome-mac/Chromium.app/')]
#zippedChromium.extract(chromiumAppPath, workingDir)
target = 'chromium-%s' % latestRev
if os.path.isdir(target):
    print 'destination already exists, exiting'
    raise SystemExit(1)
os.makedirs(target)
zippedChromium.extractall(target, members)

#zippedChromium.close()



回答3:


Here's another cut - this is the same technique, but it walks the result to demonstrate that it works.

import os
import urllib2
import zipfile
from StringIO import StringIO

response = urllib2.urlopen('http://build.chromium.org/buildbot/snapshots/chromium-rel-mac/LATEST')
latestRev = response.read()
print 'getting revision', latestRev

# we have the revision, now we need to download the zip and extract it
locRef='http://build.chromium.org/buildbot/snapshots/chromium-rel-mac/%i/chrome-mac.zip' % (int(latestRev))
latestZip = StringIO(urllib2.urlopen(locRef).read())

# we have the .zip now we need to extract the Chromium.app file, it's in chrome-mac/Chromium.app/
zippedChromium = zipfile.ZipFile(latestZip)
# find all zip members in chrome-mac/Chromium.app
members = [m for m in zippedChromium.namelist() if m.startswith('chrome-mac/Chromium.app/')]
#zippedChromium.extract(chromiumAppPath, workingDir)
target = 'chromium-%s' % latestRev
if os.path.isdir(target):
    print 'destination already exists, exiting'
    raise SystemExit(1)
os.makedirs(target)
zippedChromium.extractall(target, members)

lengths = [
    (len(dirnames), len(filenames))
    for dirpath, dirnames, filenames in os.walk(target)
    ]
dirlengths, filelengths = zip(*lengths)
ndirs = sum(dirlengths)
nfiles = sum(filelengths)
print 'extracted %(nfiles)d files in %(ndirs)d dirs' % vars()
#zippedChromium.close()

The output I get when I run it is

> .\getapp.py
getting revision 48479
extracted 537 files in 184 dirs



回答4:


There is another problem extracting an .app from a zip in Python (which doesn't happen with a typically zip utility). No one else seems to have mentioned this...

The .app can ceases to function post extraction this way, as a result of losing the execution permission bit on the nested binary. You can fix this though, by simply granting that again.

Here's a loose snippet of code that I'm using. Revise this as needed for your purposes (or write a more generic function to handle this situation in a more universal manner):

import os, zipfile
...
ZIP_PATH     = APP_PATH + ".zip" 
APP_BIN_DIR  = os.path.join( APP_PATH, "Contents/MacOS" )
zipfile.ZipFile( ZIP_PATH, 'r' ).extractall( WORK_DIR )   
BIN_PATH = os.path.join( APP_BIN_DIR, os.listdir( APP_BIN_DIR )[0] )
os.chmod( BIN_PATH, 0o777 )

My program already knew where to expect the APP_PATH to be found (i.e. within the WORK_DIR). I had to zip it up though, and shoe horn that detail in after the fact. I name my zip like XXXXX.app.zip. I resolve the BIN_PATH here pretty simply without the need to know the name of binary inside the .app, because I know there is only going to be one file in there for my use case. I grant full (777) permissions to it, because I simply delete the .app at the end of my script anyway.



来源:https://stackoverflow.com/questions/2928373/extracting-a-app-from-a-zip-file-in-python-using-zipfile

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!