ডিস্কে না লিখে একটি জিপ ফাইল ডাউনলোড এবং আনজিপ করা


86

আমি আমার প্রথম পাইথন স্ক্রিপ্টটি কাজ করতে সক্ষম হয়েছি যা কোন ইউআরএল থেকে .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" ))

4
জিপ ফর্ম্যাট স্ট্রিম করার জন্য ডিজাইন করা হয়নি। এটি ফুটার ব্যবহার করে, এর মধ্যে জিনিসগুলির মধ্যে কোথায় রয়েছে তা নির্ধারণ করতে আপনার ফাইলটির শেষের প্রয়োজন , অর্থ এটির একটি উপসেট দিয়ে কিছু করার আগে আপনার পুরো ফাইলটি থাকা দরকার।
চার্লস ডাফি

উত্তর:


66

আমার পরামর্শটি কোনও StringIOঅবজেক্টটি ব্যবহার করা হবে । এগুলি ফাইলগুলি অনুকরণ করে তবে স্মৃতিতে থাকে। সুতরাং আপনি এই মত কিছু করতে পারে:

# 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():
    [ ... ]

পাইথন 3 এ স্ট্রিংআইও এর পরিবর্তে বাইটসআইও ব্যবহার করুন:

import zipfile
from io import BytesIO

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

"স্ট্রিংআইও অবজেক্টটি ইউনিকোড বা ৮-বিট স্ট্রিংগুলিকে গ্রহণ করতে পারে" এর অর্থ কি এই নয় যে আপনি যে বাইটগুলি লেখার প্রত্যাশা করছেন তা যদি 0 মডি 8 এর সাথে একত্রে হয় না, তবে আপনি হয় ব্যতিক্রম নিক্ষেপ করবেন বা ভুল ডেটা লিখবেন?
নিনজেকেকো

4
মোটেও নয় - আপনি কেন একসাথে 8 বাইট লিখতে সক্ষম হবেন? বিপরীতে, আপনি কখন একবারে 8 টিরও কম বিট লেখেন?
প্রেরক 3

@ নিনজাগেকো: আপনার মনে হচ্ছে কোনও সমস্যার আশঙ্কা রয়েছে যদি রচনাটি প্রত্যাশিত বাইট সংখ্যাটি 8 এর একাধিক না হয় তবে স্ট্রিংআইও সম্পর্কে বিবৃতিটি পাওয়া যায় না এবং এটি সম্পূর্ণ ভিত্তিহীন। স্ট্রিংআইওর সমস্যাটি তখন যখন ব্যবহারকারী সিস্টেমের ডিফল্ট এনকোডিংয়ের (যা সাধারণত ) ডিকোডেবল নয় এমন বস্তুর সাথে বস্তুর সাথে মিশ্রিত হয় । unicodestrascii
জন মাচিন

4
উপরের কোডটিতে ছোট মন্তব্য: আপনি যখন .zip এর বাইরে একাধিক ফাইল পড়েন তখন নিশ্চিত হয়ে নিন যে আপনি একের পর এক ডেটা পড়েছেন, কারণ zipfile.open দুইবার কল করার পরে প্রথমটিতে রেফারেন্সটি সরিয়ে দেওয়া হবে।
সাইপ্পি

15
খেয়াল করুন যে পাইথন 3 হিসাবে আপনার ব্যবহার করতে হবেfrom io import StringIO
জর্জি লিটাও

81

নীচে একটি কোড স্নিপেট আমি জিপড সিএসভি ফাইল আনতে ব্যবহার করি, দয়া করে একবার দেখুন:

পাইথন 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 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")
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']

27

আমি বিশাল এর দুর্দান্ত উত্তরের একটি আপডেটড পাইথন 3 সংস্করণ অফার করতে চাই, যা পাইথন 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পাইথন 3 তে কোনও মডিউল নেই (এটি সরানো হয়েছে io.StringIO)। পরিবর্তে, আমি ব্যবহার io.BytesIO] 2 , কারণ আমরা একটি bytestream হ্যান্ডলিং করা হবে - দস্তাবেজ , এছাড়াও এই থ্রেড
  • ইউরোপেন:
    • " urllib.urlopenপাইথন ২.6 এবং তার পূর্বের লিগ্যাসি ফাংশনটি বন্ধ করে দেওয়া হয়েছে; urllib.request.urlopen()পুরানদের সাথে মিলে যায় urllib2.urlopen" ", ডক্স এবং এই থ্রেড

বিঃদ্রঃ:

  • পাইথন 3, মুদ্রিত আউটপুট লাইন তাই মত দেখতে হবে: b'some text'। এটি প্রত্যাশিত, যেমন তারা স্ট্রিং নয় - মনে রাখবেন, আমরা একটি বাই স্ট্রিম পড়ছি। কটাক্ষপাত আছে Dan04 এর চমৎকার উত্তর

আমি কিছু ছোট ছোট পরিবর্তন করেছি:

  • আমি ব্যবহার with ... asপরিবর্তে zipfile = ...অনুযায়ী ডক্স
  • স্ক্রিপ্টটি এখন ব্যবহার করে .namelist() জিপের সমস্ত ফাইলের মধ্যে চক্র করে এবং তাদের বিষয়বস্তু মুদ্রণ করে।
  • আমি ZipFileঅবজেক্টটির সৃষ্টিটিকে সরানwith বিবৃতিতে , যদিও আমি নিশ্চিত নই যে এটি আরও ভাল কিনা।
  • আমি নুমেনরফরফ্লাইফের মন্তব্যের প্রতিক্রিয়া হিসাবে, ফাইলটিতে বাইটস্ট্রিম (জিপের প্রতিটি ফাইল) লিখে একটি বিকল্প যুক্ত করেছি (এবং মন্তব্য করেছি); এটি "unzipped_and_read_"ফাইলের নাম এবং একটি ".file"এক্সটেনশনের শুরুতে যুক্ত করে (আমি ব্যবহার করতে পছন্দ করি না".txt" বাইটস্ট্রিং সহ ফাইলগুলির জন্য করি)। কোডটির ইনডেন্টিং অবশ্যই এটি ব্যবহার করতে চাইলে সামঞ্জস্য করা দরকার।
    • এখানে সাবধান হওয়া দরকার - কারণ আমাদের একটি বাইট স্ট্রিং রয়েছে, আমরা বাইনারি মোড ব্যবহার করি, তাই "wb"; আমার অনুভূতি আছে যে বাইনারি লেখা যাইহোক যাইহোক কৃমি খুলতে পারে ...
  • আমি একটি উদাহরণ ফাইল ব্যবহার করছি, ইউএন / লকডে পাঠ্য সংরক্ষণাগার :

আমি যা করিনি:

  • নিউমেনরফরফ লাইফ ডিস্কে জিপ সংরক্ষণের বিষয়ে জিজ্ঞাসা করেছিল। আমি নিশ্চিত না যে সে কী বোঝাতে চেয়েছিল - জিপ ফাইল ডাউনলোড করে? এটি একটি ভিন্ন কাজ; দেখতে Oleh Prypin এর চমৎকার উত্তর

এখানে একটি উপায়:

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)

আপনি যদি সমস্ত ফাইল ডিস্কে লিখতে চান তবে সহজ উপায় হ'ল লুপিংয়ের পরিবর্তে my_zip_file.extractall ('my_target') ব্যবহার করুন। তবে দারুণ!
MCMZL

আপনি কি আমাকে এই প্রশ্নে সাহায্য করতে পারেন: stackoverflow.com/questions/62417455/…
হর্ষিত কাক্কর

18

একটি অস্থায়ী ফাইলে লিখুন যা র‌্যামে থাকে

এটি tempfileমডিউলটি দেখা দেয় ( http://docs.python.org/library/tempfile.html ) এর মধ্যে কেবল জিনিসটি রয়েছে:

tempfile.SpooledTemporaryFile ([সর্বোচ্চ_সাইজ = 0 [, মোড = 'ডাব্লু + বি' [, বুফসাইজ = -1 [, প্রত্যয় = '' [, উপসর্গ = 'টিএমপি' [, দির = কিছুই নেই]]]]]]]

এই ফাংশনটি টেম্পোরারি ফাইলে () ঠিক যেমন কাজ করে, কেবলমাত্র ফাইলের আকার সর্বাধিক সাইজ ছাড়িয়ে যাওয়া বা ফাইলের ফাইলনো () পদ্ধতি না বলা পর্যন্ত মেমরিটিতে ডেটা ছড়িয়ে দেওয়া হয়, যেখানে বিন্দুতে ডিস্কে লিখিত থাকে এবং টেম্পোরারি ফাইলের সাথে অপারেশনটি এগিয়ে যায় ()।

ফলস্বরূপ ফাইলে একটি অতিরিক্ত পদ্ধতি রয়েছে, রোলওভার (), যার কারণে ফাইলটি তার আকার নির্বিশেষে একটি ডিস্ক ফাইলটিতে রোল করে।

প্রত্যাবর্তিত অবজেক্টটি একটি ফাইল-জাতীয় অবজেক্ট যার _ফাইল বৈশিষ্ট্যটি হয় স্ট্রিংআইও অবজেক্ট বা সত্য ফাইল অবজেক্ট, রোলওভার () ডাকা হয়েছে কিনা তার উপর নির্ভর করে। এই ফাইল-জাতীয় অবজেক্টটি একটি সাধারণ ফাইলের মতো একটি স্টেটমেন্ট সহ ব্যবহার করা যেতে পারে।

সংস্করণ 2.6 এ নতুন New

অথবা যদি আপনি অলস হন এবং আপনার কাছে /tmpলিনাক্সে টিএমপিএফস লাগানো থাকে তবে আপনি কেবল একটি ফাইল তৈরি করতে পারেন, তবে আপনাকে এটি নিজে মুছতে হবে এবং নামকরণের সাথে মোকাবেলা করতে হবে


4
+1 - স্পুলিডেম্পোরারি ফাইল সম্পর্কে জানতেন না। আমার প্রবণতাটি এখনও স্ট্রিংআইওকে স্পষ্টভাবে ব্যবহার করতে হবে তবে এটি জেনে রাখা ভাল।
প্রেরক

16

সম্পূর্ণতার জন্য আমি আমার পাইথন 3 উত্তর যুক্ত করতে চাই:

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
    return [zipfile.open(file_name) for file_name in zip_names]

14

অনুরোধগুলি ব্যবহার করে অন্যান্য উত্তরে যুক্ত করা :

 # 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']

ব্যবহারের সাহায্যে (চ) যেমন জন্য আরো ফাংশন বিবরণ পেতে extractall () যা জিপ ফাইল যা পরে সঙ্গে ব্যবহার করা যেতে পারে বিষয়বস্তু চায়ের খোলা সঙ্গে


আপনার সিএসভি পড়তে, করুন:with f.open(f.namelist()[0], 'r') as g: df = pd.read_csv(g)
কোরি লেভিনসন

3

বিশাল উদাহরণটি যদিও দুর্দান্ত, ফাইলটির নাম আসার পরে বিভ্রান্ত হয় এবং আমি 'জিপফাইলে' পুনরায় সংশোধন করার যোগ্যতা দেখি না।

এখানে আমার উদাহরণটি এমন একটি জিপ ডাউনলোড করে যাতে কিছু ফাইল থাকে যার মধ্যে একটি সিএসভি ফাইল যা পরে আমি একটি প্যান্ডাস ডেটা ফ্রেমে পড়েছিলাম:

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

(দ্রষ্টব্য, আমি পাইথন ২.7.১৩ ব্যবহার করি)

এটি হ'ল সঠিক সমাধান যা আমার পক্ষে কাজ করেছিল। আমি স্ট্রিংআইওটি সরিয়ে এবং আইও লাইব্রেরি যুক্ত করে পাইথন 3 সংস্করণের জন্য এটি সামান্য কিছুটা টুইট করেছি

পাইথন 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])

1

ডিস্কে কোনও ফাইল নেই এমন ক্ষেত্রে ফাইলটির নাম কী হওয়া উচিত তা विशालের উত্তরে তা স্পষ্ট ছিল না। আমি বেশিরভাগ প্রয়োজনে পরিবর্তন না করেই তার উত্তরটি পরিবর্তন করেছি।

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

এটি পাইথন 2 উত্তর।
বরিস

0

zipfileমডিউলটি ব্যবহার করুন । কোনও ইউআরএল থেকে একটি ফাইল বের করতে, আপনাকে urlopenকোনও BytesIOবস্তুর মধ্যে কলের ফলাফল মোড়ানো দরকার । এটি কারণ যে কোনও ওয়েব অনুরোধের ফলাফল প্রত্যাখ্যানকে 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বিবৃতিতে প্রসঙ্গ পরিচালক হিসাবে এই সমস্ত জিনিস ব্যবহার করা ভাল অনুশীলন , যাতে এগুলি সঠিকভাবে বন্ধ হয়ে যায়।


0

এই সমস্ত উত্তর বড় এবং দীর্ঘ প্রদর্শিত হবে। কোডটি ছোট করার জন্য অনুরোধগুলি ব্যবহার করুন , যেমন:

import requests, zipfile, io
r = requests.get(zip_file_url)
z = zipfile.ZipFile(io.BytesIO(r.content))
z.extractall("/path/to/directory")
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.