Lun Jun 12, 2006 6:07 am
|
 |
ignasificus
Perlero Nuevo

|
Registrado: 01 Jun 2006
Mensajes: 13
Ubicación: Valencia
|
|
| Extraer direcciones web |
|
|
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: |
| ($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  |
|
|
|

Lun Jun 12, 2006 6:44 am
|
 |
ignasificus
Perlero Nuevo

|
Registrado: 01 Jun 2006
Mensajes: 13
Ubicación: Valencia
|
|
|
|
|
Bien, de momento he exo esto:
| Código: |
#!/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.. |
|

Lun Jun 12, 2006 7:06 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4084
Ubicación: Valladolid, España
|
|
|
|
|
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: |
| ($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: | Cita: | 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... |
|

Lun Jun 12, 2006 7:25 am
|
 |
ignasificus
Perlero Nuevo

|
Registrado: 01 Jun 2006
Mensajes: 13
Ubicación: Valencia
|
|
|
|
|
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! |
|

Lun Jun 12, 2006 9:51 am
|
 |
macgregor
Perlero Frecuente

|
Registrado: 09 Dic 2004
Mensajes: 117
Ubicación: españa
|
|
|
|
|
| Código: |
$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.
Ultima edición por macgregor el Mar Jun 13, 2006 3:35 am, editado 1 vez |
|

Lun Jun 12, 2006 11:52 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4084
Ubicación: Valladolid, España
|
|
|
|
|
| ignasificus escribió: | 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 escribió: | 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 escribió: | | 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 escribió: | | 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? |
|

Lun Jun 12, 2006 12:21 pm
|
 |
ignasificus
Perlero Nuevo

|
Registrado: 01 Jun 2006
Mensajes: 13
Ubicación: Valencia
|
|
| Gracias! |
|
|
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: |
$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.. |
|

Lun Jun 12, 2006 1:57 pm
|
 |
kidd
Creador de Perl en Español

|
Registrado: 15 Oct 2003
Mensajes: 1389
Ubicación: México
|
|
|
|
|
Hola:
Lo que puedes hacer para evitar el warning que te lanza es verificar que cumpla con la expresión regular:
| Código: |
$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: |
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
Recuerda que uno de los grandes beneficios que tiene Perl es la existencia de CPAN:
http://perlenespanol.baboonsoftware.com/articulos/archivo/000134.html
Saludos |
|

Lun Jun 12, 2006 2:07 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4084
Ubicación: Valladolid, España
|
|
|
|
|
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: |
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: |
$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: |
if ( $linea =~ m/HREF="([^"]*)"/ ) {
$fichero_limpio[$i++] = $1;
} |
|
|

Lun Jun 12, 2006 3:14 pm
|
 |
ignasificus
Perlero Nuevo

|
Registrado: 01 Jun 2006
Mensajes: 13
Ubicación: Valencia
|
|
| ya va! XD |
|
|
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: |
#!/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: |
| 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??
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. |
|

Mar Jun 13, 2006 3:51 am
|
 |
macgregor
Perlero Frecuente

|
Registrado: 09 Dic 2004
Mensajes: 117
Ubicación: españa
|
|
|
|
|
Hola.
Lamento haberme dejado el '=' en la expresion regular y que no fuera tan exacta como debería las prisas que no son buenas consejeras.... y lo torpe que soy! :]
(no sufras por lo de editar... yo también edité mi mensaje y añadí ese '=' )
Respecto al tema de los argumentos tienes razón, en el vector @ARGV tenemos los parámetros enviados.
| Código: |
$numArgs = $#ARGV + 1; # así obtenemos el número total de argumentos
foreach $argnum (0 .. $#ARGV)
{
print "$ARGV[$argnum]\n";
} |
|
|
Powered by phpBB © 2001, 2005 phpBB Group
|