NEWS
Screen-Scraping?
-
Liebe Automatisierungsgemeinde,
ich möchte periodisch einen Teil einer externen Website herauspicken und in einem Widget anzeigen. Hat jemand Ideen?
Erst hatte ich ein HTML-Widget in Vis erzeugt und wollte dann mit jQuery immer mal die URL im Hintergrund laden, den richten Teil herausparsen und dann in den Text des Widgets injizieren. Aber das Skript wollte nie laufen. Ich hatte den Eindruck, mein document.ready kam lange bevor die Ansicht bereit war.
Aktuell mache ich es schmutzig mit einem externen Cron-Job in Ruby, der mir die Information holt und per Simple-API in ioBroker schubst.
Oder habt ihr eine kluge Idee, wie man im "Scripts"-Teil einen periodischen Job für das Screen-Scraping bauen kann?
Gruß,
Christoph -
-
Du kannst über ein script im Javascript Adapter die Daten holen, parsern und in einem Datenpunkt speichern, welchen du dann mit einem widget im vis anzeigst. Also ähnlich deinem Ruby nur halt alles im iobroker. Nachteil wenn du es in der vis mit jquery machst, du lädst die Daten für jede offene vis, und auch bei jedem Neuladen. Und ja dei .ready kommt vermutlich zu früh, die vis ist keine vom server geparserte html-seite die bei .ready komplett geladen ist sondern läuft dynamisch im Browser.
-
@Glasfaser Danke für den Vorschlag. Da die Texte sich dort immer mal ändern, denke ich, dass ich mit einer fixen Position nicht glücklich werde. Ich muss schon irgendwie an das DOM und das richtige herauspicken.
-
@dbweb Gefällt mir, das über Datenpunkte zu machen. Das lässt sich im Vis auf jeden Fall am einfachsten darstellen.
Ich bin kein JS-Crack und hänge nach einem Experimentieren leider fest. Ich möchte ja eine URL laden und dann in das HTML reingucken.
Herausforderung 1: URL laden.
Mein Gedankengang: "ioBroker basiert auf NodeJS. Also muss ich etwas laden, das in NodeJS läuft." Ergo habe ich in /opt/iobroker ein "npm add request" ausgeführt (das soll eine nette Library für den Zweck sein), iobroker restartet und es im Script-Editor in ioBroker damit probiert:
const request = require('request'); request('https://www.dahmetal.de/index.php/linien-und-schulverkehr/verkehrsmeldungen', (err, res, body) => { if (err) { return console.log("error"+err); } console.log("url: "+body.url); console.log(body.explanation); });
Der Code wird irgendwie ausgeführt, aber es wird keine URL abgerufen. Das hier kommt im Log:
13:22:02.431 info javascript.0 Stop script script.js.common.schulbus 13:22:02.443 info javascript.0 Start javascript script.js.common.schulbus 13:22:02.443 info javascript.0 script.js.common.schulbus: registered 0 subscriptions and 0 schedules 13:22:03.029 info javascript.0 script.js.common.schulbus: url: undefined 13:22:03.029 info javascript.0 script.js.common.schulbus: undefined
Muss ich etwas beachten, wenn ich JS-Code im ioBroker-Kontext laufen lasse? Denn genau dieser Code-Schnipsel direkt mit "node schulbustest.js" läuft 1a.
-
Vom Grundsatz her schaut das gut aus, kanns grad nicht testen auf dem Handy, du kriegst aber ein "url undefined", machs mal noch einfacher, probiers mal ohne https und auf localhost und gib JSON.stringify(body) aus.
-
@dbweb Danke noch mal. Offenbar hatte ich ein Tutorial für request gewählt, dass nicht zur aktuellen Version passte. Daher die Verwirrung. Jetzt tut es. Ich hatte bisher eher mit Javascript im Browser zu tun und war der irrigen Annahme, dass die Welt in NodeJS gaaaaanz anders ist.
Wer in die Verlegenheit kommt, um Daten aus anderen Websites scrapen möchte… das hier funktioniert bei mir als Script:
const cheerio = require('cheerio'); const request = require('request'); function schulbus_status() { request('https://www.dahmetal.de/index.php/linien-und-schulverkehr/verkehrsmeldungen', (err, res, body) => { if (err) { return console.log("error: "+err); } const $ = cheerio.load(body); var meldung = $('p#l8115').children()[0].nextSibling.data; setState('javascript.0.my.schulbus_status', meldung); }); }; schedule('*/15 * * * *', function () { schulbus_status(); });
Den state javascript.0.my.schulbus_status habe ich als Text-Feld angelegt. Und ich habe in /opt/iobroker die Javascript-Pakete installieren müssen (und ioBroker danach neu gestartet):
npm install cheerio npm install request
Danke noch mal für euer Gehirn auch im Namen meiner Frau, die jetzt morgens am Küchentablet ablesen kann, ob der Schulbus fährt.
-
Könntest du bitte noch ein Screenshot machen , damit andere erkennen wie es dann aussieht !?
Eventuell die Original Webseite und dann deins .
-
Da es sich um etwas wichtiges handelt würde ich Fehler noch etwas besser abfangen und dann auch im VIS für deine Frau anzeigen, dass die Abfrage nicht geklappt hat
Ansonsten, schaut gut aus. Komme auch eher aus dem js-Frontend-Bereich, node ist aber eigendlich dasselbe, nur halt mit etwas mehr Möglichkeiten...
-
Alles klar. Der Vollständigkeit halber…
So sieht der relevante Teil der oben genannten URL im Browser aus, den ich gerne in ioBroker zur Verfügung hätte:
Wenn man im Browser mit F12 die Entwickler-Tools öffnet, findet man den interessanten Text hier:
Im Firefox kann ich z.B. mit der rechten Maustaste auf den spannenden Text-Teil klicken und "q" drücken. Dann werde ich direkt im HTML-Quelltext an die richtige Stelle geleitet.Ich bin zwar kein Javascript-Held, aber mit jQuery habe ich schon ein paar mal gearbeitet und weiß grob, wie ich an bestimmte Informationen auf einer Website komme. Ich suche zunächst nach dem "P"-Tag mit der ID "#l8115". Innerhalb dieses Tags (children()) suche ich mir das erste heraus, das ich finde ([0]). Damit bin ich beim "strong"-Tag angekommen. Meine gesuchte Information ist "nebenan" (nextSibling). Und mit dem "data"-Attribut bekomme ich dann den eigentlichen Text.
Vermutlich kann man das in jQuery auch eleganter machen. Aber irgendwie war ich einfach froh, die gewünschte Information gefunden zu haben.
Falls ihr auch eine Website "screen scrapen" wollt, finde ich dafür jQuery eine schöne Lösung. Manche Websites laden jQuery ohnehin dazu und ihr könnte direkt in der Entwickler-Konsole (F12) mit dem "$"-Objekt von jQuery herumspielen. Alternativ könnt ihr jQuery einfach in jede angezeigte Website mit diesem Javascript-Schnipsel nachladen, in dem ihr ihn in die Javascript-Konsole (F12) einfügt:
var jq = document.createElement('script'); jq.src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"; document.getElementsByTagName('head')[0].appendChild(jq); jQuery.noConflict();
Im Prinzip sucht sucht dieses Geschwurbel in der aktuellen HTML-Seite nach dem "head"-Tag, in dem die Javascript-Dateien nachgeladen werden. Dort packt es einen weiteren "script"-Tag rein und lädt Javascript rein. Danach habt ihr in der Konsole das jQuery-Objekt "$" zur Verfügung und könnt euch mit den Selektoren von jQuery durch das HTML fräsen, bis die gewünschte Information herauspurzelt. Details zu den Selektoren findet ihr unter https://api.jquery.com/category/selectors/
Ich hoffe, das hilft etwas dem Verständnis, wie man Daten aus anderen Websites ausleihen kann.