Wer mehrere Webauftritte auf unterschiedlichen Plattformen betreibt, hat mitunter das Problem, das selbe Texte auf verschiedenen Auftritten stehen sollen. Diese möchte man aber natürlich nicht dauernd kopieren oder mehrfach pflegen.
Auf Basis der Perl-Module HTML::TreeBuilder und LWP::UserAgent hab ich daher ein Skript geschrieben, welches definierte Webseiten einließt und über ein SSI-Befehl dann in der jeweiligen Seite anzeigt: import-url.pl.
Das Skript besteht aus drei Teilen: Zuerst wird die Liste der auszulesenden URLs aus einer CSV-Datei eingelesen. Welche dieser URL eingebunden wird, liefert die ID, welche im Aufrufparameter des Skriptes liegt. Eine direkte Angabe der URL wäre zu gefährlich, da ansonsten Dritte beliebige URLs importieren könnten, bzw. die Webseite für ungewollte Webpipes ausnutzen könnten.
Im zweiten Teil wird über LWP die URL ausgelesen:
use LWP::UserAgent; my $ua = LWP::UserAgent->new; $ua->agent($CONST{'Agentname'}); # Create a request my $req = HTTP::Request->new(GET => $url); # Pass request to the user agent and get a response back my $res = $ua->request($req); # Check the outcome of the response my $plaincontent; if ($res->is_success) { $plaincontent = $res->content; } else { return "No response"; }
Der Inhalt wird dann mit HTML::TreeBuilder analysiert.
Die Webseiten, die ich betreibe haben eine klar definierte Semantik, in der der eigentlich Inhalt von einem <div id=“content“> … </div> umschlossen wird. Danach suche ich um alle Teile der Webseite wegzulassen, die bspw. Menu oder Metainformationen enthalten:
use HTML::TreeBuilder; my $tree = HTML::TreeBuilder->new; $tree->no_space_compacting(1); $tree->parse($htmltext); $tree->eof; my $subpart; my $bereich = $tree->look_down('_tag', 'div', sub { return unless $_[0]->attr('id') =~ /content/; } ) ; my $out = join '', map( ref($_) ? $_->as_HTML(undef,undef,{}) : $_, $bereich->content_list ); if (not $out) { $out=$bereich->as_HTML; } $tree->delete;
Die Variable $out
enthält somit den Inhalt der Seite.
Wenn die Seite keine Bilder oder Links enthielte, wäre ich damit fertig. Diese muss ich aber noch anpassen.
Dazu suche ich in einer while()-Schleife und ein paar Regular Expressions einfach nach den Vorkommen von src=““ und href=““ innerhalb der HTML-Tags.
Das sieht dann im wesentlichen so aus (Beispiel nur für die Suche nach Links):
while ($content =~ /href="([^"]+)"/i) { $link =$1; $pre = $`; $post = $'; if (($link =~ /^\//i) && ($link !~ /^([a-z]+):\/\//i) && ($link !~ /^mailto/i)) { $link = "href=\"".$base.$link."\""; } elsif (($link !~ /$base/i) && ($link !~ /^([a-z]+):\/\//i) && ($link !~ /^mailto/i)) { $link = "href=\"".$uripath."/".$link."\""; } else { $link = "href=\"$link\""; } $content = $post; $tcontent .= "$pre$link"; } $tcontent .= $content;
$content
ist der HTML-Text, $content
ist dabei das Ergebnis. Ausgehend von der ursprünglichen URL verfüge ich ausserdem über die beiden Variable $base
und $uripath
, welche die Adresse der Website und die URI der Seite enthalten.
Das Skript ließe sich nun noch leicht erweitern. Zum Beispiel über spezifische RegExp pro einzulesender URL oder auch um eine noch genauere Filterung des Inhaltes nach anderen Bereichen.