Загрузка и распаковка a.zip файл без записи на диск
мне удалось получить мой первый скрипт python для работы, который загружает список .ZIP-файлы из URL-адреса, а затем приступает к извлечению ZIP-файлов и записывает их на диск.
теперь я в недоумении, чтобы достичь следующего шага.
моя основная цель-загрузить и извлечь zip-файл и передать содержимое (данные CSV) через поток TCP. Я бы предпочел не писать на самом деле ни один из zip или извлеченных файлов на диск, если бы я мог уйти с ним.
здесь это мой текущий скрипт, который работает, но, к сожалению, приходится записывать файлы на диск.
import urllib, urllister
import zipfile
import urllib2
import os
import time
import pickle
# check for extraction directories existence
if not os.path.isdir('downloaded'):
os.makedirs('downloaded')
if not os.path.isdir('extracted'):
os.makedirs('extracted')
# open logfile for downloaded data and save to local variable
if os.path.isfile('downloaded.pickle'):
downloadedLog = pickle.load(open('downloaded.pickle'))
else:
downloadedLog = {'key':'value'}
# remove entries older than 5 days (to maintain speed)
# path of zip files
zipFileURL = "http://www.thewebserver.com/that/contains/a/directory/of/zip/files"
# retrieve list of URLs from the webservers
usock = urllib.urlopen(zipFileURL)
parser = urllister.URLLister()
parser.feed(usock.read())
usock.close()
parser.close()
# only parse urls
for url in parser.urls:
if "PUBLIC_P5MIN" in url:
# download the file
downloadURL = zipFileURL + url
outputFilename = "downloaded/" + url
# check if file already exists on disk
if url in downloadedLog or os.path.isfile(outputFilename):
print "Skipping " + downloadURL
continue
print "Downloading ",downloadURL
response = urllib2.urlopen(downloadURL)
zippedData = response.read()
# save data to disk
print "Saving to ",outputFilename
output = open(outputFilename,'wb')
output.write(zippedData)
output.close()
# extract the data
zfobj = zipfile.ZipFile(outputFilename)
for name in zfobj.namelist():
uncompressed = zfobj.read(name)
# save uncompressed data to disk
outputFilename = "extracted/" + name
print "Saving extracted file to ",outputFilename
output = open(outputFilename,'wb')
output.write(uncompressed)
output.close()
# send data via tcp stream
# file successfully downloaded and extracted store into local log and filesystem log
downloadedLog[url] = time.time();
pickle.dump(downloadedLog, open('downloaded.pickle', "wb" ))
8 ответов:
мое предложение было бы использовать
StringIO
Ниже приведен фрагмент кода, который я использовал для извлечения заархивированного csv-файла, пожалуйста, посмотрите:
Python 2:
from StringIO import StringIO from zipfile import ZipFile from urllib import urlopen resp = urlopen("http://www.test.com/file.zip") zipfile = ZipFile(StringIO(resp.read())) for line in zipfile.open(file).readlines(): print linePython 3:
from io import BytesIO from zipfile import ZipFile from urllib.request import urlopen # or: requests.get(url).content resp = urlopen("http://www.test.com/file.zip") zipfile = ZipFile(BytesIO(resp.read())) for line in zipfile.open(file).readlines(): print(line.decode('utf-8'))здесь
file- это строка. Чтобы получить фактическую строку, которую вы хотите передать, Вы можете использоватьzipfile.namelist(). Например,resp = urlopen('http://mlg.ucd.ie/files/datasets/bbc.zip') zipfile = ZipFile(BytesIO(resp.read())) zipfile.namelist() # ['bbc.classes', 'bbc.docs', 'bbc.mtx', 'bbc.terms']
я хотел бы предложить обновленную версию Python 3 отличного ответа Вишала, который использовал Python 2, а также некоторое объяснение адаптаций / изменений, которые, возможно, уже упоминались.
from io import BytesIO from zipfile import ZipFile import urllib.request url = urllib.request.urlopen("http://www.unece.org/fileadmin/DAM/cefact/locode/loc162txt.zip") with ZipFile(BytesIO(url.read())) as my_zip_file: for contained_file in my_zip_file.namelist(): # with open(("unzipped_and_read_" + contained_file + ".file"), "wb") as output: for line in my_zip_file.open(contained_file).readlines(): print(line) # output.write(line)изменения:
- нет
StringIOв Python 3. Вместо этого я используюio, а из него я импортируюBytesIO, потому что мы будем обрабатывать bytestream -- Docs, и этой теме.- urlopen:
- " устаревший urllib.функция urlopen из Python 2.6 и более ранних версий была прекращена; urllib.запрос.urlopen () соответствует старому urllib2.urlоткрыть.",Docs.
- импорт urllib.запрос:
Примечание:
- в Python 3 печатные выходные строки будут выглядеть так:
b'some text'. Этот ожидается, так как они не являются строками - помните, что мы читаем bytestream. Взгляните на Dan04 ответ.несколько незначительных изменений я сделал:
- Я использую
with ... asвместоzipfile = ...по данным документы.- скрипт теперь использует
namelist()чтобы просмотреть все файлы в zip и распечатать их содержимое.- я переместил создание
ZipFileобъект в оператор with-, хотя я не уверен, что это лучше.- Я добавил (и закомментировал) возможность записать bytestream в файл (на файл в zip), в ответ на комментарий NumenorForLife; он добавляет
"unzipped_and_read_"к началу имени файла и (Я предпочитаю не использовать".txt"для файлов с bytestrings). Отступы кода, конечно, должны быть скорректированы, если вы хотите его использовать.
- здесь нужно быть осторожным -- потому что у нас есть байтовая строка, мы используйте двоичный режим, так что
"wb"; у меня такое чувство, что написание двоичного кода открывает банку червей в любом случае...- Я использую пример файла текстовый архив UN/LOCODE:
чего я не сделал:
- NumenorForLife спросил о сохранении zip на диск. Я не уверен, что он имел в виду это ... скачивание zip-файла? Это другая задача; см. отличный ответ Олега Припина.
вот так:
import urllib.request import shutil with urllib.request.urlopen("http://www.unece.org/fileadmin/DAM/cefact/locode/2015-2_UNLOCODE_SecretariatNotes.pdf") as response, open("downloaded_file.pdf", 'w') as out_file: shutil.copyfileobj(response, out_file)
писать во временный файл, который находится в оперативной памяти
получается
tempfileмодуль (http://docs.python.org/library/tempfile.html) имеет только вещь:tempfile.SpooledTemporaryFile([max_size=0[, mode= 'w+b' [, bufsize=-1 [, suffix="[, prefix= ' tmp ' [, dir=None]]]]])
этот функция работает точно так же TemporaryFile() делает, за исключением того, что данные буферизуется в памяти до тех пор, пока файл размер превышает аргумент max_size, или до тех пор, пока вызывается метод fileno () файла, по адресу которые указывают на содержимое записывается на диск и работа продолжается как с TemporaryFile().
полученный файл имеет один дополнительный метод опрокидывания(), который вызывает файл для перехода к файлу на диске независимо от его размера.
возвращенный объект является файлом-как объект, атрибут _file которого либо объект StringIO или истинный файл объект, в зависимости от того, ролловер() был называемый. Этот файл-как объект может быть использован в с заявление, как и обычный файл.
новое в версии 2.6.
или если вы ленивы и у вас есть tmpfs-mounted
/tmpна Linux, вы можете просто сделать файл там, но вы должны удалить его самостоятельно и иметь дело с именованием
Я хотел бы добавить мой Python3 ответ для полноты:
from io import BytesIO from zipfile import ZipFile import requests def get_zip(file_url): url = requests.get(file_url) zipfile = ZipFile(BytesIO(url.content)) zip_names = zipfile.namelist() if len(zip_names) == 1: file_name = zip_names.pop() extracted_file = zipfile.open(file_name) return extracted_file
добавление к другим ответам с помощью запросы:
# download from web import requests url = 'http://mlg.ucd.ie/files/datasets/bbc.zip' content = requests.get(url) # unzip the content from io import BytesIO from zipfile import ZipFile f = ZipFile(BytesIO(content.content)) print(f.namelist()) # outputs ['bbc.classes', 'bbc.docs', 'bbc.mtx', 'bbc.terms']использовать help (f) чтобы получить дополнительную информацию о функциях, например extractall(), который извлекает содержимое в zip-файл, который впоследствии может быть использован с открытого.
в ответе Вишала не было очевидно, каким должно быть имя файла в тех случаях, когда на диске нет файла. Я изменил свой ответ, чтобы работать без изменений для большинства нужд.
from StringIO import StringIO from zipfile import ZipFile from urllib import urlopen def unzip_string(zipped_string): unzipped_string = '' zipfile = ZipFile(StringIO(zipped_string)) for name in zipfile.namelist(): unzipped_string += zipfile.open(name).read() return unzipped_string
пример Вишала, как бы велик он ни был, сбивает с толку, когда речь заходит об имени файла, и я не вижу смысла в переопределении 'zipfile'.
вот мой пример, который загружает zip, содержащий некоторые файлы, один из которых является csv-файл, который я впоследствии прочитал в кадр данных pandas:
from StringIO import StringIO from zipfile import ZipFile from urllib import urlopen import pandas url = urlopen("https://www.federalreserve.gov/apps/mdrm/pdf/MDRM.zip") zf = ZipFile(StringIO(url.read())) for item in zf.namelist(): print("File in zip: "+ item) # find the first matching csv file in the zip: match = [s for s in zf.namelist() if ".csv" in s][0] # the first line of the file contains a string - that line shall de ignored, hence skiprows df = pandas.read_csv(zf.open(match), low_memory=False, skiprows=[0])(обратите внимание, я использую Python 2.7.13)
Comments