पायथन: एक फ़ाइल में एकाधिक JSON ऑब्जेक्ट्स को Deserialize करने का प्रयास कर रहे प्रत्येक ऑब्जेक्ट के साथ कई लेकिन लगातार लाइनों की संख्या

ठीक है, लगभग एक हफ्ते के शोध के बाद मैं एसओ को एक शॉट देने जा रहा हूं। मेरे पास एक टेक्स्ट फ़ाइल है जो निम्नानुसार दिखती है (उदाहरण के रूप में 3 अलग जेसन ऑब्जेक्ट्स दिखा रही है लेकिन फ़ाइल में इनमें से 50K हैं):

{
"zipcode":"00544",
"current":{"canwc":null,"cig":7000,"class":"observation"},
"triggers":[178,30,176,103,179,112,21,20,48,7,50,40,57]
}
{
"zipcode":"00601",
"current":{"canwc":null,"cig":null,"class":"observation"},
"triggers":[12,23,34,28,100]
}
{
"zipcode":"00602",
"current":{"canwc":null,"cig":null,"class":"observation"},
"triggers":[13,85,43,101,38,31]
}

मुझे पता है कि पाइथन जेसन लाइब्रेरी का उपयोग कर JSON ऑब्जेक्ट्स के साथ कैसे काम करना है, लेकिन फ़ाइल को पढ़ने से 50 हजार अलग जेसन ऑब्जेक्ट्स बनाने के तरीके के साथ मुझे चुनौती है। (शायद मैं इस बारे में भी सही तरीके से सोच नहीं रहा हूं लेकिन आखिरकार मुझे डेटाबेस में deserialize और लोड करने की जरूरत है) मैंने कोशिश की है कि मुझे एक जनरेटर की जरूरत है ताकि मैं इसका उपयोग करने में सक्षम था:

with open(file) as f:
    for line in itertools.islice(f, 0, 7): #since every 7 lines is a json object
        jfile = json.load(line)

लेकिन उपरोक्त स्पष्ट रूप से काम नहीं करेगा क्योंकि यह एक एकल जेसन ऑब्जेक्ट के रूप में 7 लाइनों को नहीं पढ़ रहा है और मुझे यह भी सुनिश्चित नहीं है कि फिर पूरी फाइल पर फिर से कैसे चलें और व्यक्तिगत जेसन ऑब्जेक्ट्स लोड करें।

निम्नलिखित मुझे एक सूची देगी जो मैं टुकड़ा कर सकता हूं:

list(open(file))[:7]

किसी भी तरह की सहायता की सच में प्रशंसा की जाएगी।


मुझे जो चाहिए वह काफी करीब है और मुझे सचमुच एक कदम दूर लगता है लेकिन फिर भी पुनरावृत्ति के साथ थोड़ा संघर्ष कर रहा है। यह अंततः मुझे सभी डेटाफ्रेम का एक पुनरावर्तक प्रिंटआउट प्राप्त करेगा, लेकिन मैं इसे कैसे बना सकता हूं ताकि मैं अनिवार्य रूप से संयोजित सभी टुकड़ों के साथ एक विशाल डेटाफ्रेम को कैप्चर कर सकूं? मैं फिर सीएसवी इत्यादि के लिए उस अंतिम डेटाफ्रेम को निर्यात कर सकता था (इसके अलावा पहले एक विशाल डेटाफ्रेम बनाने के बजाय डेटाबेस में इस परिणाम को अपलोड करने का एक बेहतर तरीका भी है?)

def lines_per_n(f, n):
    for line in f:
        yield ''.join(chain([line], itertools.islice(f, n - 1)))

def flatten(jfile):
    for k, v in jfile.items():
        if isinstance(v, list):
            jfile[k] = ','.join(v)
        elif isinstance(v, dict):
            for kk, vv in v.items():
                jfile['%s' % (kk)] = vv
            del jfile[k]
            return jfile

with open('deadzips.json') as f:
    for chunk in lines_per_n(f, 7):
        try:
            jfile = json.loads(chunk)
            pd.DataFrame(flatten(jfile).items())
        except ValueError, e:
            pass
        else:
            pass
0
@ डेवएल मैं देख रहा हूं कि आप क्या कह रहे हैं और मैंने शायद इसे खराब कहा है, लेकिन मेरा मतलब है कि उन व्यक्तिगत हिस्सों में से प्रत्येक को लोड करने में सक्षम होना जो एक जेसन ऑब्जेक्ट बनाते हैं और फिर प्रत्येक को व्यक्तिगत रूप से संसाधित करने में सक्षम होते हैं।
जोड़ा लेखक horatio1701d, स्रोत
मुझे माफ़ कर दो अगर मैं बेवकूफ हूँ; लेकिन हर 5 लाइनों में एक जेसन ऑब्जेक्ट नहीं है? वैसे भी अपने नमूने के आधार पर ..
जोड़ा लेखक Dave Lawrence, स्रोत

2 उत्तर

इसके बजाय 6 अतिरिक्त लाइनें लोड करें, और string को json.loads() पर पास करें:

with open(file) as f:
    for line in f:
        # slice the next 6 lines from the iterable, as a list.
        lines = [line] + list(itertools.islice(f, 6))
        jfile = json.loads(''.join(lines))

        # do something with jfile

json.load() will slurp up more than just the next object in the file, and islice(f, 0, 7) would read only the first 7 lines, rather than read the file in 7-line blocks.

आप जेनरेटर में आकार एन के ब्लॉक में एक फ़ाइल पढ़ने को लपेट सकते हैं:

from itertools import islice, chain

def lines_per_n(f, n):
    for line in f:
        yield ''.join(chain([line], itertools.islice(f, n - 1)))

फिर अपनी इनपुट फ़ाइल को बंद करने के लिए इसका उपयोग करें:

with open(file) as f:
    for chunk in lines_per_n(f, 7):
        jfile = json.loads(chunk)

        # do something with jfile

वैकल्पिक रूप से, यदि आपके ब्लॉक परिवर्तनीय लंबाई के रूप में बाहर निकलते हैं, तब तक पढ़ लें जब तक आपके पास कुछ पार्स न हो:

with open(file) as f:
    for line in f:
        while True:
            try:
                jfile = json.loads(line)
                break
            except ValueError:
                # Not yet a complete JSON value
                line += next(f)

        # do something with jfile
0
जोड़ा
यह वास्तव में शानदार और बहुत सराहना की है। मैं वास्तव में lines_per_n फ़ंक्शन को कॉल करने में सक्षम होना पसंद करता हूं और फिर मैं उस खंड को संसाधित कर सकता हूं। बेवकूफ सवाल के बारे में खेद है क्योंकि मैं अभी भी जेनरेटर को कैसे लागू करना सीख रहा हूं लेकिन फ़ाइल में सभी ऑब्जेक्ट्स के लिए अपनी पहली प्रसंस्करण को कैसे लागू कर सकता हूं, केवल पहले के विपरीत? दूसरे शब्दों में पहले खंड पर प्रक्रिया चलाएं, फिर फ़ाइल के अंत तक स्वचालित रूप से बाद के हिस्सों पर प्रक्रिया को चलाएं?
जोड़ा लेखक horatio1701d, स्रोत
मेरा कोड अपडेट किया गया। यह बहुत कुछ है जो मैं पूरा करना चाहता हूं और सुझाव बहुत उपयोगी थे लेकिन ऐसा लगता है कि मैं बस यह याद कर रहा हूं कि यह सुनिश्चित करने के लिए कि यह सभी हिस्सों को संसाधित करता है।
जोड़ा लेखक horatio1701d, स्रोत
@MartijnPieters। समझ गया। धन्यवाद।
जोड़ा लेखक horatio1701d, स्रोत
मुझे आशा है कि मैं अविश्वसनीय रूप से करीब हूं। अद्यतन प्रश्न किसी भी सुझाव की बहुत सराहना की जाएगी।
जोड़ा लेखक horatio1701d, स्रोत
मेरे लगभग अंतिम संस्करण में अद्यतन प्रश्न। वास्तव में कुछ सलाह की सराहना करेंगे। पहले ही, आपका बहुत धन्यवाद।
जोड़ा लेखक horatio1701d, स्रोत
@stephan: एक बिंदु तक, हाँ। मैंने दोनों दृष्टिकोणों का उपयोग किया है, इस पर निर्भर करता है कि फाइल कितनी अच्छी तरह से संरचित है। यदि वस्तुओं को नई लाइनों द्वारा सीमित किया जाता है और अधिकांश स्निपेट छोटे-लाइनर होते हैं, तो अपवाद हैंडलर दृष्टिकोण अच्छा और तेज़ होता है।
जोड़ा लेखक Martijn Pieters, स्रोत
@stephan: ध्यान दें कि JSONDecoder.raw_decode केवल एक इनपुट स्ट्रिंग के साथ काम करता है, फ़ाइल ऑब्जेक्ट नहीं, इसलिए आपको लाइनों को बफर करने के लिए स्वयं को पढ़ना होगा। आप एक्स लाइनों को पढ़ सकते हैं, पार्स करने की कोशिश कर सकते हैं, और आवश्यकतानुसार लाइनों को जोड़ सकते हैं क्योंकि कच्चे डिकोडर वस्तुओं को पाता है। लेकिन जब नई लाइनों द्वारा सीमित किया जाता है, तो मेरा दूसरा दृष्टिकोण बस इतना सुविधाजनक होता है।
जोड़ा लेखक Martijn Pieters, स्रोत
@ prometheus2305: यह वही है जो जनरेटर करता है ; यह आपकी फ़ाइल से एन लाइनों के हिस्सों को एक पुनरावर्तनीय के रूप में उत्पन्न करता है। मेरे जवाब में सचित्र के रूप में बस एक लूप का उपयोग करें।
जोड़ा लेखक Martijn Pieters, स्रोत
@ prometheus2305: आपका लूप मेरे लिए सही दिखता है, बशर्ते आप लूप में df ऑब्जेक्ट के साथ कुछ भी करें। अन्यथा लूप का अगला पुनरावृत्ति पिछले डेटाफ्रेम को इसके उपयोग किए बिना बदल देता है।
जोड़ा लेखक Martijn Pieters, स्रोत
@ prometheus2305: flatten() में, वापसी jfile.items() वास्तव में उसमें इंडेंट किया गया है? आप शायद उस लूप के पहले पुनरावृत्ति को वापस नहीं करना चाहते हैं।
जोड़ा लेखक Martijn Pieters, स्रोत
@ prometheus2305: आप शायद अपने घटकों का व्यक्तिगत रूप से परीक्षण करना चाहते हैं; पहले से एक खंड पर flatten() को आज़माएं, उदाहरण के लिए, यह देखने के लिए कि क्या आप इसकी अपेक्षा करते हैं।
जोड़ा लेखक Martijn Pieters, स्रोत
@stephan हालांकि, सावधान रहें कि JSONDecoder.raw_decode वर्तमान में अग्रणी व्हाइटस्पेस
जोड़ा लेखक svk, स्रोत
इतना अजीब जवाब! धन्यवाद, @MartijnPieters
जोड़ा लेखक Alberto Megía, स्रोत
आपके दूसरे समाधान के लिए, JSONDecoder.raw_decode मूल रूप से यह आपके लिए करता है।
जोड़ा लेखक stephan, स्रोत

जैसा कि कहीं और कहा गया है, एक सामान्य समाधान फ़ाइल को टुकड़ों में पढ़ना है, प्रत्येक टुकड़े को अंतिम में जोड़ना है, और उस नए हिस्से को पार्स करने का प्रयास करें। यदि यह विश्लेषण नहीं करता है, तब तक जारी रखें जब तक आपको कुछ ऐसा न हो जाए। एक बार जब आपके पास कुछ पार्स हो, तो इसे वापस कर दें, और प्रक्रिया को पुनरारंभ करें। जब तक आप डेटा से बाहर नहीं निकलते हैं तब तक कुल्ला-दोहराएं।

यहां एक संक्षिप्त जनरेटर है जो यह करेगा:

def load_json_multiple(segments):
    chunk = ""
    for segment in segments:
        chunk += segment
        try:
            yield json.loads(chunk)
            chunk = ""
        except ValueError:
            pass

इसे इस तरह प्रयोग करें:

with open('foo.json') as f:
   for parsed_json in load_json_multiple(f):
      print parsed_json

आशा है कि ये आपकी मदद करेगा।

0
जोड़ा