Práctica: Analisis de URLs en el Programa de Descarga

Mejore el tratamiento de los URL en el programa de descarga de paginas HTML desarrollado en la práctica 3.10 y presentado en la sección 3.9. Codifique en URL el descriptor usado como parámetro. Convierta las direcciones relativas en absolutas y descargue aquellas que se corresponden con ficheros HTML. Asegúrese que la misma página no es descargada múltiples veces.

La función head de LWP::Simple permite obtener las cabeceras HTTP de un fichero sin tener que descargarlo. El siguiente ejemplo muestra un uso:

casiano@beowulf:/tmp/Net-Server-0.96/examples$ perl -MLWP::Simple -dwe 0
  DB<1> ($type, $length, $mod) = head('http://nereida.deioc.ull.es/~pp2/perlexamples/node39.html')
  DB<2> x ($type, $length, $mod)
0  'text/html; charset=iso-8859-1'          # tipo MIME
1  19796                                    # tamaño en bytes
2  1175942205                               # fecha de modificacion en MUT
  DB<4> p scalar(localtime($mod))
Sat Apr  7 11:36:45 2007

Extienda el guión para que admita un parámetro que limite el tamaño de los ficheros que serán descargados. Algunos servidores no devuelven la información sobre el tamaño. Considere tal posibilidad.

Casiano Rodríguez León
2010-03-22
A>uri_escape en el módulo URI::Escape realiza el codificado URL de cualesquiera caracteres que deban ser codificados:
pp2@nereida:~/src/perl/LWP$ perl -MURI::Escape -wde 0
main::(-e:1):   0
  DB<1> $nombre = uri_escape("Juan Hernández")
  DB<2> $query = "name=$nombre+age=35+country=Spain"
  DB<3> print $query
name=Juan%20Hern%E1ndez+age=35+country=Spain

La función uri_escape_utf8 codifica los caracteres en UTF-8 antes de escaparlos.

El Método Clone

El método clone nos permite copiar un objeto URI:

pp2@nereida:~/src/perl/LWP$ perl -wd uri.pl http://user:pass@example.com:992/animal/bird?species=seagull#wings
main::(uri.pl:5):       my $surl = shift || die "Se esperaba una URL\n";
  DB<1> c 8
main::(uri.pl:8):       print "Scheme:   '",$url->scheme(),"'\n";
  DB<2> $copy = $url->clone()
  DB<3> x ($url, $copy)
0  URI::http=SCALAR(0x83fd460)
   -> 'http://user:pass@example.com:992/animal/bird?species=seagull#wings'
1  URI::http=SCALAR(0x83fdc88)
   -> 'http://user:pass@example.com:992/animal/bird?species=seagull#wings'

Los Setters de los Objetos URI

Se pueden usar los métodos anteriores como setters:
  DB<4> $copy->path('/weblogs')
  DB<5> x ($copy->path, $url->path)
0  '/weblogs'
1  '/animal/bird'

URIs en Contexto de Cadenas

Al tratar un objeto de la clase URI como una cadena se obtiene la cadena que describe la URL:

  DB<6> print "$copy"
http://user:pass@example.com:992/weblogs?species=seagull#wings

Normalización de URIs

Se denomina normalización de una URL o canonización de una URL al resultado de transformar la URL de una manera consistente de manera que sea posible determinar si dos cadenas URLs son equivalentes.

canonical normaliza una URI:

pp2@nereida:~/src/perl/LWP$ perl -MURI -wde 0
  DB<1> $u = URI->new('HTTP://user:pass@example.com:992/animal/bird?species=%41eagull%2ewings')
  DB<2> $w = $u->canonical()
  DB<3> x ($u, $w)
0  URI::http=SCALAR(0x83ffc84)
   -> 'HTTP://user:pass@example.com:992/animal/bird?species=%41eagull%2ewings'
1  URI::http=SCALAR(0x84004ac)
   -> 'http://user:pass@example.com:992/animal/bird?species=Aeagull.wings'

Comparación de URIs

El método eq dice si las dos URIs son iguales. dos URIs son iguales si su representación canónica es la misma:
  DB<4> p $u->eq($w)
1
Si lo que se quiere ver es que las dos referencias son iguales se debe usar el operador ==
  DB<5> p $u == $w

  DB<6> $z = $u

  DB<7> p $u == $z
1
El operador eq devuelve TRUE si las dos cadenas asociadas son iguales:
  DB<8> p $u eq $z
1
  DB<9> p $u eq $w

Recuerde que las componentes que describen el fichero y directorio diferencian entre el uso de mayúsculas y minúsculas (si es que el S.O. lo hace) Esto no ocurre con la componente que define el dominio.

Métodos Auxiliares

Métodos auxiliares de utilidad son path_query, path_segments, host_port y default_port:

pp2@nereida:~/src/perl/LWP$ perl -MURI -wde 0
main::(-e:1):   0
  DB<1> $u = URI->new('http://user:pass@example.com:992/animal/bird?species=seagull#wings')
  DB<2> x $u->path_query
0  '/animal/bird?species=seagull'
  DB<3> x $u->path_segments                      # contexto de lista
0  ''
1  'animal'
2  'bird'
  DB<4> x scalar($u->path_segments)              # contexto escalar
0  '/animal/bird'
  DB<5> x $u->host_port
0  'example.com:992'
  DB<6> x $u->default_port
0  80



Ausencia de Ciertas Componentes

En general, cuando una componente no existe el correspondiente método devuelve undef:

  DB<7> $v = URI->new('http://example.com/index.html')
  DB<8> print "not defined" unless defined($v->query)
not defined

Sin embargo ciertas componentes no tiene sentido en ciertas clases de URLs. Por ejemplo un URL del tipo mailto: no dispone de una componente host. En tal caso, la llamada al método host produce una excepción:

  DB<9> $m = URI->new('mailto:name@domain.es')
  DB<10> print $m->host
Can't locate object method "host" via package "URI::mailto" \
   at (eval 18)[/usr/share/perl/5.8/perl5db.pl:628] line 2.
La excepción puede evitarse comprobando el esquema o usando el método UNIVERSAL can:
 DB<11> $x = $m->can('host')? $m->host : "No host"
 DB<12> print $x
No host

Argumentos de una LLamada

En los primeros tiempos de internet los argumentos de una llamada a un procesador de un formulario (queries) eran cadenas separadas por el signo '+'

pp2@nereida:~/src/perl/LWP$ perl -MURI -wde 0
  DB<1> $v = URI->new('http://www.example.com/search.pl?LWP+module+perl')
  DB<2> x $v->query_keywords()
0  'LWP'
1  'module'
2  'perl'
El método query_keywords permite obtener la lista de argumentos cuando la llamada ocurre de acuerdo con este protocolo. Posteriormente se ha adoptado una forma de llamada con nombres:

  DB<4> $w = URI->new('http://www.example.com/search.pl?lib=LWP&word=module&language=perl')
  DB<5> x $w->query_form()
0  'lib'
1  'LWP'
2  'word'
3  'module'
4  'language'
5  'perl'
en este caso usamos el método query_form

Conversión de una URL Relativa en una Absoluta

Una URL absoluta comienza con el esquema y contiene todas las componentes que el esquema requiere. Por ejemplo, la URL

http://nereida.deioc.ull.es/~pp2/perlexamples/node37.html
es absoluta.

Cualquier URL que no comienza con un esquema es relativa. Para determinar el recurso al que se refiere una URL relativa es necesario prefijar una URL base absoluta. Se usa una notación que semeja la notación Unix para describir la jerarquía de archivos:

Las siguientes URL son relativas:

El método new_abs permite la conversión de URLs relativas en absolutas:
        $abs = URI->new_abs($relative, $base);
Por ejemplo:
casiano@beowulf:/tmp/Net-Server-0.96/examples$ perl -MURI -dwe 0
  DB<1> $base = 'http://nereida.deioc.ull.es/~pp2/perlexamples/node37.html'
  DB<2> $can = URI->new_abs('../apuntes/node127.html', $base)->canonical
  DB<3> x $can
0  URI::http=SCALAR(0x83e75c0)
   -> 'http://nereida.deioc.ull.es/~pp2/apuntes/node127.html'
  DB<4> p $can
http://nereida.deioc.ull.es/~pp2/apuntes/node127.html

Conversión de una URL Absoluta en una Relativa

El método rel permite la conversión de URLs absolutas en relativas:

        $rel = $absolute->rel($absolute_base);
Por ejemplo:
casiano@beowulf:/tmp/Net-Server-0.96/examples$ perl -MURI -dwe 0
DB<1> $pp2_37 = URI->new('http://nereida.deioc.ull.es/~pp2/perlexamples/node37.html')
DB<2> $pl_37 = URI->new('http://nereida.deioc.ull.es/~pl/perlexamples/node37.html')
DB<3> p $pl_37->rel($pp2_37)
../../~pl/perlexamples/node37.html



Subsecciones
Casiano Rodríguez León
2010-04-19