NEWS
[Gelöst] Werte von Clever Tanken
-
@merlin2k11 So ich bin einfach zu blöde für JSONATA manchmal - nun habe ich es wieder mit einer function Node gemacht. Um beides zu synchronisieren wird das Ganze über Flow-Variablen synchronisiert:
-
@homoran Ich verstehe diese Diskussion nicht - es geht darum, wie man aus einer HTML Seite mit Node-Red ähnlich wie mit dem Parser Daten auslesen und aufbereiten kann. Der Inhalt ist mir wurscht - man kann ja die Überschrift ändern und schreiben
Website mit NodeRed parsen
Aber ansonsten halte ich mich da raus - ich hab nun eine technische Lösung präsentiert und gut ist.
-
@homoran sagte in Werte auslesen von Webseite:
und bitte keine externen Hoster für den Quelltext!
doch, wenn sie regex101 direkt nehmen dann schon
dort kann man wunderschön einen link auf seine gespeicherten daten speichern -
@mickym Wenn es nur um Jsonata geht, da kann ich helfen, was nicht heißt, dass es nicht noch einfacher geht.
Gruß
Reiner -
@oliverio Es geht darum, dass Files (oder auch Bilder) vom extern Hoster auch mal gelöscht oder der Link geändert werden könnte. Dann ist das Anhängsel hier im Thread wertlos, da es sich nicht mehr öffnen lässt. Was direkt im Filesystem des Forums liegt, bleibt auch da, bislang auch nach Umzügen zu anderen Hostern.
Deshalb sollte man immer Anhänge forenintern speichern und verlinken.Gruss, Jürgen
-
@rewenode Ach schön dass Du Dich meldest - mein JSONATA Lehrer. Ich kanns nur leider nicht importieren - da Du den Export nicht in CodeTags gepackt hast und dann interpretiert der Browser irgendwelche Zeichen. Kannst Du es nochmal in CodeTags exportieren?
Ja und war mir neu, wie oder dass man mehrere Abschnitte in der html node kombinieren kann.
So und die größte Herausforderung ist aber ken Array als Text, sondern ein Objekt mit den Kraftstoffen als Eingenschaften des Objektes wie bei mir unten.
Also Ergebnis, sollte schon so aussehen:
Ich scheitere immer daran die Objektingenschaften durch zu iterieren bzw. mappen.
Aber vielleicht kannst Du ja erst mal Deinen Flow nochmal in CodeTags packen, damit ich es mir in Ruhe anschauen kann, aber wie gesagt Ziel wäre EIN Objekt mit den entsprechenden Eigenschaften zu haben.
-
@mickym sagte in Werte auslesen von Webseite:
Ich kanns nur leider nicht importieren - da Du den Export nicht in CodeTags gepackt hast und dann interpretiert der Browser irgendwelche Zeichen. Kannst Du es nochmal in CodeTags exportieren?
Oh, sorry ;-( Schau mal ob es jetzt geht. Hab deb Beitrag geändert.
Gruß
Reiner -
@rewenode Ja jetzt ist die Change-Node solo drin und das wichtigste ist mit dem Code:
( $art := $filter(payload,function( $v,$i){ ($i)%2=0 }); $preis := $map($filter(payload,function( $v,$i){ ($i)%2=1 }),function($v,$i){ $split($v,"\n")[2].$trim().$number() }) ; $map($art,function($v,$i){ $v & ": " & $preis[$i] }) )
Allerdings stimmt das Ergebnis nicht.
Schön wäre wie gesagt ein Objekt - Ok das bekomme ich nun auch ohne Flow variablen aber halt mit JS hin. Ich schau mir das nochmal in Ruhe an. Hab mal den Output in eine InjectNode gemacht, um nicht immer die Webabfrage zu starten:
Momentan kommt bei Deinem Code - immer noch ein Array, statt eines Objektes raus und die Werte passen noch nicht. Aber ich werde es erst nochmal so in JS machen und dann unterhalten wir uns über JSONATA.
-
-
@rewenode Ja und nein - hab mal den Output in eine Inject Node gegeben, um nicht dauern die Webabfrage zu machen.
Klare Verbesserung aus der HTML Node - es werden nur die Textinhalte geholt.
Generell verstehe ich es - dass Du intern nun auch 2 Arrays machst, indem Du die geraden Elemente der $art zuweist und die ungeraden der $kraftstoff.
So bei dem Preis verstehe ich was Du machst - aber ich würde lieber Zahlen haben.Dann lass uns mal zu der Zeile kommen, die in meinen Augen Probleme macht:
$split($v,"\n")[2].$trim().$number()
Ich hab mal das formatNumber schon weggelassen, weil ich ja keine Strings haben möchte. Allerdings bekomme ich das Leerzeichen vor nicht weg.
Laut Beschreibung sollten ja auch führende Leerzeichen entfernt werden:
tut es aber nicht.
Das Einzige wie ich es nun hin bekomme, ist wenn man das Objekt zusammensetzt, das ich es dort nochmal mache:
$map( $art, function($v,$i){ $v & ": " & $preis[$i] } ){$split(":")[0]: $split(":")[1].$trim().$number()}
Das eigentlich geniale an JSONATA bzw. verwirrende ist die Iteration zur Objekterzeugung - das geht einfach noch nicht so recht in meinem Schädel.
Sprich wenn ich die splits weglasse hast Du einfach ein array in dem Du mit maps, die zusammengesetzt sind.
$map( $art, function($v,$i){ $v & ": " & $preis[$i] } )
ergibt also das Array.
Über das Verketten wird impliziert also jedes einzelne Array Element weiterverarbeitet.
$map( $art, function($v,$i){ $v & ": " & $preis[$i] } ){$split(":")[0]: $split(":")[1].$trim().$number()}
Das ist eigentlich das geniale an JSONATA - aber geht immer nicht so in den Kopf. Damit habe ich das gewünschte Ergebnis - wobei ich also
oben jetzt nur noch das $trim() stehen habe - da dort aus mir unerfindlichen Gründen die Zahlenumwandlung nicht geht:
Man kann das $trim() oben sogar ganz weglassen.
Also insgesamt sieht es nun so aus:
( $art := $filter( payload, function( $v,$i){ ($i)%2=0 } ); $preis := $map( $filter( payload, function( $v,$i){ ($i)%2=1 } ), function($v,$i){ $split($v,"\n")[2] } ) ; $map( $art, function($v,$i){ $v & ": " & $preis[$i] } ){$split(":")[0]: $split(":")[1].$trim().$number()} )
Der Punkt ist ja eigentlich ein Abkürzung für das map - wenn ich also diesen kleinen Punkt machen - wird quasi aus jeder Property wieder ein Array Element gebildet.
$map( $art, function($v,$i){ $v & ": " & $preis[$i] } ).{$split(":")[0]: $split(":")[1].$trim().$number()}
Dieser Punkt also ergibt dann:
Im Prinzip habe ich das verstanden - ich muss nur diese Verkettungen noch in meinen Kopf bekommen - jedenfalls ist diese Funktion schon mal zum Abspeichern.
Bleibt nur die Frage offen, warum funktioniert das Konvertieren in einen Zahlenwert oben nicht und unten schon???
EDIT: habe es auch mit dem Mapping oben versucht - das ergibt auch immer wieder Strings:
$preis := $map( $filter( payload, function( $v,$i){ ($i)%2=1 } ), function($v,$i){ $split($v,"\n")[2] } ).$trim().$number() ;
Erzeugt trotzdem:
Na zumindest funktioniert es wenn man es unten bei der Objekterstellung macht. Ich versuche das jetzt trotzdem nochmal mit regEx.
-
@rewenode Lieber Reiner - ich danke Dir wieder einmal so recht herzlich.
- ich bin immer noch verwirrt aber ich habe es nun in einen Einzeiler geschafft - danke für Deine Ideen. Hat mich Zeit gekostet - aber mit dem JSONATA Exerciser habe ich mich schrittweise vorgetastet.
Die magische Zeile (JSONATA ist magisch) lautet:
payload#$i[$i%2=0]{$$.payload[$i]:($$.payload[$i+1].$match(/\d\.\d+/).match.$number())}
Damit reduziert sich der ganze Flow auf:
Wenn man es als String dann auch noch mit den Nachkommastellen formatiert haben will kann man das dann ja noch einfach hinterher schieben.
payload#$i[$i%2=0]{$$.payload[$i]:($$.payload[$i+1].$match(/\d\.\d+/).match.$number().$formatNumber("#0.00"))}
NodeRed ist einfach genial.
- ich bin immer noch verwirrt aber ich habe es nun in einen Einzeiler geschafft - danke für Deine Ideen. Hat mich Zeit gekostet - aber mit dem JSONATA Exerciser habe ich mich schrittweise vorgetastet.
-
@mickym sagte in Werte auslesen von Webseite:
Die magische Zeile (JSONATA ist magisch) lautet
Sehr gut !!! Die Verlockung ist immer groß, JSONata-Konstrukte bis zum Einzeiler zu komprimieren, zumal es oft möglich ist.
Gründe, warum ich das oft versuche zu vermeiden sind:- ich will auch 2 Wochen später noch kapieren, was ich hier eigentlich gemacht habe;-) Und wenn da noch RegEx-Ausdrücke drin sind, geht es fast nicht mehr ohne sinnige Kommentare
- Man kann da schon ganz schön Zeit verdaddeln nur um ein paar Zeilen Code einzusparen
Aber Spaß kann das schon machen;-)
Gruß und schönen Sonntag
Reiner -
@rewenode Wenn ich Dich als Fachmann schon mal da habe.
Wenn ich, wie anfangs 2 Arrays habe - und möchte eines als topics bzw. property und das andere als Value nehmen:
{ "topic": [ "topic_01", "topic_02", "topic_03", "topic_04", "topic_05", "topic_06" ], "payload": [ 2.1, 1.96, 2.02, 2.11, 2.09, 1.08 ] }
dann bringe ich es nicht hin ohne $distinct-Function ein sauberes Objekt zu bekommen:
topic#$i@$t.payload@$p{$t:$p[$i]}
topic#$i@$t.payload@$p{$t:$distinct($p[$i])}
Gibts da noch eine andere Möglichkeit zu verhindern, dass der payload - mal Anzahl der Elemente in einem Array rauskommt. In dieser Variable $i scheint es ein ganzes Array .
Eventuell muss man da vorher was ausfiltern, weil im Beispiel - enthält das $i ja skalare Werte:
EDIT:
Ah ich habs
- muss man vorher ausfiltern.
topic#$i@$t.payload#$j@$p[$i=$j]{$t:$p}
Hier noch die praktische Anwendung in Node-Red:
Sorry dass ich den Thread etwas missbraucht habe. - Aber vielleicht ist das ja auch für andere interessant. Höre jetzt auch auf.
-
Danke Dir Reiner und auch einen schönen Sonntag.
-
@mickym So?
$.topic#$i{$$.topic[$i]:$$.payload[$i]}
Ja, sollte vlt. ein eigener Thread werden
Gruß
Reiner -
@rewenode sagte in Werte auslesen von Webseite:
$.topic#$i{$$.topic[$i]:$$.payload[$i]}
Ja - das geht auch.
- Meins ist umständlicher.
Ist abgespeichert.
-
@mickym Oder auch so, um mal mit $zip zu spielen
$zip($.topic,$.payload){$[0]:$[1]}
#$i brauchts da natürlich nicht.
In JSONata gibt es da immer 1000...Gruß
Reiner -
@rewenode sagte in Werte auslesen von Webseite:
$zip($.topic,$.payload){$[0]:$[1]}
Ich muss immer erst 2mal überlegen - OK die Zip Funktion ist ja beschrieben - aber ich bin wieder über das reduce in dem Objekt gestolpert. Das man mit 0 und 1 ja jedes Array-Element
durchiteriert wird - Aber auch sehr elegant.
-
@mickym zurück zum eigentlichen Thema. Einen hätte ich noch
Mit einem besseren Selektor wird es dann nur ein ganz kurzer Einzeiler.price-type-name, [id|=current-price]
Und im Change dann:
payload#$i[($i%2)=0]{$$.payload[$i]:$$.payload[$i+1].$number()}
Gruß
Reiner -
@rewenode sagte in Werte auslesen von Webseite:
Das mit dem JSONATA ist ja nun nach den vorherigen Ausführungen zu erklären
- aber mit den CSS Selektoren bist Du mir im Vorteil - auch wenn es in der Hilfe zur HTML Node verlinkt ist: https://github.com/fb55/css-select#user-content-supported-selectors
Aber ich bevorzuge dann die andere Schreibweise mit [class="price-type-name"] und dann die Vergleiche zu machen. Das mit dem vorangestellten Punkt einer Klasse entspricht - ist mir bei CSS zwar prinzipiell bekannt, aber hätte ich hier nie verwendet.
Ok - ich merke - ich beginne das mit den CSS Selektoren erst langsam zu verstehen. Dann geht das was @merlin2k11 gesagt hat, dass es nicht exakt übereinstimmen muss.
- Klasse.
Dann gehen aber noch ein paar mehr Selektoren:
Ich hab heute jedenfalls wieder einiges von Dir gelernt.
Vielen Dank!
EDIT:
Noch eine Info - wenn man eine Standalone Version von NodeRed nutzt, kann man auch den doppelten Kontextspeicher verwenden, dann muss man für solche Tests keine Webanfragen machen.
-
@mickym sagte in Werte auslesen von Webseite:
Noch eine Info - wenn man eine Standalone Version von NodeRed nutzt, kann man auch den doppelten Kontextspeicher verwenden, dann muss man für solche Tests keine Webanfragen machen.
wieder was gelernt