¿Script para obtener el código de estado HTTP de una lista de URL?

87

Tengo una lista de URL que necesito comprobar para ver si todavía funcionan o no. Me gustaría escribir un script bash que lo haga por mí.

Solo necesito el código de estado HTTP devuelto, es decir, 200, 404, 500 y así sucesivamente. Nada mas.

EDITAR Tenga en cuenta que hay un problema si la página dice "404 no encontrado" pero devuelve un mensaje 200 OK. Es un servidor web mal configurado, pero es posible que deba considerar este caso.

Para obtener más información sobre esto, consulte Comprobar si una URL va a una página que contiene el texto "404".

Manu
fuente
2
Para ser justos, el "error" de mi secuencia de comandos es solo cuando el servidor devuelve el código HTTP 200 pero el texto del cuerpo dice "404 no encontrado", que es un servidor web que no funciona correctamente.
Phil
2
El estado de salida de wget será 0 si el código de respuesta fue 200, 8 si 404, 4 si 302 ... Puede usar $? variable para acceder al estado de salida del comando anterior.
Casey Watson

Respuestas:

194

Curl tiene una opción específica --write-out, para esto:

$ curl -o /dev/null --silent --head --write-out '%{http_code}\n' <url>
200
  • -o /dev/null tira la salida habitual
  • --silent tira el medidor de progreso
  • --head realiza una solicitud HEAD HTTP, en lugar de GET
  • --write-out '%{http_code}\n' imprime el código de estado requerido

Para resumir esto en un script Bash completo:

#!/bin/bash
while read LINE; do
  curl -o /dev/null --silent --head --write-out "%{http_code} $LINE\n" "$LINE"
done < url-list.txt

(Los lectores con ojos de águila notarán que esto usa un proceso de rizo por URL, lo que impone penalizaciones de conexión TCP y de bifurcación. Sería más rápido si se combinaran varias URL en un solo rizo, pero no hay espacio para escribir la monstruosa repetición de opciones que curl requiere para hacer esto).

Phil
fuente
Muy agradable. ¿Puedo ejecutar ese comando en cada URL de mi archivo?
Manu
1
@Manu: Sí, he editado mi respuesta para mostrar una posible forma de terminar el comando curl. Supone que url-list.txt contiene una URL por línea.
Phil
1
No sé por qué el script de arriba y la respuesta siempre me dan 000 en la salida, pero cuando ejecuto el comando solo una vez sin bucle, funciona ...
Karol F
1
@KarolFiturski Tuve el mismo problema (que probablemente hayas solucionado desde entonces, pero en caso de que alguien más se tope con esto ...) en mi caso, tuve retornos de carro en los extremos de la línea de mi archivo de entrada, lo que provocó que las URL fueran como http://example.com/\ral pasar por el circuito
Jordan Robinson
1
Tuve este problema y pude solucionarlo cambiando la línea que termina del tipo Windows al tipo Linux.
Tristan
38
wget --spider -S "http://url/to/be/checked" 2>&1 | grep "HTTP/" | awk '{print $2}'

imprime solo el código de estado para usted

usuario551168
fuente
9
+1 Muestra varios códigos cuando se redirige una URL, cada uno en una nueva línea.
Ashfame
Tuve que deshacerme de --spider para que funcione con la solicitud que estaba tratando de hacer, pero funciona.
amitavk
30

Ampliando la respuesta ya proporcionada por Phil. Agregar paralelismo es una obviedad en bash si usa xargs para la llamada.

Aquí el código:

xargs -n1 -P 10 curl -o /dev/null --silent --head --write-out '%{url_effective}: %{http_code}\n' < url.lst

-n1 : use solo un valor (de la lista) como argumento para la llamada curl

-P10 : Mantenga activos 10 procesos de rizo en cualquier momento (es decir, 10 conexiones en paralelo)

Consulte el write_outparámetro en el manual de curl para obtener más datos que pueda extraer usándolo (tiempos, etc.).

En caso de que ayude a alguien, esta es la llamada que estoy usando actualmente:

xargs -n1 -P 10 curl -o /dev/null --silent --head --write-out '%{url_effective};%{http_code};%{time_total};%{time_namelookup};%{time_connect};%{size_download};%{speed_download}\n' < url.lst | tee results.csv

Simplemente genera una gran cantidad de datos en un archivo csv que se puede importar a cualquier herramienta de oficina.

estani
fuente
2
Paralelismo, entrada de archivos y csv. Exactamente lo que estaba buscando.
Agey
Brillante, me alegró el día.
xlttj
Esto es increíble, justo lo que estaba buscando, gracias señor. Una pregunta, ¿cómo se podría incluir el título de la página en los resultados del csv?
MitchellK
@estani - stackoverflow.com/users/1182464/estani ¿cómo se podría incluir la obtención del título de una página en el archivo .csv? Lo siento por volver a publicar, olvidé etiquetarte para que te notifiquen sobre esta pregunta. Muchas gracias.
MitchellK
@MitchellK, esto no está manejando el contenido de la llamada http en absoluto. Si el "título de la página" (lo que sea) está en la URL, entonces puede agregarlo. De lo contrario, debe analizar toda la página para extraer el "título" de la misma (suponiendo que se refiera a una página html recuperada por http). Busque otras respuestas en el desbordamiento de pila o haga esa pregunta específica.
estani
15

Esto se basa en una amplia disponibilidad wget, presente en casi todas partes, incluso en Alpine Linux.

wget --server-response --spider --quiet "${url}" 2>&1 | awk 'NR==1{print $2}'

Las explicaciones son las siguientes:

--quiet

Apague la salida de Wget.

Fuente - páginas de manual de wget

--spider

[...] no descargará las páginas, solo verifique que estén ahí. [...]

Fuente - páginas de manual de wget

--server-response

Imprima los encabezados enviados por los servidores HTTP y las respuestas enviadas por los servidores FTP.

Fuente - páginas de manual de wget

Lo que no dicen --server-responsees que la salida de esos encabezados se imprime con un error estándar (sterr) , por lo que es necesario redirigir a stdin.

La salida enviada a la entrada estándar, podemos canalizarla awkpara extraer el código de estado HTTP. Ese código es:

  • el segundo ( $2) grupo de caracteres que no está en blanco:{$2}
  • en la primera línea del encabezado: NR==1

Y porque queremos imprimirlo ... {print $2}.

wget --server-response --spider --quiet "${url}" 2>&1 | awk 'NR==1{print $2}'
Salathiel Genèse
fuente
1
2>&1 | head -1 | awk '{ print $2 }'
Usé
7

Úselo curlpara buscar solo el encabezado HTTP (no el archivo completo) y analizarlo:

$ curl -I  --stderr /dev/null http://www.google.co.uk/index.html | head -1 | cut -d' ' -f2
200
dogbane
fuente
curl me dice 200 cuando wget dice 404 ... :(
Manu
La -Ibandera hace que curl realice una solicitud HTTP HEAD, que algunos servidores tratan por separado de un HTTP GET normal y, por lo tanto, puede devolver valores diferentes. El comando aún debería funcionar sin él.
lambshaanxy
4

wget -S -i *file* obtendrá los encabezados de cada URL en un archivo.

Filtre grepel código de estado específicamente.

colinross
fuente
1

Encontré una herramienta "webchk" escrita en Python. Devuelve un código de estado para una lista de URL. Https://pypi.org/project/webchk/

La salida se ve así:

▶ webchk -i ./dxieu.txt | grep '200'
http://salesforce-case-status.dxi.eu/login ... 200 OK (0.108)
https://support.dxi.eu/hc/en-gb ... 200 OK (0.389)
https://support.dxi.eu/hc/en-gb ... 200 OK (0.401)

¡Espero que ayude!

Yura Loginov
fuente
0

Debido a https://mywiki.wooledge.org/BashPitfalls#Non-atomic_writes_with_xargs_-P (salida de trabajos paralelos con xargsriesgos mezclados), usaría GNU Parallel en lugar de xargsparalelizar:

cat url.lst |
  parallel -P0 -q curl -o /dev/null --silent --head --write-out '%{url_effective}: %{http_code}\n' > outfile

En este caso particular, puede ser seguro de usar xargsporque la salida es muy corta, por lo que el problema con el uso xargses más bien que si alguien más tarde cambia el código para hacer algo más grande, ya no será seguro. O si alguien lee esta pregunta y piensa que puede reemplazarlo curlcon otra cosa, entonces tampoco es seguro.

Ole Tange
fuente