programing

디스크에 쓰지 않고 .zip 파일 다운로드 및 압축 풀기

goodsources 2023. 7. 25. 20:54
반응형

디스크에 쓰지 않고 .zip 파일 다운로드 및 압축 풀기

.Z의 목록을 다운로드하는 첫 번째 파이썬 스크립트를 사용할 수 있었습니다.URL에서 IP 파일을 추출한 다음 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" ))

아래는 압축된 CSV 파일을 가져오는 데 사용한 코드 조각입니다. 확인해 보십시오.

파이썬 2:

from StringIO import StringIO
from zipfile import ZipFile
from urllib import urlopen

resp = urlopen("http://www.test.com/file.zip")
myzip = ZipFile(StringIO(resp.read()))
for line in myzip.open(file).readlines():
    print line

파이썬 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")
myzip = ZipFile(BytesIO(resp.read()))
for line in myzip.open(file).readlines():
    print(line.decode('utf-8'))

여기서file는 문자열입니다.하고자 하는 전할실문을가져려면다사다니음용합을오자열제를 사용하면 됩니다.zipfile.namelist()를 들면예를 들어.

resp = urlopen('http://mlg.ucd.ie/files/datasets/bbc.zip')
myzip = ZipFile(BytesIO(resp.read()))
myzip.namelist()
# ['bbc.classes', 'bbc.docs', 'bbc.mtx', 'bbc.terms']

제 제안은 물건을 사용하는 것입니다.파일을 에뮬레이트하지만 메모리에 상주합니다.다음과 같은 작업을 수행할 수 있습니다.

# get_zip_data() gets a zip archive containing 'foo.txt', reading 'hey, foo'

import zipfile
from StringIO import StringIO

zipdata = StringIO()
zipdata.write(get_zip_data())
myzipfile = zipfile.ZipFile(zipdata)
foofile = myzipfile.open('foo.txt')
print foofile.read()

# output: "hey, foo"

또는 더 간단하게(비샬에 대한 사과):

myzipfile = zipfile.ZipFile(StringIO(get_zip_data()))
for name in myzipfile.namelist():
    [ ... ]

Python 3에서는 바이트 사용문자열 대신 IOIO:

import zipfile
from io import BytesIO

filebytes = BytesIO(get_zip_data())
myzipfile = zipfile.ZipFile(filebytes)
for name in myzipfile.namelist():
    [ ... ]

저는 Python 2를 사용하던 Vishal의 훌륭한 답변의 업데이트된 Python 3 버전을 이미 언급되었을 수 있는 적응/변경에 대한 설명과 함께 제공하고자 합니다.

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)

필요한 변경 사항:

  • Python 3에는 모듈이 없습니다(으로 이동되었습니다).io.StringIO에 )을 합니다.io.BytesIO]2, 우리는 바이스트림을 다룰 것이기 때문에 -- 문서, 이 스레드도 다룰 것입니다.
  • urlopen:
    • "은urllib.urlopenPython 2.6 이전 버전의 기능이 중단되었습니다. 이전 버전에 해당합니다.urllib2.urlopen문서와 이 스레드.

참고:

  • 다음과 : Python 3은 다음과 .b'some text'이것은 문자열이 아니기 때문에 예상됩니다. 기억하세요. 우리는 바이스트림을 읽고 있습니다.Dan04의 훌륭한 답변을 보세요.

몇 가지 사소한 변경 사항:

  • 사용합니다with ... aszipfile = ...문서에 따르면.
  • 이제 스크립트는 를 사용하여 zip에 있는 모든 파일을 순환하고 내용을 인쇄합니다.
  • 개체 생성을 다음으로 이동했습니다.with진술, 비록 그게 더 나은지는 확신할 수 없지만.
  • 을 추가); 은 "NumenorForLife" (zip) "를 추가합니다."unzipped_and_read_"과 파이의시부분및작름일의 시작 ".file"▁to사▁(다▁not▁prefer)를 사용하지 않는 것을 선호합니다.".txt"테스트 문자열이 있는 파일의 경우).물론 코드를 사용하려면 코드 들여쓰기를 조정해야 합니다.
    • 여기서 주의할 필요가 있습니다. 바이트 문자열이 있기 때문에 이진 모드를 사용합니다."wb"바이너리를 쓰면 벌레 통조림이 열리는 것 같은 느낌이 듭니다.
  • UN/LOCODE 텍스트 아카이브라는 예제 파일을 사용하고 있습니다.

내가 하지 않은 것:

  • NumenorForLife에서 zip을 디스크에 저장하는 방법을 문의했습니다.무슨 뜻인지 잘 모르겠어요. zip 파일을 다운로드하는 건가요?그것은 다른 과제입니다. Oleh Pripin의 훌륭한 답변을 보십시오.

방법은 다음과 같습니다.

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)

완성도를 위해 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))
    files = [zipfile.open(file_name) for file_name in zipfile.namelist()]
    return files.pop() if len(files) == 1 else files

        

RAM에 있는 임시 파일에 쓰기

알고 보니tempfile모듈(http://docs.python.org/library/tempfile.html )에는 다음과 같은 기능이 있습니다.

임시 파일스풀링됨TemporaryFile([max_size=0[, mode='w+b'[, bufsize=-1[, 접미사='[, 접두사='tmp'[, dir="]])

이 함수는 파일 크기가 max_size를 초과할 때까지 또는 파일의 fileno() 메서드가 호출되어 내용이 디스크에 기록되고 TemporaryFile()로 작업이 진행될 때까지 데이터가 메모리에 스풀된다는 점을 제외하고 TemporaryFile()과 동일하게 작동합니다.

결과 파일에는 롤오버()라는 한 가지 추가 방법이 있습니다. 이 방법을 사용하면 크기에 관계없이 파일이 디스크에 있는 파일로 롤오버됩니다.

반환된 개체는 _file 특성이 String인 파일과 유사한 개체입니다.rollover()가 호출되었는지 여부에 따라 IO 개체 또는 실제 파일 개체입니다.이 파일과 유사한 개체는 일반 파일과 마찬가지로 with 문에서 사용할 수 있습니다.

버전 2.6의 새로운 기능.

마운트가 tmpfs 마운트를 사용합니다./tmp리눅스에서, 당신은 단지 그곳에서 파일을 만들 수 있지만, 당신은 그것을 직접 삭제하고 이름 짓는 것을 처리해야 합니다.

요청을 사용하여 다른 답변에 추가:

 # 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)사용하여 zip 파일의 내용을 추출하는 extractall()과 같은 더 많은 기능 세부 정보를 얻으며 나중에 open과 함께 사용할 수 있습니다.

이 모든 대답은 너무 크고 길어 보입니다.요청을 사용하여 코드를 단축합니다. 예:

import requests, zipfile, io
r = requests.get(zip_file_url)
z = zipfile.ZipFile(io.BytesIO(r.content))
z.extractall("/path/to/directory")

Vishal의 예는 아무리 훌륭해도 파일 이름에 관해서는 혼란스러우며, 저는 'zipfile'을 재정의하는 것의 장점을 보지 못합니다.

다음은 일부 파일이 포함된 zip을 다운로드하는 예이며, 그 중 하나는 csv 파일이며 나중에 판다 데이터 프레임으로 읽습니다.

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을 사용합니다.)

이것이 저에게 효과가 있었던 정확한 해결책입니다.문자열을 제거하여 파이썬 3 버전용으로 조금 수정했습니다.IO 및 IO 라이브러리 추가

파이썬 3 버전

from io import BytesIO
from zipfile import ZipFile
import pandas
import requests

url = "https://www.nseindia.com/content/indices/mcwb_jun19.zip"
content = requests.get(url)
zf = ZipFile(BytesIO(content.content))

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])

디스크에 파일이 없는 경우 파일 이름이 무엇이어야 하는지는 Vishal의 답변에서 명확하지 않았습니다.저는 대부분의 필요에 따라 수정하지 않고 그의 답변을 수정했습니다.

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

모듈을 사용합니다.URL에서 파일을 추출하려면 호출 결과를 개체로 묶어야 합니다.이는 웹 요청의 결과가 반환되었기 때문입니다.urlopen검색을 지원하지 않습니다.

from urllib.request import urlopen

from io import BytesIO
from zipfile import ZipFile

zip_url = 'http://example.com/my_file.zip'

with urlopen(zip_url) as f:
    with BytesIO(f.read()) as b, ZipFile(b) as myzipfile:
        foofile = myzipfile.open('foo.txt')
        print(foofile.read())

파일을 이미 로컬로 다운로드한 경우에는BytesIO바이너리 모드로 열고 다음으로 넘어가기만 하면 됩니다.ZipFile직접:

from zipfile import ZipFile

zip_filename = 'my_file.zip'

with open(zip_filename, 'rb') as f:
    with ZipFile(f) as myzipfile:
        foofile = myzipfile.open('foo.txt')
        print(foofile.read().decode('utf-8'))

다시 한 번, 당신이 해야 한다는 것을 기억하세요.open이진()'rb' 모드의 파일로, 텍스트가 아닌zipfile.BadZipFile: File is not a zip file오류

이러한 모든 것을 컨텍스트 관리자로 사용하는 것이 좋습니다.with문을 닫아야 합니다.

언급URL : https://stackoverflow.com/questions/5710867/downloading-and-unzipping-a-zip-file-without-writing-to-disk

반응형