strohne / Facepager

Facepager was made for fetching public available data from YouTube, Twitter and other websites on the basis of APIs and webscraping.
https://github.com/strohne/Facepager/releases
506 stars 198 forks source link

Unpack list data #14

Closed strohne closed 11 years ago

strohne commented 11 years ago

Display lists in single columns or unpack lists into new datasets.

dorvak commented 11 years ago

Mal auf deutsch, weil gerade schneller:

def getDictValue(data,multikey):
    keys=multikey.split('.')                
    value=data
    for key in keys:
        if type(value) is dict:
            value=value.get(key,"")
        elif type(value) is list:
            valuelist=[]
            for elem in value:
                if key in elem:
                    valuelist.append(elem[key])
                else:
                    valuelist.append(elem)
            return ";".join(str(vlelem) for vlelem in valuelist)
        else:
            return ""
    if type(value) is dict:
        return json.dumps(value) 
    else:        
        return value   
strohne commented 11 years ago

Du fragst: Wo findet eigentlich die Iteration hier statt?

Antwort: die Iteration findet über die keys statt, also in deinem Beispiel über [user,entities]. Zuerst wird value auf den input gesetzt. Nach der ersten Iteration ist value der Wert in user, nach der zweiten Iteration ist value der Wert von user.entities. Dann wirt erst returned. Die Iteration gräbt sich gewissermaßen in das JSON rein.

Habe mich gerade auch über einen Satz in der Hilfe gewundert: "Using nested columns like "user.entities.url.urls" (for Twitter Tweets) may have no effect in the object view". -> das sollte auf jeden Fall einen Effekt haben, läuft über die gleiche Funktion. Bist Du sicher? Kannst Du mir ggf. ein reproduzierbares Beispiel geben (welches Query)?

Ich glaube Deine Funktion geht so nicht, das müsste man rekursiv lösen, weil ja für jedes Listenelement der Inhalt auch auf tieferen Ebenen ausgelesen werden soll.

Ich überlege mir morgen mal was, falls Du nicht schon eine Lösung hast.

strohne commented 11 years ago

Noch eine Idee: ich fände es besser, wenn der key bei Listen entweder wie bisher als Index (0,1 etc.) oder als Wildcard (* oder n) angegeben werden muss. Dann kann man sowohl einzelne Items als auch alle Items (und vielleicht auch noch die Liste in JSON-Format) ausgeben.

dorvak commented 11 years ago

Ja, das wäre tatsächlich gut oder die Ideallösung! Wenn man die Inhalte auf tieferen Elementen auslesen möchte, muss man denke ich eine Reukrusion bauen und eine Funktion nochmal aufrufen (am optimalsten sogar irgendwie als Generator?).

Ich hatte mal eine alte Funktion, um nested Dicts auszulesen (die ist aber auch noch optimierbar; nester() ) und als Iterator/Generator verwendbar (lookup() ). Vielleicht kann man die beiden nutzen (ein paar Dinge wie das "$t" kann man rausnehmen, das ist YouTube-spezifisch. Kann mir aber auch noch mal Gedanken machen. So low-level Funktionen finde ich eh immer ganz spannend :)

def nester(d, k):
    if isinstance(d, dict):
        if d.get(k, None) is not None:
            try:
                if d[k].get('$t', None) is not None:
                    yield d[k]['$t']
                else:
                    yield d[k]
            except:
                yield d[k]
        for subdict in d:
            for dictocc in nester(d[subdict], k):
                yield dictocc
    if isinstance(d, list):
        for elems in d:
            for listocc in nester(elems, k):
                yield listocc

Und hier der lookup bzw die Verwendung als Generator:

def lookup(d, k):
    try:
        return [l for l in nester(d, k)].pop()
    except IndexError:
        return None
strohne commented 11 years ago

Siehe eines der letzten Commits.

strohne commented 11 years ago

Habe vorhin die Methode überarbeitet. Schau doch mal, ob die das so macht wie du es gerne hättest. Siehe auch die commit message.

dorvak commented 11 years ago

Sieht sehr gut aus, funktioniert zumindest alles in meinem Tests!