3

I'm working on a script that will automatically update an installed version of Calibre. Currently I have it downloading the latest portable version. I seem to be having trouble saving the zipfile. Currently my code is:

import urllib2
import re
import zipfile

#tell the user what is happening
print("Calibre is Updating")

#download the page
url = urllib2.urlopen ( "http://sourceforge.net/projects/calibre/files" ).read()

#determin current version
result = re.search('title="/[0-9.]*/([a-zA-Z\-]*-[0-9\.]*)', url).groups()[0][:-1]

#download file
download = "http://status.calibre-ebook.com/dist/portable/" + result
urllib2.urlopen( download )

#save
output = open('install.zip', 'w')
output.write(zipfile.ZipFile("install.zip", ""))
output.close()
Jacobm001
  • 4,431
  • 4
  • 30
  • 51
  • Every time I start the download it reports a failure. I'm not sure why. – Jacobm001 Jan 11 '12 at 06:00
  • @Jacobm001: It would be helpful if you provided a short description of what you want and expect your code to do, and include the error message you are getting. It's pretty easy to spot a programming error in your code, but since it's not entirely clear what you want the program to do, it's hard to know if the error is relevant to solving your problem or just a minor detail that is beside the point. – Fabian Fagerholm Jul 29 '12 at 14:36

4 Answers4

7

You don't need to use zipfile.ZipFile for this (and the way you're using it, as well as urllib2.urlopen, has problems as well). Instead, you need to save the urlopen result in a variable, then read it and write that output to a .zip file. Try this code:

#download file
download = "http://status.calibre-ebook.com/dist/portable/" + result
request = urllib2.urlopen( download )

#save
output = open("install.zip", "w")
output.write(request.read())
output.close()
David Robinson
  • 77,383
  • 16
  • 167
  • 187
  • I've tried your method, but I seem to be running into an issue with it. It downloads the file fine, but when I try to open the completed file it says it's a corrupted file. Any ideas? Edit: I've just noticed that the file using your method is just under 200KB larger than the intended zip file. – Jacobm001 Jan 11 '12 at 06:49
  • I am having the same problem as Jacobm001. Any advise would really be appreciated. The file downloads, but it gives an error when I try to unzip it. – user1496289 Jul 29 '14 at 10:36
  • @user1496289: would it be possible to provide the link to the file so I can reproduce the problem? – David Robinson Jul 29 '14 at 17:28
  • @DavidRobinson Would you mind explaining why using ZipFile and urlopen together is a bad idea? This example seems to use both http://stackoverflow.com/a/5711095/2423246 – NumenorForLife Apr 28 '15 at 13:08
3

There also can be a one-liner:

open('install.zip', 'wb').write(urllib.urlopen('http://status.calibre-ebook.com/dist/portable/' + result).read())

which doesn't have a good memory-efficiency, but still works.

Barosl Lee
  • 176
  • 1
  • 4
  • I don't think they're that bad, if we know what we're doing. Readability and performance are not always the best answers. We can try to improve writability, while not damaging readability so much. – Barosl Lee Jan 11 '12 at 06:53
  • - not maintainable; - unreadable; - not really testable; - not debugable; - you are likely to be the only one to maintain it; - "we" might not include you in a few months or years (nothing personal, it's just the way it is); - you may need to bump into such one-liners a few times that you didn't code, but you have to maintain to understand my reasoning – sjngm Jan 11 '12 at 07:38
  • I didn't say maintainability is not important. There are always some areas that "writing faster" is more important than "writing maintainable code". Updater script which is asked, in my opinion, is an instant program that doesn't really require every single point in programming language theory. It's just a toy script with fun, so not using the one-liner in the production code is just enough. That's why I said "they are not always the best answers". – Barosl Lee Jan 11 '12 at 08:48
2

have you tryed

output = open('install.zip', 'wb') // note the "b" flag which means "binary file"
Arsenio Siani
  • 261
  • 3
  • 10
  • 3
    Code without explanation is usual not very useful. Consider adding information what that 'b'-flag actually does for future readers. – Sumurai8 Feb 17 '14 at 10:32
2

If you just want to download a file from the net, you can use urllib.urlretrieve:

Copy a network object denoted by a URL to a local file ...

Example using requests instead of urllib2:

import requests, re, urllib

print("Calibre is updating...")
content = requests.get("http://sourceforge.net/projects/calibre/files").content

# determine current version
v = re.search('title="/[0-9.]*/([a-zA-Z\-]*-[0-9\.]*)', content).groups()[0][:-1]
download_url = "http://status.calibre-ebook.com/dist/portable/{0}".format(v)

print("Downloading {0}".format(download_url))
urllib.urlretrieve(download_url, 'install.zip')
# file should be downloaded at this point
miku
  • 181,842
  • 47
  • 306
  • 310