Open Source im professionellen Einsatz
Linux-Magazin 11/2011
© Gunnar Pippel, 123RF

© Gunnar Pippel, 123RF

Perl-Skript holt dynamisch generierte Werte aus Webseiten

Abgesaugt

Gibt es kein API für das Einsammeln von Webinformationen, hilft oft Perl mit der Brechstange des Screenscraping. Seit Neuestem überwindet es dabei sogar die Hürde Javascript.

595

Nicht weniger als drei ehrwürdige Linksys-Router schaufeln die Ethernet-Pakete im Wohnbereich der Perlmeister-Labs umher. Auf allen dreien tut die Tomato-Firmware [2] seit Jahren ohne jeglichen Störfall ihren Dienst. Da Tomatos Admin-Webseite nicht nur allerlei nützliche Einstellungen erlaubt (Abbildung 1), sondern darüber hinaus noch informative Statusdaten anzeigt, lag es nahe, einen Screenscraper zu schreiben, um die Daten in regelmäßigen Abständen auf den PC zu holen, in einer Datenbank zu speichern und bei auffälligen Ausreißern Alarm auszulösen.

Abbildung 1: Tomatos Übersichtsseite listet unter anderem die Uptime des Routers in Tagen und Stunden auf.

Aua, Javascript!

Der erste Versuch allerdings ging daneben: Beim Einholen der mit Basic Auth gesicherten Seite via »wget http://root:Passwort@192.162.0.1« zeigte sich, dass Tomato die Felder der Anzeige mittels Javascript auffrischt und einfache Webscraper wie das Perl-Modul WWW::Mechanize statt der begehrten Uptime-Zeit lediglich Javascript-Code runterladen (Abbildung 2).

Abbildung 2: Durch einfaches Einholen der Webseite lässt sich der Uptime-Wert nicht extrahieren.

Damit die Seite die Daten richtig anzeigt, muss auf Client-Seite eine Javascript-Engine anlaufen, die den Code interpretiert und gemäß den darin enthaltenen Anweisungen das DOM (Document Object Model) der im Browser dargestellten Seite auffrischt. Einfache Screenscraper tun das nicht, sondern verhalten sich wie Browser mit abgeschaltetem Javascript und erhalten daher nicht das eigentlich gewünschte Ergebnis.

Das siebte Weltwunder

Die herkulische Aufgabe, diese Browseraktionen in Perl zu implementieren, hat das CPAN-Modul WWW::Scripter erledigt. Zusammen mit dem Plugin WWW::Scripter::Plugin::Ajax für Serverrückrufe, der DOM-Schnittstelle HTML::DOM und der Pure-Perl-ECMA-Skript-(Javascript)-Engine JE stellt es alle notwendigen Funktionen bereit.

Wenn man darüber nachdenkt, wie viele DOM-spezifische Unterschiede bei Browsern es allein zwischen dem Internet Explorer und Firefox gibt, dann lässt sich erahnen, wie viel Arbeit in den Modulen steckt. Außerdem verhält sich das Modul wie ein weiterer Browser, Unterschiede zwischen seiner Implementierung und dem sonst verwendeten Desktopbrowser sind unvermeidlich. Eine weitere Möglichkeit, einen Javascript-gesteuerten Skriptclient zu implementieren, wäre der Einsatz einer Browser-Fernsteuerung wie Selenium [3].

Listing 1 zieht zunächst WWW::Scripter herein und lädt das separat erhältliche Ajax-Plugin mit der Methode »use_plugin()« . Die Klasse ist von WWW::Mechanize und damit auch von LWP::UserAgent abgeleitet und unterstützt demnach die Methode »get()« zum Einholen von Webseiten. Da der Router beim HTTP-Zugang nach einem Passwort für den Rootaccount fragt, stellt das Skript dieses mittels der ebenfalls ererbten Methode »credentials()« zur Verfügung.

Listing 1

tomato-overview

01 #!/usr/local/bin/perl -w
02 use strict;
03 use WWW::Scripter;
04 use Sysadm::Install qw(:all);
05 use HTML::TreeBuilder::XPath;
06
07 my $w = WWW::Scripter->new();
08 $w->use_plugin('Ajax');
09
10 my $pw = slurp "pw.txt";
11 chomp $pw;
12 $w->credentials( "root", $pw );
13 $w->get('http://192.168.0.1');
14
15 $w->wait_for_timers( max_wait => 1 );
16
17 my $tree= HTML::TreeBuilder::XPath->new();
18 $tree->parse( $w->content() );
19 my $uptime =
20   $tree->findvalue(
21     '/html/body//tr[@id="uptime"]/' .
22     'td[@class="content"]');
23
24 print "uptime: $uptime\n";

Damit das Passwort nicht hart im Skript kodiert ist, liest es die Funktion »slurp()« aus der Datei »pw.txt« im aktuellen Verzeichnis ein. Die Datei enthält nur eine Zeile mit dem Passwort und sollte gegen unberechtigte Lese- oder gar Schreibzugriffe geschützt sein. Ganz astrein ist diese Lösung freilich nicht, doch irgendwie muss ich den Schlüssel unter der Fußmatte verstecken, wenn das Skript automatisch laufen soll und der User nicht jedes Mal das Passwort tippen kann.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 3 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Perl-Snapshot

    Wer die Ethernet-Leitung oder den Wireless-Router kontrolliert, jubelt den angeschlossenen Geräten neue Inhalte unter oder gaukelt ihnen vor, sie stünden am anderen Ende der Welt. Besonders eindrucksvoll ist der Effekt, wenn diese sich erst einmal zugeknöpft geben.

  • Flask

    Dank des Python-basierten Microframework Flask, dessen Name sich mit Flachmann übersetzen lässt, steuern die Nutzer im lokalen Netzwerk einen Raspberry Pi über ein Webinterface.

  • Perl-Snapshot

    HTML 5 bringt Websockets, über die Webserver mit ihren Clients in einen Dialog treten können. Die im Folgenden vorgestellte kleine Webapplikation zeigt in Echtzeit im Browser, welche Seiten beliebige User von einem Webserver im Moment aufrufen.

  • Browser ferngesteuert

    Das Testen komplexer Webapplikationen erfordert nicht unbedingt teure proprietäre Tools wie Test Director oder Silk Performer: Selenium gibt's umsonst. Es steuert alle gängigen Browser unter verschiedenen Betriebssystemen fern und lässt sich unter anderem mit Perl programmieren.

  • Eingang zur Unterwelt

    Prinzipiell lassen sich C und Perl gut miteinander verheiraten. Die zum Zugriff benutzte XS-Schnittstelle hat es allerdings in sich, weil sie C- und Perl-Syntax in schwer verdaulicher Weise mischt. Einfacher ist der Abstieg in die Unterwelt der C-Systemprogrammierung mit dem Inline-Modul.

comments powered by Disqus

Ausgabe 09/2016

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.