Das Problem
Ich habe mir sagen lassen, dass es auch hier bei uns Leute gibt die in einer Fantasy League mitspielen. Irgendwie werden da virtuelle aber real existierende Sportler gezogen und verkauft und nach einem speziellen Algorithmus werden Punkte verteilt, die abhängig von den tatsächlichen Resultaten sind, die dieser Spieler erzielt. Nun, auf jeden Fall wird da viel mit Statistiken gewurstelt. Ein Fantasy League-Mitglied ist an mich herangetreten, weil er die online publizierten Resultate der Skaters und Goalies der NHL in einem Excel haben wollte.
Zuerst dachte ich, das sei ein Fall für Dapper. War es aber nicht, da auf der Webpage reine Text-Exporte waren.
Die Erfahrung hat gezeigt, dass die Form der Ausgabe auf diesen Seiten oftmals ändert und man sich auf so wenig wie möglich verlassen sollte.
Die Felder dieser Tabelle haben keine Trennzeichen, sondern eine feste Breite und sind links- oder rechtsbündig formatiert.
Einige Punkte der Lösung
Download der Webseite in eine Variable
Zuerst muss man mal an die Seite rankommen. In PHP den Inhalt einer URL in einen String laden ist in der Theorie relativ einfach. In der Praxis jedoch ist aus Sicherheitsgründen der Zugriff auf URLs für die file* Funktionen oftmals eingeschränkt. Nunja, dann wird halt ein cURL-Fallback mit eingebaut, so dass wir auf jeden Fall in $page ein Array aus den Zeilen der HTML-Datei haben:
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_USERAGENT, 'User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.6) Gecko/20070723 Iceweasel/2.0.0.6 (Debian-2.0.0.6-0etch1+lenny1)');
curl_setopt ($ch, CURLOPT_HEADER, 0);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec ($ch);
curl_close ($ch);
$page=explode("\n",$result);
}
Überschriften auslesen
Ich lese die Tabellenübberschriften mit einem regulären Ausdruck aus (man beachte dass die Sternchen sich der Formatierung (links/rechts) anpassen), aus dem danach die Spaltenbreiten gelesen werden können. Aus den Spaltenbreiten wiederum kann ein regulärer Ausdruck gebaut werden über den auf die Werte zugegriffen werden kann.
Beispielsweise steht auf der Webpage:
daraus lese ich mit folgendem Regexp die Feldbreiten:
Damit baue ich dynamisch einen neuen regulären Ausdruck, der die Tabellendaten auslesen kann:
Codiert sieht es so aus. $tline im Codebeispiel beinhaltet eine getrimmte Zeile aus dem HTML.
if(preg_match('@^(NAME *)(POS *)(GP)( *G)( *A)( *PTS)( *SOG)( *\\+/\\-)( *PIM)( *PPG)( *SHG)$@',$tline,$matches)) {
if(!$inresults) {
// Nach den Überschriften kommen die Tabelleneinträge
$inresults=true;
// Überschriften auslesen
$headercaptions=preg_split('/ +/', $tline, -1, PREG_SPLIT_NO_EMPTY);
// Überschriften ausgeben
echo "\r\n".join("\t",$headercaptions)."\r\n";
}
// Wie breit ist ein Feld (in Zeichen)
$sizes=array();
for($i=1;$i<count($matches);$i++) {
$sizes[$i-1]=strlen($matches[$i]);
}
// Suchmuster für Einträge aufbauen
$searchpattern="";
foreach($sizes as $size) {
$searchpattern.='(.{'.$size.'})';
}
//print $searchpattern."<br />";
$searchpattern='/^'.$searchpattern.'$/';
continue;
}
// Tabellenzeilen auslesen
if($inresults && preg_match($searchpattern, $tline, $matches)) {
$row=array();
for($i=1; $i<count($matches); $i++) {
$row[]=trim($matches[$i]);
}
// Und ausgeben
echo join("\t",$row)."\r\n";
continue;
}
Ausgabe als Excel
Hier bescheisse ich… Ich gebe nur eine tabulatorseparierte Liste aus. Excel schnallts, OpenOffice leider nicht (hat da wer eine gescheitere Lösung? HTML-Tabellen?)…
Zuerst die Headers:
Einzelne Zellen werden mittels Tabulator (\t) voneinander getrennt, Zeilenenden werden durch "\r\n" markiert:
Die Lösung
Die komplette Lösung kann hier fantasy-league heruntergeladen werden und eine Demo gibts auf apps.oncode.info…