Webseiten auslesen und importieren

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.