Über mich

Startseite arrow Tipps & Tricks arrow Simple HTML DOM Parser - HTML mit PHP ändern

Simple HTML DOM Parser - HTML mit PHP ändern

Dienstag, 11. August 2009
Geschrieben von Armin Vieweg
Jüngst bin ich auf eine schöne kleine Library gestoßen die sich "Simple HTML DOM" nennt. Man kann serverseitig (also mit PHP) den Quellcode mit komfortablen Selectors ändern, wie man es z.B. aus jQuery kennt.

In jQuery gibt es sehr komfortable Selectors. Man kann zum Beispiel sagen, dass jeder Link der extern ist eine zusätzliche Klasse zugewiesen bekommt. Der Code in jQuery sieht dafür so aus:

$("a[href^='http://']").addClass("external");



In CSS 3 gibt es auch die Möglichkeit Selektierungen an Hand von z.B. Eigenschaften vorzunehmen, das sähe in einem CSS3-Stylesheet dann so aus:

a[href^='http://'] {
  color:red;
}


Aber Achtung! CSS3 Befehle werden vom Internet Explorer 8 oder früher nicht unterstützt. Lediglich Vorreiter wie Firefox, etc. unterstützen bereits CSS3-Befehle (und sogar schon HTML5).


Aber ohne jetzt ausschweifen zu wollen, stellt sich mir hierbei die Frage: Wie kann ich eine Klasse über PHP dem entsprechenden Link hinzufügen? Denn jQuery und damit JavaScript klappt nicht auf allen Computern (kann man ja ausschalten) und CSS3 wird nicht flächendeckend unterstützt.



Grundvoraussetzung
Also die Grundvoraussetzung ist, dass wir den Quellcode der Seite die wir gleich ausgeben möchten in einer Variable gespeichert haben um so darauf zugreifen zu können. Wie das geht mit PHP habe ich in zwei Artikeln etwas näher erläutert:

Inhalte mit PHP abfangen und
PHP und .htaccess: Aus statisch mach dynamisch


Haben wir jetzt den Quellcode z.B. in der Variable $inhalte gespeichert, ist die Frage, wie kann z.B. jedem Link, dass sich im DIV mit der id="content" befindet eine zusätzliche Klasse geben? Es gibt vermutlich seitenlange Reguläre Ausdrücke mit denen das ginge, aber es geht sehr viel schneller und einfacher!


PHP Simple HTML DOM Parser

Was hier trotz des Wörtchens "simple" immer noch recht kompliziert klingt ist gar nicht so schlimm wie es aussieht. Wenn wir die aktuell 35,2 KB große kleine Datei über ein Include oder besser ein Require ins PHP einfügen, also so:

require_once($_SERVER["DOCUMENT_ROOT"] . "/inc/simple_html_dom.php");


Dann können wir im Anschluss daran mit neuen Befehlen arbeiten. Wir gehen ja noch davon aus, dass der Quellcode ganz normal als Text in der Variable $inhalte steht.

Damit kann das Script noch nichts anfangen, der Text muss erst geparsed werden. Ist aber nicht schwer, dafür gibt es folgenden Befehl:

$inhalte = str_get_html($inhalte);


Wir überschreiben hier die Variable $inhalte mit der geparsten Variante des Quellcodes.

Man kann auch statt einer Variable direkt eine Datei öffnen oder sich den Quellcode einer externen Seite "leechen" mit folgendem Befehl:

$html = file_get_html('test.html');
$external_html = file_get_html('http://www.google.de/');


Das aber nur am Rande - wir arbeiten jetzt mit $inhalte weiter.


Ich will alle Links im DIV mit der id="content" aufgelistet haben. Kein Problem dafür nutzen wir folgenden Code:

$meine_links = $inhalte->find('#content a');



Die Variable $meine_links ist jetzt ein DOM-Parser-Objekt, vergleichbar mit einem assoziativen Array, d.h. wir können hier mit einer foreach-Schleife arbeiten. Also eine Schleife die für jedes gefundene Element was entsprechendes ausführt.

Der Befehl von eben, kombiniert mit der entsprechenden Schleife sieht dann so aus:

foreach($inhalte->find('#content a') as $e) {
  echo("Link gefunden mit href: " . $e->href . "<br>\n");
}


$e beinhaltet dank der foreach-Schleife immer das aktuelle Element, dass unserem Selektor entspricht. Die Eigenschaften des Objektes sind auch die Eigenschaften des Elementes. Wir können darüber jedes beliebige Attribut abfragen.


Den Quellcode in der Variable verändern
Im letzten Beispiel haben wir in der foreach-Schleife ein Echo zum Ausgeben verwendet. Wir wollen aber in der Regel den Quellcode selbst manipulieren und anschließend komplett als fertige Website ausgeben. Dies geht ebenfalls denkbar einfach und zwar auch über die Attribute des Objektes.

foreach($inhalte->find('#content a') as $e) {
  $e->target = "_blank";
}


Dadurch, dass wir der Eigenschaft "target", die ein Link ja besitzt, einen neuen Wert zuweisen wirkt sich diese Änderung auf alle Elemente in dem Quellcode aus. Also alle Links im DIV mit der id="content" haben nun das Attribut "target" mit dem Wert "_blank" zugewiesen bekommen.

Geben wir den Quellcode nun mit

$fertige_inhalte = $inhalte;
echo $fertige_inhalte;


aus, sehen wir den ursprünglichen Quellcode mit den eben definierten Änderungen. Den Schritt vor dem Echo machen wir um aus dem DOM-Objekt wieder reinen Text zu machen und ihn dann auszugeben.

Wenn wir weiterhin objektorientiert bleiben wollen, können wir aber auch dieses hier schreiben:

$fertige_inhalte = $inhalte->save();
echo $fertige_inhalte;



Alternativ kann man den Quellcode auch direkt in eine Datei zurückschreiben:

$html->save('ergebnis.html');


Das ist total praktisch und relativ einfach zu handhaben.



Spezielle Attribute
Verschiedene Elemente im HTML haben ja verschiedene Eigenschaften. Ein Link hat z.B. ein "target", ein Bild hat kein "target", dafür einen "alt"-Tag. Hier unterscheiden sich die Elemente, darauf muss man auch entsprechend achten. Versucht man ein Attribut aufzurufen, den es nicht gibt erhält man als Rückgabe "NULL". Man erhält allerdings auch "NULL" zurück, wenn man in einem Link ein Target ausgeben möchte, der gar nicht vorhanden ist (obwohl es valide wäre).

Abgesehen von den "normalen" Attributen gibt es aber noch speziell definierte Eigenschafen, die es im normalen HTML so gar nicht gibt.

Und zwar gibt es noch Folgendes:

echo $e->tag; //Ausgabe: a
echo $e->outertext; //Ausgabe: <a href="test.html">Dies ist ein <b>Lin...</a>
echo $e->innertext; //Ausgabe: Dies ist ein <b>Link</b>
echo $e->plaintext; //Ausgabe: Dies ist ein Link


Diese Eigenschaften sind vergleichbar mit innerHTML oder outerHTML aus JavaScript.


Sich im Quellcode bewegen
Wir können uns auch im Quellcode bewegen. Wir wollen also nicht alle Links haben, die mit "http://" im "href" beginnen, sondern alle Elemente, die danach kommen - oder sich vielleicht innerhalb des Links befinden. Oder wir wollen das Element haben, was sich oberhalb des Links befindet.

Hierfür haben die Entwickler ähnliche Befehle eingebaut, wie wir sie schon aus JavaScript oder Libraries wie jQuery kennen:

$element_danach = $e->next_sibling();
$element_davor = $e->prev_sibling();


Wir können auch Kombinationen machen, z.B. alle Kinder-Elemente im nächsten Element:

$elemente_im_element_danach = $e->next_sibling()->children();





Lizenz, Download und Dokumentation
Dieses Script, was mit seinen 35,2 KB recht schnittig ist, unterliegt der MIT-Lizenz, kann also frei (auch für kommerzielle Zwecke) verwendet werden.

Das Projekt selbst liegt bei Sourceforge. Dort liegt auch die Dokumentation und findet sich der Download der verschiedenen Versionen. Die aktuelle Version ist 1.11, diese war auch Bestandteil meiner Tests.

Website von PHP Simple HTML DOM Parser


Download Version 1.11 (als ZIP mit Beispielen)



Wenn Ihr Alternativen kennt, Fragen habt oder schon Erfahrungen damit machen konntet - immer gerne her damit - die Kommentarfunktion steht Euch zur freien Verfügung.


  Kommentare (1)
 1 Geschrieben von: Hannes, am 08.09.2009 um 15:48
interessant, erinnert mich irgendwie an Zend Dom Query, also den CSS Mode dabei ( http://framework.zend.com/manual/de/zend.dom.query.html ), bin hier aber ab einem gewissen Punkt zu XPath gewechselt auf dem dies aufbaut, und ich denke mal das Selbe gilt auch für das hier beschriebene Modul.  
 
Sprich ein Aufbau auf xpath, gibt hier ja auch die sehr schöne native simple XML Funktion ( http://de2.php.net/manual/en/simplexmlelement.xpath.php ) ist natürlich etwas komplexer als CSS Selektoren, bietet aber viel mehr Möglichkeiten und keine Einschränkungen (da die CSS Selektoren halt auch "nur" darauf aufbauen). 
 
Nichts desto Trotz, sehr schöner Artikel!
Letzte Aktualisierung ( Montag, 17. August 2009 )
 
< Zurück   Weiter >