2009-04-09 9 views
5

Używam PHP i libtidy do próby zeskanowania czegoś, co może być najbardziej przerażającym i zniekształconym użyciem tabel HTML w historii. Witryna zamyka kilka tagów table, tr, td, font lub bold i konsekwentnie umieszcza wiele różnych warstw tabel w tabelach.Screenscraping najgorszy HTML jaki kiedykolwiek widziałeś w swoim życiu

Przykładowy fragment:

<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"> 

Magicznie, wszystkie przeglądarki wydają się uczynić to w porządku. PHPTidy radzi sobie dobrze z tym wszystkim, ale tabele są zagnieżdżone tak głęboko i prawie losowo, że trudno jest je przetrawić za pomocą DOM XPath.

Czy ktoś ma jakieś zalecenia dotyczące innych sposobów podejścia do tego?

POUBOJOWE: Po zbyt wiele belgijskich piw pszenicy i brudząc się mój kod prawdziwy dobry Mam wspaniałe rezultaty usuwając wszystkie znaczniki poprzez strip_tags(), z wyjątkiem tabeli, tr i td, a następnie uruchomienie go przez libtidy. Jest teraz pięknie sformatowany i bardzo łatwo przemierzany. Wydaje się, że po prostu trzeba trochę masować przed wysłaniem go do analizatora składni.

+0

Naprawdę smutne jest, widziałem gorsze !!! – SirDemon

+0

Oddelegowany. Gorzej, gdy zobaczysz kod taki jak ten z PHP wymieszanym z nim. – epochwolf

+0

Skrypt SO Prettify nie może parsować tego html – bendewey

Odpowiedz

3

Istnieje kilka sztuczek, których można użyć do czyszczenia wysoce przewidywalnych struktur, takich jak tabele. Przed uruchomieniem HTML, możesz użyć Regex lub czegoś, aby wyszukać <tr> i , po których następują inne <tr> lub <td>, i wstawić odpowiedni bliższy tuż przed nim. Istnieje pewne dodatkowe oszustwo do umieszczania tabel wewnątrz <td>, ale nic, co jest niemożliwe do obsłużenia. Zacznij od zlokalizowania najgłębszej struktury i stamtąd na zewnątrz.

Prawdziwą łamigłówką są rzeczy takie jak nie zamknięte <div> i <p>, które mogą być znacznie trudniejsze do dopasowania do ich odpowiednich (lub brakujących) elementów zamykających.

0

Być może lepszym rezultatem będzie skrobanie potrzebnych wyników za pomocą wyrażeń regularnych, zamiast analizowania ich jako XML.

2

Jeśli jesteś otwarty na inne języki, takie jak Python, Beautiful Soup świetnie nadaje się do rekonstrukcji słabo napisanego kodu HTML. Po prostu próbowałem uruchomić twój HTML przez poniższy fragment i jest teraz całkiem czytelny.

#!/usr/bin/env python 

from BeautifulSoup import BeautifulSoup 

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

Tak - dla zapisu nie koniecznie jestem zależny od PHP, aby to zrobić. –

+0

Zdecydowanie sprawdź Beautiful Soup then. Jest to zdecydowanie najlepszy skrobaczka, z której korzystałem. Dostępna jest również wersja Ruby, na wypadek gdybyś wolał Python. –

2

Jeśli szukasz danych, chciałbym tylko usunąć wszystkie html i obsługiwać go jako linia po linii wejściowej surowe. Możesz użyć funkcji strip_tags.

$clean = strip_tags($input); 

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

użyłem XPath z lxml biblioteki Pythona do analizowania IMDB Top 250 strony. View the source dla siebie, aby zobaczyć, jak źle jest.

Poniższy kod analizuje zapisaną IMDB Top 250 strony (top250.html) i przechowuje uzyskane informacje w bazie danych SQLite (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() 
Powiązane problemy