2009-04-09 3 views
5

Ich benutze PHP und libtidy, um zu versuchen, scrape was möglicherweise die schrecklichste und missformiert Verwendung von HTML-Tabellen in der Geschichte sein könnte. Die Site schließt nur wenige Tags für Tabelle, tr, td, Schriftart oder Fett und nistet durchgängig viele verschiedene Tabellenschichten innerhalb von Tabellen.Screencraping der hässlichste HTML, die Sie jemals in Ihrem Leben gesehen haben

Beispiel Snippet:

<center> 
<table border="1" bordercolor="#000000" cellspacing="0" cellpadding="0"> 
<tr> 
<td width="50%"> 
<center> 
Home Team - <b>Wildcats<td> 
<center> 
Away Team - <b>Polar Bears<tr> 
<td colspan="2"> 
<center> 
<b><font size="+1">Rosters<tr> 
<td valign="top"> 
<center> 
<table border="0" cellspacing="0"> 
<tr> 
<td> 
<font size="2">1&nbsp;<td> 
<font size="2">Baird, T<tr> 
<td> 
<font size="2">2&nbsp;<td> 
<font size="2">Knight, P<tr> 
<td> 
<font size="2">8&nbsp;<td> 
<font size="2">Miller, B<tr> 
<td> 
<font size="2">9&nbsp;<td> 
<font size="2">Huebsch, B<tr> 
<td> 
<font size="2">11&nbsp;<td> 
<font size="2">Buschmann, C<tr> 
<td> 
<font size="2">12&nbsp;<td> 
<font size="2">Reding, J<tr> 
<td> 
<font size="2">14&nbsp;<td> 
<font size="2">Simpson, S<tr> 
<td> 
<font size="2">27&nbsp;<td> 
<font size="2">Kupferschmidt, M<tr> 
<td> 
<font size="2">28&nbsp;<td> 
<font size="2">Anderson, D<tr> 
<td> 
<font size="2">31&nbsp;<td> 
<font size="2">Gehrts, J<tr> 
<td> 
<font size="2">39&nbsp;<td> 
<font size="2">McGinnis, G<tr> 
<td> 
<font size="2">42&nbsp;<td> 
<font size="2">Temple, B<tr> 
<td> 
<font size="2">44&nbsp;<td> 
<font size="2">Kemplin, A<tr> 
<td> 
<font size="2">77&nbsp;<td> 
<font size="2">Weiner, B<tr> 
<td> 
<font size="2">95&nbsp;<td> 
<font size="2"> 
Zytkoskie, D</table> 
<td valign="top"> 
<center> 
<table border="0" cellspacing="0"> 
<tr> 
<td> 
<font size="2">5&nbsp;<td> 
<font size="2">Mack, A<tr> 
<td> 
<font size="2">8&nbsp;<td> 
<font size="2">Foucault, R<tr> 
<td> 
<font size="2">11&nbsp;<td> 
<font size="2">Oberpriller, D *<tr> 
<td> 
<font size="2">12&nbsp;<td> 
<font size="2">Underwood, J<tr> 
<td> 
<font size="2">15&nbsp;<td> 
<font size="2">Oberpriller, M<tr> 
<td> 
<font size="2">19&nbsp;<td> 
<font size="2">Langfus, B<tr> 
<td> 
<font size="2">25&nbsp;<td> 
<font size="2">Carroll, R<tr> 
<td> 
<font size="2">30&nbsp;<td> 
<font size="2">Hirdler, T<tr> 
<td> 
<font size="2">33&nbsp;<td> 
<font size="2">Gibson, S<tr> 
<td> 
<font size="2">35&nbsp;<td> 
<font size="2">Marthaler, C<tr> 
<td> 
<font size="2">44&nbsp;<td> 
<font size="2">Yurik, J<tr> 
<td> 
<font size="2">58&nbsp;<td> 
<font size="2"> 
Gronemeyer, S</table> 
<tr> 
<td colspan="2"> 
<center> 
<b><font size="+1">Goals<tr> 
<td valign="top"> 
<center> 
<table border="1" cellspacing="0" width="100%"> 
<td> 
<b><font size="2">Player<td> 
<b><font size="2">Period<td> 
<b><font size="2">Time<td> 
<b><font size="2">Assist 1<td> 
<b><font size="2">Assist 2<td> 
<b><font size="2">SH<td> 
<b><font size="2">PP<tr> 
<td nowrap> 
<font size="2">Kupferschmidt,&nbsp;M<td> 
<font size="2">1<td> 
<font size="2">12:51<td nowrap> 
<font size="2">Kemplin,&nbsp;A<td nowrap> 
<font size="2">None<td> 
<font size="2"> 
<center> 
<td> 
<font size="2"> 
<center> 
<tr> 
<td nowrap> 
<font size="2">McGinnis,&nbsp;G<td> 
<font size="2">1<td> 
<font size="2">12:33<td nowrap> 
<font size="2">Huebsch,&nbsp;B<td nowrap> 
<font size="2">None<td> 
<font size="2"> 
<center> 
<td> 
<font size="2"> 
<center> 
<tr> 
<td nowrap> 
<font size="2">Kupferschmidt,&nbsp;M<td> 
<font size="2">2<td> 
<font size="2">16:01<td nowrap> 
<font size="2">None<td nowrap> 
<font size="2">None<td> 
<font size="2"> 
<center> 
<td> 
<font size="2"> 
<center> 
<tr> 
<td nowrap> 
<font size="2">Buschmann,&nbsp;C<td> 
<font size="2">3<td> 
<font size="2">00:38<td nowrap> 
<font size="2">None<td nowrap> 
<font size="2">None<td> 
<font size="2"> 
<center> 
<td> 
<font size="2"> 
<center> 
</table> 
<td valign="top"> 
<center> 
<table border="1" cellspacing="0" width="100%"> 
<td> 
<b><font size="2">Player<td> 
<b><font size="2">Period<td> 
<b><font size="2">Time<td> 
<b><font size="2">Assist 1<td> 
<b><font size="2">Assist 2<td> 
<b><font size="2">SH<td> 
<b><font size="2">PP<tr> 
<td nowrap> 
<font size="2">Oberpriller,&nbsp;D *<td> 
<font size="2">3<td> 
<font size="2">12:31<td nowrap> 
<font size="2">Gronemeyer,&nbsp;S<td nowrap> 
<font size="2">None<td> 
<font size="2"> 
<center> 
<td> 
<font size="2"> 
<center> 
</table> 
<tr> 
<td colspan="2"> 
<center> 
<b><font size="+1">Penalties<tr> 
<td valign="top"> 
<center> 
<table border="1" cellspacing="0" width="100%"> 
<td> 
<b><font size="2">Player<td> 
<font size="2"><b>Period<td> 
<font size="2"><b>Minutes<td> 
<font size="2"><b>Offense<td> 
<font size="2"><b>Start<td> 
<font size="2"><b>Expired<tr> 
<td nowrap> 
<font size="2">Buschmann,&nbsp;C<td> 
<font size="2"> 
<center> 
3<td> 
<font size="2"> 
<center> 
2<td> 
<font size="2">Interference<td> 
<font size="2">11:11<td> 
<font size="2">09:11<tr> 
<td nowrap> 
<font size="2">Buschmann,&nbsp;C<td> 
<font size="2"> 
<center> 
3<td> 
<font size="2"> 
<center> 
2<td> 
<font size="2">Unsportmanlike Conduct<td> 
<font size="2">03:26<td> 
<font size="2">01:26<tr> 
<td nowrap> 
<font size="2">Bench<td> 
<font size="2"> 
<center> 
3<td> 
<font size="2"> 
<center> 
2<td> 
<font size="2">Too Many Men<td> 
<font size="2">01:46<td> 
<font size="2"> 
00:00</table> 
<td valign="top"> 
<center> 
<table border="1" cellspacing="0" width="100%"> 
<td> 
<b><font size="2">Player<td> 
<font size="2"><b>Period<td> 
<font size="2"><b>Minutes<td> 
<font size="2"><b>Offense<td> 
<font size="2"><b>Start<td> 
<font size="2"><b>Expired<tr> 
<td nowrap> 
<font size="2">Marthaler,&nbsp;C<td> 
<font size="2"> 
<center> 
1<td> 
<font size="2"> 
<center> 
2<td> 
<font size="2">Interference<td> 
<font size="2">01:19<td> 
<font size="2">16:19<tr> 
<td nowrap> 
<font size="2">Underwood,&nbsp;J<td> 
<font size="2"> 
<center> 
2<td> 
<font size="2"> 
<center> 
2<td> 
<font size="2">Interference<td> 
<font size="2">12:32<td> 
<font size="2">10:32<tr> 
<td nowrap> 
<font size="2">Marthaler,&nbsp;C<td> 
<font size="2"> 
<center> 
3<td> 
<font size="2"> 
<center> 
2<td> 
<font size="2">Interference<td> 
<font size="2">11:39<td> 
<font size="2"> 
09:39</table> 
<tr> 
<td colspan="2"> 
<center> 
<font size="+1"><b>Goalies<tr> 
<td> 
<center> 
<table border="1" cellspacing="0" width="100%"> 
<td> 
<b><font size="2">Name<td> 
<font size="2"><b>Shots<td> 
<font size="2"><b>Goals<tr> 
<td> 
<font size="2">Baird,&nbsp;T<td> 
<font size="2">20<td> 
<font size="2">1<tr> 
<td> 
<font size="2"><b>Open Net<td> 
<td> 
<font size="2"> 
0</table> 
<td> 
<center> 
<table border="1" cellspacing="0" width="100%"> 
<td> 
<b><font size="2">Name<td> 
<font size="2"><b>Shots<td> 
<font size="2"><b>Goals<tr> 
<td> 
<font size="2">Hirdler,&nbsp;T<td> 
<font size="2">42<td> 
<font size="2"> 

Magisch, alle Browser diese einfach gut zu machen scheinen. PHPTidy schafft es, alles zu verstehen, aber die Tabellen sind so tief und fast zufällig verschachtelt, dass es mit DOM XPath sehr schwierig ist, sie zu durchlaufen.

Hat jemand irgendwelche Empfehlungen für andere Ansätze, um dies anzugehen?

Post-Mortem: Nach dem viel zu viele belgische Weizenbiere und meinen Code zu beschmutzen up wirklich gut Ich habe großartige Ergebnisse durch alle Tags über strip_tags Entfernen() mit dem Tisch, tr und td, dann durch libtidy läuft. Es ist jetzt schön formatiert und sehr leicht zu durchlaufen. Scheint so, als ob es nur ein wenig massieren müsste, bevor es an den Parser gesendet wird.

+0

Die wirklich traurige Sache ist, habe ich Schlimmeres gesehen !!! – SirDemon

+0

abgeordnet. Es ist schlimmer, wenn Sie Code wie diesen mit PHP vermischt sehen. – epochwolf

+0

das SO Prettify-Skript kann diese HTML nicht analysieren – bendewey

Antwort

3

Es gibt ein paar Tricks, mit denen Sie sehr vorhersagbare Strukturen wie Tabellen bereinigen können. Bevor Sie HTML ordentlich ausführen, können Sie Regex oder etwas verwenden, um nach <tr> 's und <td>' s zu suchen, denen ein weiterer <tr> oder <td> folgt, und fügen Sie den entsprechenden näheren unmittelbar davor ein. Es gibt einige zusätzliche Tricks für die Aufnahme von Tabellen innerhalb einer <td>, aber nichts, was unmöglich zu handhaben ist. Beginne einfach mit der Lokalisierung der innersten Struktur und bewege dich von dort nach außen.

Das echte Puzzle ist Dinge wie nicht geschlossene <div> 's und <p>' s, die viel schwieriger sein, mit ihren entsprechenden (oder fehlenden) Closers zusammenpassen.

0

Vielleicht haben Sie mehr Glück, die Ergebnisse, die Sie brauchen, mit regulären Ausdrücken zu scrappen, anstatt sie als XML zu analysieren.

2

Wenn Sie für andere Sprachen wie Python offen sind, ist Beautiful Soup hervorragend geeignet, schlecht geschriebenes HTML zu rekonstruieren. Ich habe gerade versucht, Ihren HTML-Code durch das folgende Snippet zu lesen, und es ist jetzt gut lesbar.

#!/usr/bin/env python 

from BeautifulSoup import BeautifulSoup 

html = "long string of html" 
soup = BeautifulSoup(html) 
print soup.prettify() 
+0

Ja - für den Rekord bin ich nicht unbedingt abhängig von PHP, um dies zu tun. –

+0

Auf jeden Fall schöne Suppe dann. Es ist bei weitem der beste Screen Scraper, den ich verwendet habe. Es gibt auch eine Ruby-Version, falls Sie Python bevorzugen. –

2

Wenn Sie Daten suchen, würde ich nur entfernen Sie alle html und behandeln es als line-by-line Roh-Eingangs. Sie können die strip_tags Funktion verwenden.

$clean = strip_tags($input); 

// example: <p>Test paragraph.</p> <a href="#fragment">Other text</a> 
// returns: Test paragraph. Other text 
0

I verwendet XPath mit lxml der Python-Bibliothek IMDB Top 250 Seiten zu analysieren. View the source für sich selbst zu sehen, wie schlimm es ist.

Der folgende Code parst eine gespeicherte IMDB Top 250 Seite (top250.html) und speichert die extrahierten Informationen in einer SQLite-Datenbank (top250.db)

import sqlite3 
from lxml import html 

tree = html.parse('top250.html') 

class TopMovie(object): 
    base_xpath = "/html/body/div/div[2]/layer/div[3]/table/tr/td[3]/div/table/tr/td/table/tr[%d]" 

    def __init__(self, num): 
     self.rank = num 
     self.xpath = self.base_xpath % (self.rank + 1) 

    def rating(self): 
     return tree.xpath(self.xpath + '/td[2]/font')[0].text 

    def link(self): 
     return tree.xpath(self.xpath + '/td[3]/font/a')[0].values()[0] 

    def title(self): 
     return tree.xpath(self.xpath + '/td[3]/font')[0].text_content() 

    def votes(self): 
     return tree.xpath(self.xpath + '/td[4]/font')[0].text 


def main(): 
    conn = sqlite3.connect('top250.db') 
    conn.execute("""DROP TABLE IF EXISTS movies""") 
    conn.execute(""" 
     CREATE TABLE movies (
      id INTEGER PRIMARY KEY, 
      title TEXT, 
      link TEXT, 
      rating TEXT, 
      votes INTEGER 
     )""") 

    for n in xrange(1, 251): 
     m = TopMovie(n) 
     query = r'INSERT INTO movies VALUES (%d, "%s", "%s", "%s", "%s")' \ 
      % (n, m.title(), m.link(), m.rating(), m.votes().replace(',', '')) 
     conn.execute(query) 

    conn.commit() 
    conn.close() 


if __name__ == "__main__": 
    main() 
Verwandte Themen