• Publicidad

Obtener datos tabla HTML

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Re: Obtener datos tabla HTML

Notapor explorer » 2012-04-03 09:32 @438

En efecto, me refiero a los rowspan...

Fíjate en la segunda tabla, segunda fila de datos: en realidad son dos filas, ya que las celdas de Receiver, Time Lag, y Last Modify Time están compartidas en las dos filas, con sendos rowspan.

No es un problema sencillo el desenrollar esas celdas compartidas...

La solución sería usar el módulo HTML::TableExtract, que con la opción gridmap se puede controlar la forma de extracción de los datos, en árbol o en rejilla, ocupándose él de estos casos de celdas fantasma.

Usando el método rows() nos devolverá el contenido de las filas, pero en las celdas fantasma su contenido será undef, por lo que habrá que recordar el valor de la celda correspondiente de la fila anterior para saber el verdadero de la celda.

O mejor aún: usar space(), que sí hace todo ese trabajo. Lo único que hay que hacer es un doble bucle de filas y columnas de la tabla, extraer la información con space(), y guardarlo en un array bidimensional, o como indicas más arriba, en un array de hashes.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Publicidad

Re: Obtener datos tabla HTML

Notapor explorer » 2012-04-03 19:42 @862

He encontrado una solución con Mojolicious, ya que he visto que las tablas, sus celdas expandidas, se concentran en la primera parte de cada fila (la parte izquierda de cada fila). Si las tablas siguen esa regla, entonces es fácil "parchear" la solución: si una fila tiene menos celdas que la anterior, quiere decir que tenemos que insertarle por delante celdas que hay en la fila anterior, ya que son celdas expandidas (rowspan="2").

Con este programa:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use Modern::Perl '2012';
  3. use Mojo::Asset::File;
  4. use Mojo::DOM;
  5. use List::MoreUtils 'zip';
  6.  
  7. @ARGV == 2 or die "Uso: $0 <archivo.html> <master>\n";          # Comprobamos los argumentos
  8.  
  9. my($archivo, $master) = @ARGV;                                  # Leemos los argumentos
  10.  
  11. my $file_asset = Mojo::Asset::File->new(path => $archivo);      # Crear acceso al archivo
  12. my $mojo = Mojo::DOM->new($file_asset->slurp);                  # Leer el archivo y analizar
  13.  
  14. ### Buscar el master
  15. # Buscamos el párrafo que contiene el master, mirando uno por uno
  16. my $master_collection
  17.     = $mojo->find("p center[class=page-subtitle] a");           # La colección de master
  18.  
  19. my $posicion = -1;                                              # Posición en la que estará nuestro master
  20. my $i = 0;                                                      # Contador de posición actual
  21. for my $parrafo_master ($master_collection->each) {             # Para cada master
  22.     if ($parrafo_master->text eq $master) {                     # Encontrado
  23.         $posicion = $i;                                         # Lo anotamos
  24.         last;                                                   # y salimos
  25.     }
  26.  
  27.     $i++;                                                       # No encontrado, seguimos
  28. }
  29.  
  30. die "ERROR: No encuentro master [$master] en la hoja.\n"
  31.     if $posicion == -1;
  32.  
  33. say "Tabla número $posicion";
  34.  
  35. ### Extraemos la tabla correspondiente
  36. my $tabla = $mojo->find("table[class=bgColor9]")->[$posicion];
  37.  
  38. ### Filas de la tabla
  39. my @filas = $tabla->find("tr")->each;
  40. say "Número de filas: ", scalar @filas -2;
  41.  
  42. ### Fila de cabecera: suponemos que siempre es la fila 1
  43. # Recorremos la fila extrayendo el texto de cada celda
  44. my @headers = $filas[1]->find("th")->map(sub{shift->text})->each;
  45. $" = ']['; say "[@headers]";
  46.  
  47. ### Procesado
  48. # Recorremos de la fila 2 hasta el final.
  49. # Si el número de celdas es menor que la línea anterior,
  50. # insertamos delante las celdas que faltan, copiándolas de la fila anterior.
  51. # Luego, la fila es almacena como hash, usando las celdas de cabecera como claves.
  52. # El hash se almacena como un elemento del array @registros.
  53. my @registros;                                  # Resultado final: un array de hash
  54.  
  55. my @fila_anterior = ();                         # Necesario por si tenemos que duplicar contenido
  56.  
  57. for my $fila (2 .. $#filas) {                   # Para todas las filas de la 2 hasta el final
  58.     my @celdas                                  # Las celdas serán
  59.         = $filas[$fila]                         # de la $fila actual
  60.         ->find("td")                            # de las marcas <td>
  61.         ->map(                                  # La convertimos
  62.             sub{                                # a
  63.                 shift->all_text;                # simplemente todo su texto
  64.             }
  65.         )
  66.         ->each                                  # y lo repetimos para todas las demás
  67.         ;
  68.  
  69.     if (@celdas < @fila_anterior) {             # Si el número de @celdas es menor que el de la línea anterior
  70.         @celdas                                 # Modificamos nuestras celdas
  71.             = (                                 # Insertando celdas de la fila anterior (las primeras por la izq.)
  72.                 @fila_anterior[0 .. @fila_anterior - @celdas -1],
  73.                 @celdas                         # más las que tenemos
  74.             )
  75.             ;
  76.     }
  77.    
  78.     #say "[@celdas]";
  79.  
  80.     push @registros, { zip @headers, @celdas }; # Almacenamos el resultado en un hash, dentro de un array
  81.                                                 # Con zip, se va colocando cada pareja:clave(cabecera) y su valor(celda)
  82.  
  83.     @fila_anterior = @celdas;                   # Ahora @celdas será nuestra @fila_anterior
  84. }
  85.  
  86. use Data::Dumper::Simple;                       # Volcado de la estructura
  87. say Dumper @registros;                          # de los registros
  88.  
Coloreado en 0.005 segundos, usando GeSHi 1.0.8.4
ejecutado de esta manera:
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. $ ./programa.pl code_30381.html ldap1-2.ddol-test.com:1389
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
sale:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Tabla número 1
Número de filas: 5
[Receiver][Time Lag][Max CSN][Last Modify Time][Supplier][Sent/Skipped][Update Status][Update Started][Update Ended][Schedule][SSL?]
@registros = (
               {
                 'Update Started' => '04/02/2012 12:28:54',
                 'Update Status' => '0 Replica acquired successfully: Incremental update succeeded',
                 'Update Ended' => '04/02/2012 12:28:54',
                 'Time Lag' => '0:00:00',
                 'Last Modify Time' => '1/1/1970 01:00:00',
                 'Sent/Skipped' => '0 / 0',
                 'SSL?' => 'n',
                 'Receiver' => 'ldap1-1.ddol-test.com:1389 Type: master',
                 'Supplier' => 'ldap1-2.ddol-test.com:1389',
                 'Schedule' => 'always in sync',
                 'Max CSN' => '4f7959ae000000020000 (04/02/2012 09:47:58)'
               },
               {
                 'Update Started' => '04/02/2012 12:34:54',
                 'Update Status' => '0 Replica acquired successfully: Incremental update succeeded',
                 'Update Ended' => '04/02/2012 12:34:54',
                 'Time Lag' => '0:00:00',
                 'Last Modify Time' => '1/1/1970 01:00:00',
                 'Sent/Skipped' => '0 / 0',
                 'SSL?' => 'n',
                 'Receiver' => 'ldap2-1.ddol-test.com:1389 Type: consumer',
                 'Supplier' => 'ldap1-2.ddol-test.com:1389',
                 'Schedule' => 'always in sync',
                 'Max CSN' => '4f7959ae000000020000 (04/02/2012 09:47:58)'
               },
               {
                 'Update Started' => '04/02/2012 12:36:46',
                 'Update Status' => '0 Replica acquired successfully: Incremental update succeeded',
                 'Update Ended' => '04/02/2012 12:36:46',
                 'Time Lag' => '0:00:00',
                 'Last Modify Time' => '1/1/1970 01:00:00',
                 'Sent/Skipped' => '0 / 0',
                 'SSL?' => 'n',
                 'Receiver' => 'ldap2-1.ddol-test.com:1389 Type: consumer',
                 'Supplier' => 'ldap1-1.ddol-test.com:1389',
                 'Schedule' => 'always in sync',
                 'Max CSN' => '4f7959ae000000020000 (04/02/2012 09:47:58)'
               },
               {
                 'Update Started' => '04/02/2012 12:34:54',
                 'Update Status' => '0 Replica acquired successfully: Incremental update succeeded',
                 'Update Ended' => '04/02/2012 12:35:01',
                 'Time Lag' => '0:00:00',
                 'Last Modify Time' => '1/1/1970 01:00:00',
                 'Sent/Skipped' => '0 / 0',
                 'SSL?' => 'n',
                 'Receiver' => 'ldap2-2.ddol-test.com:1389 Type: consumer',
                 'Supplier' => 'ldap1-2.ddol-test.com:1389',
                 'Schedule' => 'always in sync',
                 'Max CSN' => '4f7959ae000000020000 (04/02/2012 09:47:58)'
               },
               {
                 'Update Started' => '04/02/2012 12:36:39',
                 'Update Status' => '0 Replica acquired successfully: Incremental update succeeded',
                 'Update Ended' => '04/02/2012 12:36:39',
                 'Time Lag' => '0:00:00',
                 'Last Modify Time' => '1/1/1970 01:00:00',
                 'Sent/Skipped' => '0 / 0',
                 'SSL?' => 'n',
                 'Receiver' => 'ldap2-2.ddol-test.com:1389 Type: consumer',
                 'Supplier' => 'ldap1-1.ddol-test.com:1389',
                 'Schedule' => 'always in sync',
                 'Max CSN' => '4f7959ae000000020000 (04/02/2012 09:47:58)'
               }
             );
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Ejemplo de acceso a un dato:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. say $registros[1]->{'Receiver'}; # ldap2-1.ddol-test.com:1389 Type: consumer
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


He visto también que la columna de Schedule tiene en todas las filas un colspan="2", lo cual puede significar, o un descuido del programador, o es que quizás, en alguna ocasión, sí que aparece una columna más. Si este es el caso, entonces sí que se nos pueden descuadrar los datos.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Obtener datos tabla HTML

Notapor magiza83 » 2012-04-04 04:37 @234

¡Hola, explorer!

No puedo decir nada más que: ¡espectacular! Funciona tal cual esperaba. En principio no debería modificarse más la estructura de la tabla.

De todas maneras, aun no entiendo muy bien cómo funciona el módulo y alguna parte del script. ¡Pero voy a estudiarmelo!

¡muchas gracias de nuevo!
magiza83
Perlero nuevo
Perlero nuevo
 
Mensajes: 14
Registrado: 2012-02-22 05:29 @270

Anterior

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 20 invitados