Cómo usar grep y cortar en script para obtener URL de sitios web desde un archivo HTML

21

Estoy tratando de usar grep and cut para extraer URL de un archivo HTML. Los enlaces se ven así:

<a href="http://examplewebsite.com/">

Otros sitios web lo han hecho .net, .govpero supongo que podría hacer el punto de corte justo antes >. Así que sé que puedo usar grep y cut de alguna manera para cortar todo antes de http y después de .com, pero me he quedado atascado por un tiempo.

eltigre
fuente
Lo edité Para algunos ignorar el espacio entre <y a, el HTML no se mostraría sin él. Gracias por atrapar eso!
eltigre
Use el formato de código (seleccione el texto y presione Ctrl-K). De lo contrario, <>obliga a que se vea como una etiqueta HTML.
muru
¿por qué no coincidir con la cita de apertura y finalización del parámetro href? Además, creo que las expresiones regulares no son las más adecuadas para HTML.
把 友情 留 在 无 盐
Quiero escribir un comando usando específicamente grep y cut para hacerlo. Me doy cuenta de que hay otras formas, pero quería saber sobre ellas.
eltigre
99
En general, no es una buena idea analizar HTML con expresiones regulares, ya que HTML no es un lenguaje regular. Si puede garantizar que el HTML que está analizando es bastante simple, y las cosas que está tratando de extraer son predecibles, es posible que pueda salirse con la suya. Pero consulte stackoverflow.com/a/1732454/4014959
PM 2Ring

Respuestas:

25

Como dije en mi comentario, generalmente no es una buena idea analizar HTML con expresiones regulares, pero a veces puedes salirte con la tuya si el HTML que estás analizando se comporta bien.

Para obtener solo las URL que están en el hrefatributo de <a>elementos, me resulta más fácil hacerlo en varias etapas. Según sus comentarios, parece que solo desea el dominio de nivel superior, no la URL completa. En ese caso, puede usar algo como esto:

grep -Eoi '<a [^>]+>' source.html |
grep -Eo 'href="[^\"]+"' | 
grep -Eo '(http|https)://[^/"]+'

donde source.htmlestá el archivo que contiene el código HTML para analizar.

Este código imprimirá todas las URL de nivel superior que ocurran como el hrefatributo de cualquier <a>elemento en cada línea. La -iopción para el primer grepcomando es asegurarse de que funcione tanto en elementos <a>como en <A>elementos. Supongo que también podría dar -ial segundo greppara capturar HREFatributos en mayúsculas , OTOH, preferiría ignorar ese HTML roto. :)

Para procesar los contenidos de http://google.com/

wget -qO- http://google.com/ |
grep -Eoi '<a [^>]+>' | 
grep -Eo 'href="[^\"]+"' | 
grep -Eo '(http|https)://[^/"]+'

salida

http://www.google.com.au
http://maps.google.com.au
https://play.google.com
http://www.youtube.com
http://news.google.com.au
https://mail.google.com
https://drive.google.com
http://www.google.com.au
http://www.google.com.au
https://accounts.google.com
http://www.google.com.au
https://www.google.com
https://plus.google.com
http://www.google.com.au

Mi salida es un poco diferente de los otros ejemplos a medida que me redirigen a la página australiana de Google.

PM 2Ring
fuente
GRACIAS. Ahora esto es exactamente lo que estaba buscando. Esta es la forma más limpia de hacerlo.
eltigre
@eltigre: ¡Un placer! Pero preste atención a la advertencia a la que me vinculé en mi comentario anterior. :)
PM 2Ring
Llegué a esta pregunta esperando puntos fáciles ... y ya había dado en el clavo por completo
Mark K Cowan
Gracias, @ MarkKCowan. :) FWIW, originalmente comencé a escribir una respuesta usando awk, pero luego decidí que una solución basada en grep sería más fácil de entender para aquellos que no están familiarizados con awk. Y de todos modos, el código anterior es más corto que mi código awk.
PM 2Ring
2
@mavavilj: Debido a que el OP solo quería el dominio de nivel superior, por lo que después del ://solo aceptamos caracteres antes del primero /o ". Pero si desea ver la URL completa, cambie ese comando a grep -Eo '(http|https)://[^"]+. Otra opción para esa línea es la grep -Eo '(http|https)://[^?"]+'que corta las opciones de consulta. Sin embargo, esa variación aún imprimirá las URL que están contenidas dentro de otra URL como parámetro de consulta, pero se imprimirán en una línea separada.
PM 2Ring
25

No estoy seguro si está limitado en herramientas:

Pero la expresión regular puede no ser la mejor manera de hacerlo, como se mencionó, pero aquí hay un ejemplo que preparé:

cat urls.html | grep -Eo "(http|https)://[a-zA-Z0-9./?=_-]*" | sort -u
  • grep -E: es lo mismo que egrep
  • grep -o: solo muestra lo que ha sido grepido
  • (http | https): es un / o
  • az: es todo en minúsculas
  • AZ: es todo caso superior
  • . : es punto
  • \?: es ?
  • *: es repetir el [...] grupo
  • uniq: eliminará cualquier duplicado

Salida:

bob@bob-NE722:~s$  wget -qO- https://stackoverflow.com/ | grep -Eo "(http|https)://[a-zA-Z0-9./?=_-]*" | sort -u
https://stackauth.com
https://meta.stackoverflow.com
https://cdn.sstatic.net/Img/svg-icons
https://stackoverflow.com
https://www.stackoverflowbusiness.com/talent
https://www.stackoverflowbusiness.com/advertising
https://stackoverflow.com/users/login?ssrc=head
https://stackoverflow.com/users/signup?ssrc=head
https://stackoverflow.com
https://stackoverflow.com/help
https://chat.stackoverflow.com
https://meta.stackoverflow.com
...

También puede agregar \dpara capturar otros tipos de números.

jmunsch
fuente
2
IRI regexes! ¡Usa uno de ellos y asusta al OP! :)
muru
2
@muru ... tiritando ... No sé qué decir. ¿Son esos incluso reales?
jmunsch
44
@jmunsch, uniq solo elimina los duplicados adyacentes. sort -u?
JJoao
1
funciona muy bien, la mejor respuesta !!
Gery
@JJoao es la fuente de clasificación -u más rápido que la tubería? Solo un experimento mental, la identificación tiene que mirar. Pero probablemente tenga razón, sobre el middleware de shell.
jmunsch
9

Si su grep admite expresiones regulares de Perl:

grep -Po '(?<=href=")[^"]*(?=")'
  • (?<=href=")y (?=")son expresiones de búsqueda para el hrefatributo. Esto necesita la -Popción.
  • -o Imprime el texto correspondiente.

Por ejemplo:

$ curl -sL https://www.google.com | grep -Po '(?<=href=")[^"]*(?=")'
/search?
https://www.google.co.in/imghp?hl=en&tab=wi
https://maps.google.co.in/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
https://www.youtube.com/?gl=IN&tab=w1
https://news.google.co.in/nwshp?hl=en&tab=wn
...

Como de costumbre, no hay garantía de que estos sean URI válidos, o que el HTML que está analizando sea válido.

muru
fuente
8

Como alternativa no regex , use pup :

pup 'a[href] attr{href}' < yourfile.html

Encontrará todos los aelementos que tienen un hrefatributo, luego mostrará el valor del hrefatributo.

Para instalar pup, necesita Go (un lenguaje de programación):

sudo apt-get install golang
sudo go get github.com/ericchiang/pup

La ventaja de esta solución es que no se basa en el formato HTML correcto .

Kroltan
fuente
1
+1 para pup, hora de instalar eso ...
Mark K Cowan
También puede ponerlos en el archivo. pup 'a.classname[href] attr{href}' < tut.html >links.md
Ahmad Awais
1

He encontrado una solución aquí que es en mi humilde opinión mucho más simple y potencialmente más rápido de lo que se propuso aquí. Me he ajustado un poco para admitir archivos https. Pero la versión TD; TR es ...

PD: puede reemplazar la URL del sitio con una ruta a un archivo y funcionará de la misma manera.

lynx -dump -listonly -nonumbers "http://www.goggle.com" > links.txt

lynx -dump -listonly -nonumbers "some-file.html" > links.txt

Si solo desea ver los enlaces en lugar de colocarlos en un archivo, intente esto en su lugar ...

lynx -dump -listonly -nonumbers "http://www.google.com"

lynx -dump -listonly -nonumbers "some-file.html"

El resultado será similar al siguiente ...

http://www.google.ca/imghp?hl=en&tab=wi
http://maps.google.ca/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
http://www.youtube.com/?gl=CA&tab=w1
http://news.google.ca/nwshp?hl=en&tab=wn
https://mail.google.com/mail/?tab=wm
https://drive.google.com/?tab=wo
https://www.google.ca/intl/en/options/
http://www.google.ca/history/optout?hl=en
...
etc.

Para mi caso de uso, esto funcionó bien. Pero tenga cuidado con el hecho de que hoy en día, las personas agregan enlaces como src = "// blah.tld" para URI CDN de bibliotecas. No quería verlos en los enlaces recuperados.

No es necesario intentar buscar href u otras fuentes de enlaces porque "lynx -dump" extraerá de forma predeterminada todos los enlaces en los que se puede hacer clic desde una página determinada. Entonces, lo único que debe hacer después de eso es analizar el resultado de "lynx -dump" usando grep para obtener una versión en bruto más limpia del mismo resultado.

asiby
fuente
Pero la pregunta dice "extraer URL de un archivo HTML [que se ve] como" (ejemplo), NO "extraer URL de una página web". Si su respuesta puede usarse contra un archivo que está en la máquina local, explique cómo. Por favor no responda en los comentarios; edite su respuesta para que sea más clara y completa.
G-Man dice 'reinstalar a Monica' el
1
Puede reemplazar la URL por un nombre de archivo.
asiby
@ G-Man, ¿por qué el -1? Debe probar el código usted mismo y ver que también funciona para archivos locales. He agregado esa aclaración en caso de que no fuera obvio.
asiby
Esto es realmente útil ... si está usando xargs, vale la pena agregarlo | ordenar | uniq para recortar los enlaces duplicados.
Stuart Axon
0
wget -qO- google.com |
tr \" \\n | grep https\*://

... probablemente lo haría bastante bien. Tal como está escrito, imprime:

http://schema.org/WebPage
http://www.google.com/imghp?hl=en&tab=wi
http://maps.google.com/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
http://www.youtube.com/?tab=w1
http://news.google.com/nwshp?hl=en&tab=wn
https://mail.google.com/mail/?tab=wm
https://drive.google.com/?tab=wo
http://www.google.com/intl/en/options/
http://www.google.com/history/optout?hl=en
https://accounts.google.com/ServiceLogin?hl=en&continue=http://www.google.com/
https://www.google.com/culturalinstitute/project/the-holocaust?utm_source=google&amp;utm_medium=hppromo&amp;utm_campaign=auschwitz_q1&amp;utm_content=desktop
https://plus.google.com/116899029375914044550

Si es importante que solo coincida con enlaces y entre esos dominios de nivel superior, puede hacer lo siguiente:

wget -qO- google.com |
sed '/\n/P;//!s|<a[^>]*\(https*://[^/"]*\)|\n\1\n|;D'

... o algo así, aunque para algunos seds, es posible que deba sustituir un carácter literal de línea de línea \nelectrónica para cada uno de los últimos dos ns.

Tal como está escrito, el comando anterior imprime:

http://www.google.com
http://maps.google.com
https://play.google.com
http://www.youtube.com
http://news.google.com
https://mail.google.com
https://drive.google.com
http://www.google.com
http://www.google.com
http://www.google.com
https://www.google.com
https://plus.google.com

... y para cualquier caso (pero probablemente lo más útil con este último) puede agregar un |sort -ufiltro hasta el final para obtener la lista sorteditada y soltar duplicados.

mikeserv
fuente
0

Más corto

grep -r http . --color
strash
fuente
-1
echo "<a href="http://examplewebsite.com/">"|sed -r 's:<.*"::g'|sed 's:/">$::g'
Praveen Kumar BS
fuente
No estoy seguro de que esas citas "inteligentes" sean lo que pretendía allí, ¿quizás citas "dobles" regulares?
Jeff Schaller