Nuestro primer ejemplo considera el buscador de la Universidad de La Laguna (ULL), el cual permite la búsqueda de personal vinculado a la universidad.
En primer lugar, visite la página en la que esta ubicado: http://www.ccti.ull.es/bd/. La figura 10.1 muestra la interfaz que percibe un usuario humano.
La estructura de la página que contiene al formulario es como sigue:
<form method="GET" action="index.php3"> <font face="Verdana" size="2"><span class="normal">Buscar </span></font> <input class="ObjetosTexto" type="text" name="cadena" size="20" maxlength="20" value ="" title="Cadena que desea buscar"> <font face="Verdana" size="2"><span class="normal"> en </span></font> <font class="ObjetosSelect"> <select title="Concepto por el que se busca la información" class ="ObjetosSelect" name="donde" size="1"> <option value="1">el correo eléctrónico</option> <option selected value="2">el nombre y apellidos</option> <option value="3">la dirección de trabajo</option> <option value="4">la unidad organizativa</option> <option value="5">la relación con la unidad organizativa</option> </select> </font> <input type="submit" value="Buscar" name="BotonBuscar" class="ObjetosBoton"></p> </form>
El atributo method
indica si usamos GET o POST al enviar el formulario.
El atributo action
determina la URL que recibirá los datos.
Los componentes de un formulario son text-fields, listas drop-down,
checkboxes, etc. cada uno identificado con un name
. Aqui el
campo input
define la cadena
a buscar cuando se emita el formulario
al seleccionar el botón Buscar
. La etiqueta select
permite crear un menú desplegable utilizando la lista de elementos
etiquetados con option
. Nos concentraremos en la selección 2
del menú donde
para nuestra búsqueda: buscar por nombre y apellidos.
Una vez realizada la búsqueda, la estructura de la página de salida es tal que contiene al menos tres tablas cuando se encuentran resultados. La tercera tabla es la que contiene los resultados. Una fila tiene un aspecto parecido al siguiente:
<table border="0" width="100%"> <tr> <td> <a class="all" href="mailto:xxxx@ull.es" title="Póngase en contacto con el usuario"> xxxx@ull.es</a> </td> <td> María Teresa ..... ....... </td> <td> ** Dirección de trabajo ** </font> </td> <td> Departamento de Anatomía, Anatomía Patológica e Histología </td> <td> Docentes y personal investigador </td> <td> <a name="L1724"> </a><a href="#L1724"> Teléfonos:</a><br> 1er tlfn contacto: 922319444<br> Fax trabajo: 922319999<br> </td> </tr>
Solución:
#! /usr/bin/perl -w use URI; use LWP::UserAgent; use HTML::TreeBuilder 3; die "Uso $0 \"nombre\"\n" unless @ARGV == 1; my $name = $ARGV[0]; my $url = URI->new('http://www.ccti.ull.es/bd/index.php3'); $url->query_form('cadena'=>$name, 'donde'=>'2', 'BotonBuscar'=>'Buscar'); # #print $url, "\n";Un URL nos dice como obtener algo: utiliza HTTP con este servidor y pídele esto o bien conéctate por ftp a esta máquina y carga este fichero. La llamada anterior
$url = URI->new('http://www.ccti.ull.es/bd/index.php3')
crea un objeto URI representando una URL.
La forma en la que enviamos el formulario usando LWP depende de si
se trata de una acción GET o POST.
Si es un GET se procede como en el ejemplo: se crea una URL con los
datos codíficados usando el método
$url->query_form('cadena'=>$name, 'donde'=>'2', 'BotonBuscar'=>'Buscar')
.
y después se procede a llamar al método get
.
En el código que nos ocupa, se crea el agente y se llama al
método get
en una sóla expresión:
my $response = LWP::UserAgent->new->get( $url ); die "Error: ", $response->status_line unless $response->is_success;
El constructor new
de la clase LWP::UserAgent
nos permite
utilizar un objeto de la clase agente el cual nos permite gestionar
conexiones HTTP y realizar peticiones a los servidores HTTP.
Si el método es POST se debe llamar al método $browser->post()
pasándole como argumento una referencia al vector de parámetros del formulario.
De hecho, si estuvieramos buscando por una cadena fija, digamos
Casiano
, la línea anterior podría ser sustituida por:
$response = LWP::UserAgent->new->get(http://www.ccti.ull.es/bd/index.php3?cadena=Casiano&donde=2)
Acto seguido construimos el árbol de análisis sintáctico:
my $root = HTML::TreeBuilder->new_from_content($response->content); #$root->dump; my @tables = $root->find_by_tag_name('table');La llamada
HTML::TreeBuilder->new_from_content($response->content)
crea el árbol sintáctico del HTML proporcionado por el objeto
agente y que fué dejado en el objeto $response
. El objeto $response
es de la clase HTTP::Response
.
En general la sintáxis es:
HTML::TreeBuilder->new_from_content([ string, ... ])
Si usamos en vez new_from_file
construiríamos el árbol
para el fichero pasado como argumento.
El método find_by_tag_name
devuelve la
lista de nodos etiquetados con el correspondiente tag pasado
como argumento.
En el ejemplo, la llamada $root->find_by_tag_name('table')
devuelve una lista con los nodos del árbol que estan etiquetados
con la marca table
.
Si se descomenta la línea #$root->dump;
se produce un volcado
del árbol sintáctico del HTML. La estructura del volcado (abreviada)
es similar a esto:
<html> @0 <head> @0.0 <title> @0.0.0 ...... <link href="styles.css" name="style1" rel="stylesheet" type="text/css"> @0.0.1 <body alink="#800000" link="#000080" vlink="#800000"> @0.1 ......Cada nodo aparece etiquetado con su nivel de anidamiento.
a continuación el programa comprueba que existen tres tablas en el árbol y procede a recorrer el subárbol de la segunda tabla:
if (@tables > 2) { my $result = $tables[2]; my @stack = ($result); while (@stack) { my $node = shift @stack; if (ref $node) { unshift @stack, $node->content_list; } else { print $node,"\n"; } } } elsif ($root->as_text =~ /Consulta demasiado/) { print "Consulta demasiado extensa para $name\n"; } else { print "No se encontró $name"; } $root->delete;Como se ha dicho la tercera tabla (
my $result = $tables[2]
) es la que
contiene los resultados.
La llamada al método $node->content_list
devuelve la lista
de los hijos del nodo. Asi pues, la orden unshift
coloca dichos nodos al comienzo de @stack
(por cierto, que debería haberse llamado
@queue
ya que es usada como una cola). Si el nodo $node
no es una referencia
es que se trata de una hoja, en cuyo caso contiene información y la mostramos.
Ejemplo de ejecución:
$ ./search_ull.pl Coromoto xxxxx@ull.es Lourdes Coromoto Pérez González ** Dirección de trabajo ** Departamento de Filos. de la Memoria y Propología. Docentes y personal investigador Teléfonos: 1er tlfn contacto: 922444444 Fax trabajo: 922555555 yyyyy@ull.es (Visite su página) Coromoto González Pérez c/Astrofísico Paco. Sánchez s/n. Departamento de FitoPato, Postulo. y Pomputación Docentes y personal investigador Teléfonos: 1er tlfn contacto: 922406090 Fax trabajo: 922789341
Sigue el código completo del programa:
1 #! /usr/bin/perl -w 2 3 use URI; 4 use LWP::UserAgent; 5 use HTML::TreeBuilder 3; 6 7 die "Uso $0 \"nombre\"\n" unless @ARGV == 1; 8 my $name = $ARGV[0]; 9 my $url = URI->new('http://www.ccti.ull.es/bd/index.php3'); 10 $url->query_form('cadena'=>$name, 'donde'=>'2', 'BotonBuscar'=>'Buscar'); 11 # 12 #print $url, "\n"; 13 14 my $response = LWP::UserAgent->new->get( $url ); 15 die "Error: ", $response->status_line unless $response->is_success; 16 17 my $root = HTML::TreeBuilder->new_from_content($response->content); 18 19 #$root->dump; 20 21 my @tables = $root->find_by_tag_name('table'); 22 23 if (@tables > 2) { 24 my $result = $tables[2]; 25 26 my @stack = ($result); 27 while (@stack) { 28 my $node = shift @stack; 29 if (ref $node) { 30 unshift @stack, $node->content_list; 31 } else { 32 print $node,"\n"; 33 } 34 } 35 } elsif ($root->as_text =~ /Consulta demasiado/) { 36 print "Consulta demasiado extensa para $name\n"; 37 } 38 else { 39 print "No se encontró $name"; 40 } 41 $root->delete;
Casiano Rodríguez León