Как скачать файл с помощью Python в интеллектуальным способом?
мне нужно загрузить несколько файлов через http в Python.
самый очевидный способ сделать это-просто использовать urllib2:
import urllib2
u = urllib2.urlopen('http://server.com/file.html')
localFile = open('file.html', 'w')
localFile.write(u.read())
localFile.close()
но мне придется иметь дело с URL-адресами, которые в некотором роде неприятны, скажем так:http://server.com/!Run.aspx/someoddtext/somemore?id=121&m=pdf
. При загрузке через браузер, файл имеет название, т. е.. accounts.pdf
.
есть ли способ справиться с этим в python, поэтому мне не нужно знать имена файлов и жестко закодировать их в мой скрипт?
5 ответов:
такие скрипты загрузки, как правило, нажимают заголовок, сообщающий пользователю-агенту, как назвать файл:
Content-Disposition: attachment; filename="the filename.ext"
Если вы можете захватить этот заголовок, вы можете получить правильное имя файла.
здесь еще один поток это имеет немного кода, чтобы предложить для
Content-Disposition
-на расхват.remotefile = urllib2.urlopen('http://example.com/somefile.zip') remotefile.info()['Content-Disposition']
основываясь на комментариях и anwser @Oli, я сделал такое решение:
from os.path import basename from urlparse import urlsplit def url2name(url): return basename(urlsplit(url)[2]) def download(url, localFileName = None): localName = url2name(url) req = urllib2.Request(url) r = urllib2.urlopen(req) if r.info().has_key('Content-Disposition'): # If the response has Content-Disposition, we take file name from it localName = r.info()['Content-Disposition'].split('filename=')[1] if localName[0] == '"' or localName[0] == "'": localName = localName[1:-1] elif r.url != url: # if we were redirected, the real file name we take from the final URL localName = url2name(r.url) if localFileName: # we can force to save the file as specified name localName = localFileName f = open(localName, 'wb') f.write(r.read()) f.close()
он берет имя файла из Content-Disposition; если его нет, использует имя файла из URL-адреса (если произошло перенаправление, учитывается конечный URL-адрес).
объединение намного выше, вот это более подходящие для Python решение:
import urllib2 import shutil import urlparse import os def download(url, fileName=None): def getFileName(url,openUrl): if 'Content-Disposition' in openUrl.info(): # If the response has Content-Disposition, try to get filename from it cd = dict(map( lambda x: x.strip().split('=') if '=' in x else (x.strip(),''), openUrl.info()['Content-Disposition'].split(';'))) if 'filename' in cd: filename = cd['filename'].strip("\"'") if filename: return filename # if no filename was found above, parse it out of the final URL. return os.path.basename(urlparse.urlsplit(openUrl.url)[2]) r = urllib2.urlopen(urllib2.Request(url)) try: fileName = fileName or getFileName(url,r) with open(fileName, 'wb') as f: shutil.copyfileobj(r,f) finally: r.close()
2 Кендер:
if localName[0] == '"' or localName[0] == "'": localName = localName[1:-1]
это небезопасно -- веб-сервер может передать неправильное форматированное имя как ["file.доб] или [файл.ВН'] или даже быть пустым и localName[0] поднимет исключение. Правильный код может выглядеть так:
localName = localName.replace('"', '').replace("'", "") if localName == '': localName = SOME_DEFAULT_FILE_NAME