2012-04-02 9 views
13

Ich habe eine Tabelle, die ich analysieren muss, speziell ist es ein Schulzeitplan mit 4 Blöcken von Zeit und 5 Blöcke von Tagen für jede Woche. Ich habe versucht, es zu analysieren, aber ehrlich gesagt bin ich nicht sehr weit gekommen, weil ich mit dem Umgang mit den Spalten rspspan und colspan festhalte, weil sie im Wesentlichen bedeuten, dass es an Daten mangelt, die ich fortführen muss.Analysieren einer Tabelle mit rowspan und colspan

Als Beispiel dafür, was ich tun möchte, ist hier eine Tabelle:

<tr> 
    <td colspan="2" rowspan="4">#1</td> 
    <td rowspan="4">#2</td> 
    <td rowspan="2">#3</td> 
    <td rowspan="2">#4</td> 
</tr> 

<tr> 
</tr> 

<tr> 
    <td rowspan="2">#5</td> 
    <td rowspan="2">#6</td> 
</tr> 

<tr> 
</tr> 

ich diesen Tisch nehmen wollen und es in dieser Liste konvertieren:

[[1,1,2,3,4], 
[1,1,2,3,4], 
[1,1,2,5,6], 
[1,1,2,5,6]] 

Im Moment bin ich eine flache Liste, ähnlich dieser:

[1,2,3,4,5,6] 

Aber in Wörterbuchform, mit Informationen, wie viele Spalten und ro ws es überspannt, eine Beschreibung davon und welche Woche es ist.

Offensichtlich muss dies für jede Möglichkeit von rowspan/colspan und für mehrere Wochen in der gleichen Tabelle arbeiten.

Die HTML ist nicht so sauber wie ich es porträtiert habe, es gibt eine Menge Attribute, die ich weggelassen habe, und der Text ist offensichtlich nicht so sauber geschnitten wie 1,2,3,4, sondern Blöcke von beschreibender Text. Aber wenn ich diesen Teil lösen könnte, sollte es leicht genug sein, in das zu integrieren, was ich bereits geschrieben habe.

Ich habe lxml.html und Python verwendet, um dies zu tun, aber ich bin offen für die Verwendung anderer Module, wenn es eine einfachere Lösung bietet.

Ich hoffe, jemand kann mir helfen, weil ich wirklich nicht weiß, was zu tun ist.

EDIT:

<table> 
    <tr> 
     <td> </td> 
     <td> </td> 
     <td> </td> 
     <td rowspan="4">Thing</td> 
     <td> </td> 
    </tr> 
    <tr> 
     <td> </td> 
     <td> </td> 
     <td> </td> 
     <td> </td> 
    </tr> 
    <tr> 
     <td> </td> 
     <td> </td> 
     <td> </td> 
     <td> </td> 
    </tr> 
    <tr> 
     <td> </td> 
     <td> </td> 
     <td> </td> 
     <td> </td> 
    </tr> 
</table> 

Dies wird mir einige Probleme verursacht, wird dies durch reclosedev bereitgestellt

[' ', ' ', ' ', 'Thing', ' '] 
[' ', ' ', ' ', ' ', ' '] 
[' ', ' ', ' ', ' ', ' '] 
[' ', ' ', ' ', ' ', ' '] 

Mit dem Code ausgibt, was muss ich es anpassen ändern, so dass es

ausgibt
[' ', ' ', ' ', 'Thing', ' '] 
[' ', ' ', ' ', 'Thing', ' '] 
[' ', ' ', ' ', 'Thing', ' '] 
[' ', ' ', ' ', 'Thing', ' '] 

Stattdessen?

EDIT2: Mit reclosedev der neuen Funktion, es ist eine Lösung nähern, aber es gibt immer noch Fälle, in denen es nicht richtig Zellen platzieren:

<table> 
    <tr> 
     <td> </td> 
     <td rowspan="2"> DMAT Aud. 6 </td> 
     <td rowspan="4"> Exam</td> 
     <td rowspan="2"> DMAT Aud. 7</td> 
     <td> </td> 
    </tr> 
    <tr> 
     <td> </td> 
     <td rowspan="2"> CART Aud. 4</td> 
    </tr> 
    <tr> 
     <td> </td> 
     <td rowspan="2"> CART Aud. 4</td> 
     <td rowspan="2"> OOP Aud. 7</td> 
    </tr> 
    <tr> 
     <td> </td> 
     <td> </td> 
    </tr> 
</table> 

Damit die ursprüngliche Tabelle zeigt es als solches:

[ 
[' ', ' DMAT Aud. 6 ', ' Exam', ' DMAT Aud. 7', ' '], 
[' ', ' DMAT Aud. 6 ', ' Exam', ' DMAT Aud. 7', ' CART Aud. 4'], 
[' ', ' CART Aud. 4' , ' Exam', ' OOP Aud. 7' , ' CART Aud. 4'], 
[' ', ' CART Aud. 4' , ' Exam', ' OOP Aud. 7' , ' '] 
] 

Aber die neuen Rufausgänge dies:

[ 
[' ', ' DMAT Aud. 6 ', ' Exam', ' DMAT Aud. 7', ' '], 
[' ', ' DMAT Aud. 6 ', ' Exam', ' DMAT Aud. 7', ' CART Aud. 4'], 
[' ', ' CART Aud. 4' , ' Exam', ' CART Aud. 4', ' OOP Aud. 7'], 
[' ', ' CART Aud. 4' , ' Exam', ' OOP Aud. 7' , ' '] 
] 
+3

Es würde uns wirklich helfen, wenn Sie uns zeigen könnten, welchen Code Sie gerade verwenden und welche Ausgabe Sie tatsächlich erhalten, anstatt eine Ausgabe, die ähnlich ist, was Sie bekommen. –

Antwort

11

UPDATE (entfernt vorherige Funktion)

UPDATE2 fixiert und vereinfacht.

Meine erste Funktion war falsch. Hier ist ein weiteres, es funktioniert aber braucht Tests:

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
from collections import defaultdict 


def table_to_list(table): 
    dct = table_to_2d_dict(table) 
    return list(iter_2d_dict(dct)) 


def table_to_2d_dict(table): 
    result = defaultdict(lambda : defaultdict(unicode)) 
    for row_i, row in enumerate(table.xpath('./tr')): 
     for col_i, col in enumerate(row.xpath('./td|./th')): 
      colspan = int(col.get('colspan', 1)) 
      rowspan = int(col.get('rowspan', 1)) 
      col_data = col.text_content() 
      while row_i in result and col_i in result[row_i]: 
       col_i += 1 
      for i in range(row_i, row_i + rowspan): 
       for j in range(col_i, col_i + colspan): 
        result[i][j] = col_data 
    return result 


def iter_2d_dict(dct): 
    for i, row in sorted(dct.items()): 
     cols = [] 
     for j, col in sorted(row.items()): 
      cols.append(col) 
     yield cols 


if __name__ == '__main__': 
    import lxml.html 
    from pprint import pprint 

    doc = lxml.html.parse('tables.html') 
    for table_el in doc.xpath('//table'): 
     table = table_to_list(table_el) 
     pprint(table) 

tables.html:

<table border="1"> 
    <tr> 
     <td>1 </td> 
     <td>1 </td> 
     <td>1 </td> 
     <td rowspan="4">Thing</td> 
     <td>1 </td> 
    </tr> 
    <tr> 
     <td>2 </td> 
     <td>2 </td> 
     <td>2 </td> 
     <td>2 </td> 
    </tr> 
    <tr> 
     <td>3 </td> 
     <td>3 </td> 
     <td>3 </td> 
     <td>3 </td> 
    </tr> 
    <tr> 
     <td>4 </td> 
     <td>4 </td> 
     <td>4 </td> 
     <td>4 </td> 
    </tr> 
</table> 

<table border="1"> 
<tr> 
    <td colspan="2" rowspan="4">#1</td> 
    <td rowspan="4">#2</td> 
    <td rowspan="2">#3</td> 
    <td rowspan="2">#4</td> 
</tr> 
<tr></tr> 
<tr> 
    <td rowspan="2">#5</td> 
    <td rowspan="2">#6</td> 
</tr> 
<tr></tr> 
</table> 

Ausgang:

[['1 ', '1 ', '1 ', 'Thing', '1 '], 
['2 ', '2 ', '2 ', 'Thing', '2 '], 
['3 ', '3 ', '3 ', 'Thing', '3 '], 
['4 ', '4 ', '4 ', 'Thing', '4 ']] 
[['#1', '#1', '#2', '#3', '#4'], 
['#1', '#1', '#2', '#3', '#4'], 
['#1', '#1', '#2', '#5', '#6'], 
['#1', '#1', '#2', '#5', '#6']] 
+0

Es brauchte einiges, um es zu arbeiten, was ich brauchte, insbesondere musste ich die gesamte Tabelle in kleinere Tabellen aufteilen und einige Zeilen und Spalten in diesen Tabellen löschen, aber am Ende funktionierte es. Vielen Dank. – Atheuz

+0

reclosedev: Ich habe meine Hauptpost bearbeitet, mit einem Problem, wie man mit einem bestimmten Fall umgehen soll. Ich wäre dankbar, wenn Sie es beantworten könnten. – Atheuz

+0

@Atheuz, siehe aktualisierte Antwort. Erste Funktion war wirklich falsch :(, aber das sollte funktionieren. – reclosedev

1

Für diejenigen, die eine Python 3 und BeautifulSoup Lösung wollen,

def table_to_2d(table_tag): 
    rows = table_tag("tr") 
    cols = rows[0](["td", "th"]) 
    table = [[None] * len(cols) for _ in range(len(rows))] 
    for row_i, row in enumerate(rows): 
     for col_i, col in enumerate(row(["td", "th"])): 
      insert(table, row_i, col_i, col) 
    return table 


def insert(table, row, col, element): 
    if row >= len(table) or col >= len(table[row]): 
     return 
    if table[row][col] is None: 
     value = element.get_text() 
     table[row][col] = value 
     if element.has_attr("colspan"): 
      span = int(element["colspan"]) 
      for i in range(1, span): 
       table[row][col+i] = value 
     if element.has_attr("rowspan"): 
      span = int(element["rowspan"]) 
      for i in range(1, span): 
       table[row+i][col] = value 
    else: 
     insert(table, row, col + 1, element) 

Verbrauch:

soup = BeautifulSoup('<table><tr><th>1</th><th>2</th><th>5</th></tr><tr><td rowspan="2">3</td><td colspan="2">4</td></tr><tr><td>6</td><td>7</td></tr></table>', 'html.parser') 
print(table_to_2d(soup.table)) 

Dies ist NICHT optimiert. Ich habe das für mein einmaliges Skript geschrieben.

Verwandte Themen