String aus einem request.get extrahieren

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
peko
User
Beiträge: 19
Registriert: Montag 5. Juni 2017, 14:41

Hallo zusammen,

um die Anzahl der Produkte im Vorratsraum im Keller zu sehen, möchte ich diese beim Einlagern identifizieren und in eine sqlite db eintragen.
Da ein Mitglied der Familie Probleme mit dem Treppensteigen hat, möchte ich das Prozedere vereinfachen und die Liste über eine Webseite
des RasPi ausgeben.
Der request klappt auch, nur komme ich nicht dahinter, wie ich aus dem Ergebnis nur die Zeile hinter "detailname=" extrahieren kann.
Den Teil bis zum Schlüsselwort "detailname=" bekomme ich noch weg, der Eintrag des Produktes wird mit einem "\n" abgeschlossen.
Wie kann ich diesen suchen, die Position herausfinden und ab da den Rest löschen.
Ich hab schon bei String- und Listenmanipulationen gesucht, aber nichts gefunden.

Hier mein bisheriger Versuch

Code: Alles auswählen

#!/usr/bin/python3

import requests
import re

req = requests.get("https://opengtindb.org/?ean=4000540000405&cmd=query&queryid=400000000")
print (req.text)
suche = re.findall(r"detailname=[^.;:!?]{2,}", req.text)
print (suche)
Nach was muss ich genau suchen, um den String hinter "detailname=" herauszufiltern
In diesem Fall: "Kölln Instant Flocken, 1er Pack (1x 250gr)"

Gruß peko
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Irgendwie hatten wir das Problem schon einmal.
Das ist ein Datenformat, das zeilenweise Key-Value-Paare enthält, die in Gruppen eingeteilt sind, die durch `====` getrennt werden. Also mußt Du den Response (`req` ist eine komische Abkürzung, weil da ja gar kein q vorkommt, daher niemals Variablennamen ablürzen) zeilenweise durchgehen und mit z.b. partition in Key und Value aufspalten. Man würde dafür eine Funktion schreiben, die als Ergebnis eine Liste mit Wörterbüchern hat, wobei das erste Wörterbuch angibt, ob ein Fehler aufgetreten ist, was Du auch prüfen solltest.
Zwischen ›print‹ und öffnender Klammer kommt kein Leerzeichen.
peko
User
Beiträge: 19
Registriert: Montag 5. Juni 2017, 14:41

Hallo Sirius3,

vielen Dank erstmal.
Das mit dem key / value bekomme ich leider nicht mal Ansatzweise hin, da ich keinen Plan habe, wie ich es einlesen / abfragen soll.
Haben die Zeilenenden nicht ein "\n" hinten dran, denn "====" habe ich nirgends gesehen.

Das q kommt von request, das Leerzeichen ist eine Angewohnheit aus früheren PHP-Zeiten.
Ich versuche mich zu bessern ;-)
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Ein Filehandle zeilenweise einzulesen und einen String am = zu splitten sind absolute Grundlagen.

Code: Alles auswählen

for line in lines:
    key, _, value = line.strip().partition('=')
Benutzeravatar
snafu
User
Beiträge: 6866
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich würde direkt alles parsen:

Code: Alles auswählen

dict(line.split('=') for line in response.text.splitlines() if '=' in line)
...und dann die Infos aus dem Dict nehmen, die ich benötige.
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

@snafu: das ist nicht ganz korrekt, weil der Response aus mehreren Blöcken besteht. `response` kennt `iter_lines`.
Benutzeravatar
snafu
User
Beiträge: 6866
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Bei iter_lines() werden aber Bytes geliefert, die man noch konvertieren müsste. Und dass im text Attribut Blöcke geliefert werden, wäre mir neu...
Benutzeravatar
__blackjack__
User
Beiträge: 14044
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Das fällt auf die Nase wenn der Wert auch ein oder mehrere '=' enthält.

Die Antwort besteht semantisch aus mehreren Blöcken. Das hat nichts mit `requests` zu tun, sondern mit der API die da angesprochen wird.

@peko: Das '===' ist tatsächlich auch ein '---', das hat Sirius3 wahrscheinlich einfach nur falsch erinnert. Die API kann mit mehr als einem Datensatz antworten und die einzelnen Datensätze sind durch '---'-Zeilen getrennt. Wobei vor dem ersten Datensatz auch noch eine Information kommt ob ein Fehler aufgetreten ist oder nicht. Das steht aber auch alles auf der Webseite: http://www.opengtindb.org/api.php
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
peko
User
Beiträge: 19
Registriert: Montag 5. Juni 2017, 14:41

Erstmal Danke an alle!
Ich werde den Vorschlag von Sirius3 versuchen umzusetzen.
@ __blackjack__ danke, das habe ich auch gelesen.
peko
User
Beiträge: 19
Registriert: Montag 5. Juni 2017, 14:41

Sodele,

der Hinweis von snafu hat das Ergebnis gebracht, das ich suchte.
@__blackjack__ mir reicht der erste Treffer und Produkte mit '=' im Namen gibts hoffentlich nicht so viele

Code: Alles auswählen

#!/usr/bin/python3

import requests
req = requests.get("https://opengtindb.org/?ean=4000540000405&cmd=query&queryid=400000000")
erg = dict(line.split('=') for line in req.text.splitlines() if '=' in line)
print(erg['detailname'])
Extrahiert mir exakt: Kölln Instant Flocken, 1er Pack (1x 250gr)
Das ganze db Geraffel, Ein- und Ausgaben schaffe ich dann wieder alleine.

DANKE an alle für die schnelle Hilfe
Benutzeravatar
__blackjack__
User
Beiträge: 14044
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@peko: Damit bekommst Du bei mehreren Datensätzen aber nicht den ersten sondern den letzten. Je nach dem wie vollständig die einzelnen Datensätze sind, kann es auch sein das nicht alle Schlüssel/Wert-Paare tatsächlich zum letzten Datensatz gehören, sondern man am Ende eine Mischung aus mehreren Datensätzen hat.

Und es gibt auch hier das Problem das im Wert keine '=' vorkommen dürfen, weil das sonst mit einer Ausnahme abbricht.

Du solltest auch den Fehlerwert auswerten, bevor Du irgendwelche anderen Zugriffe auf die Daten machst.

Falsche Abkürzungen sind auch immer noch eine schlechte Idee. Man kürzt `response` nicht mit `req` ab, das macht keinen Sinn und verwirrt den Leser.

Edit: Und `erg` soll wohl `ergebnis` heissen.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

@peko: da der Wink mit dem Zaunpfahl nicht zu fruchten scheint: die Rückgabe von ›requests.get‹ ist kein Request sondern eine Response!
`erg` hat dann wohl auch nichts mit Ergonomie zu tun, sondern ist ein `ergebnis` oder um nicht Englisch mit Deutsch zu mischen, `result`; und dank mehr als drei Buchstaben gibt es keine Kollision mit response.

Ein einfaches ›, 1‹ würde eines der vielen Probleme beheben, die man sich mit so einer stümperhaften Lösung einfängt. Wo ist das Problem von ein bißchen Sorgfalt?
peko
User
Beiträge: 19
Registriert: Montag 5. Juni 2017, 14:41

@sirius - momentan könntest du mich mit dem Zaunpfahl erschlagen, ich komm nicht drauf.
Ich entschuldige mich für den stümperhaften Lösungsansatz und die Frage,
und bedanke mich für die Antworten.
Wo ist das Problem von ein bißchen Höflichkeit ?
Benutzeravatar
snafu
User
Beiträge: 6866
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wie bereits angedeutet wurde, lässt sich das theoretische Problem, dass man ein Gleichheitszeichen im Wert haben könnte, auch lösen. Man muss einfach sagen, dass bloß einmal gesplittet werden soll, indem man den betreffenden Teil anpasst:

Code: Alles auswählen

line.split('=', 1)
Inwieweit das mit den Blöcken bei der Rückgabe praxisrelevant ist, kann ich nicht beurteilen. Anstatt ausfallend zu werden, könnte man ja eine konstruktive Lösung dazu liefern... :)
peko hat geschrieben: Montag 1. Juli 2019, 20:37 @sirius - momentan könntest du mich mit dem Zaunpfahl erschlagen, ich komm nicht drauf.
Es geht einfach darum, dass "request" soviel wie Anfrage heißt und "response" heißt Antwort / Rückmeldung. Was du vom get()-Aufruf zurück bekommst, ist halt die Antwort und nicht die Anfrage.
peko
User
Beiträge: 19
Registriert: Montag 5. Juni 2017, 14:41

@snafu
Vielen Dank, jetzt ist der Groschen gefallen.
Benutzeravatar
snafu
User
Beiträge: 6866
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Und das mit der Benennung ist so ein Zwiespalt: Einerseits ist bei zwei direkt aufeinanderfolgenden Zeilen die Bedeutung einer Abkürzung klar - da könnte man sogar schlichtweg "r" als Bezeichner nehmen. Andererseits wird durch das Ausschreiben von "response" auch dem unbedarften Leser recht klar, was gemeint ist, ohne dass er in die Doku des "requests"-Modul schauen muss, um sicher zu sein. Auch sind gängige Abkürzungen als Bezeichner hilfreich, wenn man sie oft ansprechen muss und ellenlange Zeilen vermeiden will. Das ist so eine Sache, bei der sich wohl immer die Geister scheiden werden. Auch in etablierten Projekten trifft man auf Abkürzungen und die Programme sind dennoch lesbar und wartbar.
Antworten