Web Scraping auf die einfache Art

Als Webentwickler stand ich schon oft vor dem Problem, dass ich gerne Informationen auf meiner Website anzeigen würde, diese Informationen auch existieren, nur leider nicht auf meinem Webserver. Das kann zum Beispiel das Kinoprogramm meiner Stadt sein. Dafür gibt es verschiedene Websites, die das Programm darstellen und die ihre Daten wiederum vermutlich von den Kinos geschickt bekommen, bloß ich komm nicht dran.

Natürlich könnte man ein Script schreiben, das mit Regulären Ausdrücken und etwas Programmierung die Daten extrahiert. Diese Herangehensweise ist aber mühsam, insbesondere wenn sich der Aufbau der Seiten ändert. Beim Versuch, ein solches Kinoprogramm zu scrapen stellte ich z.B. fest, dass das HTML offenbar nicht von einem System generiert, sondern manuell per copy&paste aktualisiert wurde, natürlich mit entsprechenden Fehlern. Diese führten dazu, dass die Regulären Ausdrücke nicht mehr trafen und keine Daten mehr extrahiert werden konnten.

Webseiten sind allerdings normalerweise keine wahllosen Aneinanderreihungen von Buchstaben, denen man nur mit der RegEx-Keule beikommen könnte. Sie sind strukturiert, und nicht selten sogar gültige XML-Dokumente. Daher können wir uns vorhandene Technolgoien zu Nutze zu machen, um auf höherer Ebene bequemer an die Daten heranzukommen. Hier das Rezept:

  1. Die URL holen, z.B. mit dem HTTP wrapper oder CURL.
  2. Die Webseite mit einem XML-Parser einlesen, z.B. mit simpleXML oder DOM-XML.
  3. Mit XPath Elemente des Objektbaumes herauspicken.
  4. Die gefundenen Daten abspeichern, in aller Regel in eine SQL-Tabelle.

Dieses Vorgehen führt schnell zum Ziel und ist so einfach, dass der Aufwand für neue Seiten gering bleibt. Zu beachten ist dabei, dass die Fehlertoleranz der meisten XML-Parser viel geringer als die XML-Konformität der meisten Webseiten ist. Kaum eine Webseite besteht aus validem XML und viele haben so schwerwiegende Fehler, dass simpleXML sie nicht scannen kann. DOM-XML ist wesentlich toleranter und daher das Mittel der Wahl. Eine Testanwendung damit könnte so aussehen:

$oldSetting = libxml_use_internal_errors(TRUE);
libxml_clear_errors();
$html = new DOMDocument();
$html->loadHtmlFile('http://helloworldsite.he.funpic.de/hellotoc.htm');
$xpath = new DOMXPath($html);
$links = $xpath->query("//small/p/a");
$return = array();
foreach ($links as $item) {
$newDom = new DOMDocument;
$newDom->appendChild($newDom->importNode($item, TRUE));
$xpath = new DOMXPath($newDom);
$title = trim($xpath->query("//div[@id='productTitle']")->item(0)->nodeValue);
$price = trim($xpath->query("//li[@class='price']/span[@class='value']")
->item(0)->nodeValue);
$return[] = array(
'title' => $title,
'price' => $price,
);
}
print_r($return);
libxml_clear_errors();
libxml_use_internal_errors($oldSetting);

Dieser Code ist für alle Seiten identisch mit zwei Ausnahmen, der URL und einer oder mehreren XPath-Angaben. Daten aus Webseiten zu extrahieren erfordert also keine aufwendige Programmierung mehr sondern es geht nur noch darum, XPath-Angaben zu formulieren, die die relevanten Daten treffen. Aus diesem Grund werde ich XPath einen weiteren Artikel widmen. Stay tuned.