2012-04-02 17 views
13

Ho un tavolo che ho bisogno di analizzare, in particolare è un programma scolastico con 4 blocchi di tempo e 5 blocchi di giorni per ogni settimana. Ho tentato di analizzarlo, ma onestamente non sono arrivato molto lontano perché sono rimasto bloccato su come gestire gli attributi rowspan e colspan, perché essenzialmente significa che c'è una mancanza di dati che devo continuare.Analizzare un tavolo con rowspan e colspan

Come esempio di ciò che voglio fare, ecco una tabella:

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

Voglio prendere quel tavolo e convertirlo in questa lista:

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

In questo momento sono ottenere una lista piatta, simile a questo:

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

ma in forma dizionario, le informazioni riguardanti il ​​numero di colonne e ro ws it span, una descrizione di esso e in quale settimana è.

Ovviamente questo deve funzionare per ogni possibilità di rowspan/colspan e per più settimane nella stessa tabella.

L'html non è così pulito come l'ho ritratto, ci sono molti attributi che ho omesso, e il testo ovviamente non è così netto come 1,2,3,4 ma piuttosto blocchi di testo descrittivo. Ma se potessi ottenere questa parte risolta, dovrebbe essere abbastanza facile da incorporare in ciò che ho già scritto.

Ho usato lxml.html e Python per farlo, ma sono aperto a utilizzare altri moduli se fornisce una soluzione più semplice.

Spero che qualcuno possa aiutarmi, perché davvero non so cosa fare.

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> 

Questo mi sta causando alcuni problemi, questo è l'output

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

Con il codice fornito da reclosedev, cosa devo cambiare per adattarla in modo che le uscite

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

Invece?

EDIT2: Utilizzando la nuova funzione di reclosedev, è avvicinando una soluzione, ma ci sono ancora casi in cui non riesce a mettere le cellule in modo corretto:

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

Con questo, la tabella originale mostra come tale:

[ 
[' ', ' 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' , ' '] 
] 

Ma le nuove uscite di chiamata in questo modo:

[ 
[' ', ' 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

Sarebbe davvero d'aiuto se poteste mostrarci quale codice state attualmente utilizzando e quale output state effettivamente ottenendo, invece di un output che è simile a quello che state ottenendo. –

risposta

11

UPDATE (rimosso funzione precedente)

UPDATE2 fissa e semplificato.

La mia prima funzione era sbagliata. Ecco un altro uno, si sta lavorando, ma ha bisogno di prove:

#!/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> 

uscita:

[['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

Ci sono voluti alcuni per farlo funzionare su quello che avevo bisogno di fare, in particolare avevo bisogno di dividere l'intera tabella in tabelle più piccole ed eliminare alcune righe e colonne all'interno di quei tavoli, ma alla fine ha funzionato. Grazie mille. – Atheuz

+0

reclosedev: ho modificato il mio post principale, con un problema su come gestire un caso specifico. Ti sarei grato se potessi rispondere. – Atheuz

+0

@Atheuz, vedere la risposta aggiornata. La prima funzione era davvero sbagliata :(, ma questa dovrebbe funzionare – reclosedev

1

Per chi vuole un Python 3 e la soluzione BeautifulSoup,

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) 

Uso:

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

Questo è NON ottimizzato. Ho scritto questo per il mio script di una volta.

Problemi correlati