• Publicidad

Extraer direcciones web

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

Extraer direcciones web

Notapor ignasificus » 2006-06-12 07:07 @338

Wenas, tengo que hacer un script, que recorra los bookmarks de netscape y con "wgets -spider" ver si los sitios están operativos.

Bien, el problema que tengo, es que el archivo "bokmarks.html" tiene muchos tags, no solo las direcciones, y me gustaria extraer todas las direcciones en un vector.

Lo que he pensado es abrir el archivo en un vector, y luego ir recorriendo ese vector con foreach y dejar cada dirección que encuentre en el segundo vector, pero ya limpio. lo he pensado hacer con la siguiente expresión regulera..
Código: Seleccionar todo
($extracto) = $x =~ m/\"(\S+)\"/;
pero temo que así me guarde también algunas otras cosas entre comilladas..

Lo probaré despues de comer y ya comento.. Y si teneis alguna idea de como podria conseguir un vector con todas las direcciones limpias, lo agradeceria mucho.

Venga, un saludo ;)
Avatar de Usuario
ignasificus
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2006-06-01 07:07 @338
Ubicación: Valencia

Publicidad

Notapor ignasificus » 2006-06-12 07:44 @364

Bien, de momento he exo esto:

Código: Seleccionar todo
 #!/usr/bin/perl

###
### Limpiar_Bookmarks forma parte del ejercicio 3 del curso linux
### Para utilizarlo como subrutina en el script.
###

$fichero_bookmarks = "bookmarks.html";

open (BOOKMARKS, $fichero_bookmarks);
@fichero_original = <BOOKMARKS>;
close (BOOKMARKS);

$i=0;

foreach $linea (@fichero_original) {
   $nombre_vector = "fichero_limpio[" . $i . "]";
   (${$nombre_vector}) = $linea =~ m/\"(\S+)\"/;
   $i++;
   }


print $fichero_limpio[1];
print $fichero_limpio[3];


pero en lugar de guardarse las direcciones, me salta el error de que las variables "fichero_limpio[1]" y "fichero_limpio[3]" no están inicializadas..

No se supone que se han guardado alli las direcciones?? No lo entiendo..
Avatar de Usuario
ignasificus
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2006-06-01 07:07 @338
Ubicación: Valencia

Notapor explorer » 2006-06-12 08:06 @379

Solución ya contestada.

Sobre la solución que ya propones, me parece que te estás complicando un poco. Estás intentando usar referencias simbólicas, que, en algunas ocasiones está bien usarlas, pero en el resto...

A ver... tu lo que quieres es hacer esto:
Código: Seleccionar todo
($fichero_limpio[$i]) = $linea =~ m/\"(\S+)\"/;
pero te encuentras con el aviso de que los elementos 1 y 3 no existen. Efectivamente: no existen. Si ves el fichero bookmarks.html verás que las primeras líneas no tienen "", por lo que el resultado de la expresión regular es un valor de undef, indicando que ha fallado, que no ha encontrado esa pareja de comillas.

Entonces, estás obligado a poner un control para saber si en la $linea se ha encontrado o no lo que quieres. Si no lo encuentras, entonces pasar a la siguiente línea.

Y un problema más que te vas a encontrar: en las primeras líneas verás que tu expresión regular saca estos valores:
Content-Type
1143387663
1111480491
1111480479
(al menos en mi fichero). Eso quiere decir que esos valores también están entrecomilladas.

Necesitas usar una expresión regular más fina...
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

Notapor ignasificus » 2006-06-12 08:25 @392

Vaya hombre... ..gracias supongo.
Aunque voy a tratar de interpretar tu código y adaptarlo a mi manera, pues no me gustaría entregar algo que no tengo la menor idea de cómo funciona...

El ejercicio dos, que muestra la info del archivo passwd, ya lo hice por mí mismo, y creeme, es mas satisfactorio así, aunque lo hice gracias a que entre todos en el foro me resolvisteis unas cuantas dudas, pero el código me ocupa algo más de una página, y es algo confuso incluso para mí, pero es mi código y le he cogido cariño :) tu código es mucho más exacto, profesional y corto.

Pero como ya he dicho, me parece de demasiado alto nivel, pues yo por ejemplo ahora mismo lo leo y me quedo bastante perdido, pero supongo que me servirá a la hora de orientarme para hacer el mio.

Otra cosa si te apuntas a un curso de linux (lo digo por carmelo), supongo que es para APRENDER y no para que te lo den hecho (que no te culpo a ti explorer, pero me parece demasiado lo que pide el carmelo este...)

¡Bueno, gracias! Voy a seguir dándole vueltas a esto.

EDITO: Vaya, sobre las expresiones regulares, estoy algo verde, pero acabo de ver que en esta misma página hay dos textos sobre esto y parece que bastante completos. Les voy a echar un vistazo! ;)


EDITO 2: Edito esto otra vez, pues veo innecesario abrir otra respuesta. Todavía no he leído esos tutoriales, pero cuando los lea, supongo que para refinar la expresión regular, podría ponerlo de manera que se quede con la cadena que hay después de cada HREF=" hasta el siguiente carácter de comillas " Así supongo que me aseguraría el guardar sólo las direcciones.. ¡Venga pues ahí queda!
Avatar de Usuario
ignasificus
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2006-06-01 07:07 @338
Ubicación: Valencia

Notapor macgregor » 2006-06-12 10:51 @494

Código: Seleccionar todo
$linea =~ m{
      ^           #inicio de cadena
      (.*)HREF=\"  #inicio del string
      (.*)\"      #URL
      (.*)        #resto de la cadena
      $           #Fin de la cadena
      }x;         #usamos "x" para poder romper esta linea

Mira a ver si te gusta esta forma de utilizar las expresiones regulares.
El contenido de cada par de paréntesis (.*) lo tienes en las variables $1, $2 y $3.
En este caso te interesa utilizar $2 ya que contendrá algo de la forma http://........

Espero que te sirva.

Un saludo.
Última edición por macgregor el 2006-06-13 04:35 @232, editado 1 vez en total
MACGREGOR [TM]
Avatar de Usuario
macgregor
Perlero nuevo
Perlero nuevo
 
Mensajes: 80
Registrado: 2004-12-09 07:32 @355
Ubicación: españa

Notapor explorer » 2006-06-12 12:52 @578

ignasificus escribiste:Vaya hombre... ..gracias supongo.
Aunque voy a tratar de interpretar tu código y adaptarlo a mi manera, pues no me gustaría entregar algo que no tengo la menor idea de cómo funciona...
¡Bien!

ignasificus escribiste:El ejercicio dos, que muestra la info del archivo passwd, ya lo hice por mí mismo, y creeme, es mas satisfactorio así, aunque lo hice gracias a que entre todos en el foro me resolvisteis unas cuantas dudas, pero el código me ocupa algo más de una página, y es algo confuso incluso para mí, pero es mi código y le he cogido cariño :) tu código es mucho más exacto, profesional y corto.
Si le has cogido cariño, nos gustará verlo cuando termines el curso.

Y mi código no es exacto ni profesional. Sólo es corto. En cuestión de exactitud, en Perl se puede resolver un problema de diez formas distintas. La mía es una más. Pero seguro que hay otras nueve más exactas -según lo que cada uno entienda por exacta-. Y para ser profesional debería estar comentado el código y tener en cuenta las situaciones límite (fallo en la apertura de ficheros, por ej.).

ignasificus escribiste:Pero como ya he dicho, me parece de demasiado alto nivel, pues yo por ejemplo ahora mismo lo leo y me quedo bastante perdido, pero supongo que me servirá a la hora de orientarme para hacer el mio.
Realmente si es más complicado, porque como sabía que eran unos deberes, pues no lo quise dejar muy claro. Si tu solución ocupa una página, pero FUNCIONA, entonces es válida.

ignasificus escribiste:Otra cosa si te apuntas a un curso de linux (lo digo por carmelo), supongo que es para APRENDER y no para que te lo den hecho (que no te culpo a ti explorer, pero me parece demasiado lo que pide el carmelo este...)
¿Se puede saber dónde estáis dando el curso?
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

Gracias!

Notapor ignasificus » 2006-06-12 13:21 @598

Wenas!

macgregor , muchas gracias por tu respuesta, pues me ha ilustrado perfectamente lo que acababa de leer sobre las expresiones regulares, que aunque no he leido el tutorial de esta web (porque no encontraba una forma comoda de imprimir...) el que he encontrado también me ha servido, pero leere en cuanto pueda los tutoriales de perl en español, pues me parece que son mas explicativos.

Tus comentarios del codigo aclaran muy bien cada cosa, y se ve mejor escrito de esa forma, que en una sola linea.

explorer . En cuando acabe el curso (que ya no queda casi, creo que este viernes..) colgaré los codigos de los dos ejercicios, para que podais ver como los ha resuelto un novato en esto, jeje. Seguro que os sorprende la forma mas rebuscada y extraña con la que ha quedado XD, pero mola!!

Sobre lo del curso.. pues es uno de iniciación al linux (con ubuntu) que dan en la UNED a distancia y eso, y weno los dos ultimos ejercicios son estos, de programación. Y la verdad es que perl era un lenguaje que quería probar, ya habia toqueteado visual basic, y c++ pero me parece que me quedo con perl. Pues es con el que he empezado a ver resultados útiles.

Ale!, voy a seguir con esto. ;)

EDITO: Bueno, he adaptado la respuesta de macgregor al còdigo, y ya me he leido los tutoriales que me faltavan. Pero..

(NOTA: @fichero_original se refiere a "bookmarks.html" pasado a ese vector. Y parte del codigo está comentado, para ver si funcionaba la variable $2)
Código: Seleccionar todo
$i=0;
foreach $linea (@fichero_original) {
    $linea =~ m{^(.*)HREF\"(.*)\"(.*)$}x;
   print $2; # <-- "uninitialized value?¿
   
        #($fichero_limpio[$i]) = $2;
   #$i++;
   }


#print @fichero_limpio;


Me salta error en esa linea, de que la variable no ha sido declarada, y tendría que estarlo, pues para eso mismo están los parentesis de la expresion regular.

Alguna idea? según he leido, los parentesis asignan una variable con cada contenido dentro de ellos, y están nombradas del tipo $1, $2, $3 etc.. dependiendo de cuantos parentesis aparezcan en la expresión..
Avatar de Usuario
ignasificus
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2006-06-01 07:07 @338
Ubicación: Valencia

Notapor kidd » 2006-06-12 14:57 @664

Hola:

Lo que puedes hacer para evitar el warning que te lanza es verificar que cumpla con la expresión regular:

Código: Seleccionar todo
$i=0;
foreach $linea (@fichero_original) {
   
    if($linea =~ m{^(.*)HREF\"(.*)\"(.*)$}x){
        $fichero_limpio[$i++] = $2;
    }

}

print join "\n", @fichero_limpio;


Ahora, te voy a recomendar otra solución que te puede facilitar mucho la vida, es el módulo HTML::SimpleLinkExtor, con el podrías hacer algo así:

Código: Seleccionar todo
use HTML::SimpleLinkExtor;

#Nuevo objeto
my $extractor = HTML::SimpleLinkExtor->new();

      #Pedimos que haga parse de tu archivo
      $extractor->parse_file("bookmarks.html");

      #Tomar todos los links
      my @all_links = $extractor->links;


Muy buena opción, ya que de entrada alguien ya hizo el trabajo sucio por ti :wink:

Recuerda que uno de los grandes beneficios que tiene Perl es la existencia de CPAN:
http://perlenespanol.com/articulos/archivo/000134.html


Saludos
Uriel Lizama Perl programmer fundador de Perl en Español
Perl Programming Language
Avatar de Usuario
kidd
Creador de Perl en Español
Creador de Perl en Español
 
Mensajes: 1166
Registrado: 2003-10-15 16:52 @744
Ubicación: México

Notapor explorer » 2006-06-12 15:07 @671

Falta un '=' después del HREF....

Es siempre más cómodo buscar lo menos posible que coincida con lo que buscamos.

Si se trata de buscar los enlaces dentro de la línea, sabemos -mirando el fichero de bookmarks- que todos esos enlaces están entrecomilladas. Como además en la misma línea puede haber más de una cadena de caracteres entrecomilladas, tenemos que buscar qué es lo que distingue al enlace del resto. Y lo distinto es lo que hay justo delante de él: HREF=. Bueno, pues eso buscaremos:
Código: Seleccionar todo
foreach $linea (@fichero_original) {
    if ( $linea =~ m/HREF="(.*?)"/ ) {
        $fichero_limpio[$i++] = $1;
    }

Es decir, buscamos HREF=", nos quedamos con lo del medio hasta la próxima ".

Hay que tener mucho cuidado con las expresiones [url].*[/url], ya que son 'glotonas', es decir, que intentan encajar la expresión regular con todos los caracteres posibles, no con la primera coincidencia.

Ejemplo: supongamos que tenemos esto:
Código: Seleccionar todo
$linea = '   <A HREF="http://www.enlace.com/" date="1212111111">';
$linea =~ m/HREF="(.*)".*$/;
print $1;  # http://www.enlace.com/" date="1212111111
La salida nos sale mal... ya que el primer .* nos captura todo lo posible y, aunque ponemos la segunda comilla doble como intento de parada, el .* glotón se da cuenta de que hay más comillas en el resto de la línea. Continúa y vé que efectivamente puede hacer coincidir el patrón con la última comilla doble, la de la fecha. De ahí la salida mal. El segundo .*$ sólo sirve para perder tiempo, pues de sobra sabemos que habrá caracteres entre lo que queremos y el final de línea. Lo mismo podríamos decir de un '^.*'. ¡Ojo! Esto no quiera decir que no sean útiles en otras circunstancias.

Necesitamos que el .* glotón se pare cuanto antes coincida el patrón regular. Poniendo $linea =~ m/HREF="(.*?)"/;la captura ya es la que queremos: el '?' hace que desaparezca la glotonería del .*. Se parará justo antes de la siguiente comilla doble, que es lo que queremos.

La forma de captura, en vez de .*? podría haber sido la tradicional [^"]* (buscamos 0 o más caracteres que no sean una comilla doble). Quizás es mucho más clara para una persona que empieza con esto de las expresiones regulares. Quedaría:
Código: Seleccionar todo
if ( $linea =~ m/HREF="([^"]*)"/ ) {
        $fichero_limpio[$i++] = $1;
    }
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

ya va! XD

Notapor ignasificus » 2006-06-12 16:14 @718

Ey, explorer

Has dado justo en el clavo! (pero yo he sido lento XD)
Digo esto, porque justo,me he estado quemando el cerebro, pensando que es lo que hacia que la variable $2, me guardase un montón de basura que no quería, y me he puesto a leer, a buscar, a probar cosas, y al final he encontrado una forma bastante rudimentaria que me funcionaba. Y cuando he venido al foro a ponerlo.. Ops! tu respuesta es justo lo que necesitaba!! jaja, pero bueno, por si teneis curiosidad, posteo la "expresión regulera" que he sacado yo. Aunque igual funciona!

Código: Seleccionar todo
#!/usr/bin/perl


$fichero_bookmarks = "bookmarks.html";

open (BOOKMARKS, $fichero_bookmarks);
@fichero_original = <BOOKMARKS>;
close (BOOKMARKS);

$i=0;
foreach $linea (@fichero_original) {
    if ( $linea =~ m{^(.*)\<A HREF\=\"(.*)\" ADD(.*)\<\/A\>$} )
   {
   $fichero_limpio[$i++] = $2;
   }
   }


print @fichero_limpio;


Como veis es mas rebuscada que poner el "?".


kidd, gracias también por tu respuesta, que como ves he implementado al còdigo. Y sobre lo de usar el modulo, esta vez creo que lo intentaré como lo estoy planteando, pero seguramente despues haga una versión utilizando el modulo que comentas, ya que no he utilizado antes los modulos, y creo que sería una oportunidad excelente para aprender a utilizarlos.

Venga, un saludo! ;)

EDITO: (hay que ver, que manía que tengo con lo de editar.. ¬¬) Me ha surgido una duda, y es que en los scripts programados en bash, tu desde la linea de comandos puedes hacer:
Código: Seleccionar todo
 cea-linux@mycomputer:~$ compruebaBookmarks ~/.netscape/bookmarks.html


Y de esta manera, "~/.netscape/bookmarks.html" se envia como un argumento que se guarda en "$1". Pero en perl, recuerdo que las variables con esta nomenclatura, están destinadas justamente a guardar lo que hay entre parentesis en las expresiones regulares.. Por tanto, donde se guardan los argumentos?? :roll:

EDITO 2: Disculpen que me conteste yo mismo, pero creo que acabo de encontrar la respuesta. Los argumentos pasados por la consola se guardan en el vector "@ARGV", por lo tanto supongo que $ARGV[0] corresponderá al primer argumento, y así sucesivamente.
<!-- Algún dia me haré una firma que valga la pena.. [b8d] Al día siguiente, conquistaré el mundo.. [/b8d]-->
Avatar de Usuario
ignasificus
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2006-06-01 07:07 @338
Ubicación: Valencia

Siguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: Bing [Bot] y 19 invitados