Skrypt, aby uzyskać kod stanu HTTP listy adresów URL?

87

Mam listę adresów URL, które muszę sprawdzić, aby sprawdzić, czy nadal działają, czy nie. Chciałbym napisać skrypt basha, który zrobi to za mnie.

Potrzebuję tylko zwróconego kodu stanu HTTP, tj. 200, 404, 500 i tak dalej. Nic więcej.

EDYTUJ Zwróć uwagę, że występuje problem, jeśli strona zawiera komunikat „404 nie znaleziono”, ale zwraca komunikat 200 OK. To źle skonfigurowany serwer internetowy, ale być może będziesz musiał rozważyć ten przypadek.

Aby uzyskać więcej informacji, zobacz Sprawdzanie, czy adres URL prowadzi do strony zawierającej tekst „404”

Manu
źródło
2
Aby być uczciwym, „błąd” w moim skrypcie występuje tylko wtedy, gdy serwer zwraca kod HTTP 200, ale w treści jest napisane „404 nie znaleziono”, co oznacza źle działający serwer WWW.
Phil
2
Kod wyjścia wget będzie wynosił 0, jeśli kod odpowiedzi to 200, 8 jeśli 404, 4 jeśli 302 ... Możesz użyć $? zmienna, aby uzyskać dostęp do statusu wyjścia poprzedniego polecenia.
Casey Watson,

Odpowiedzi:

194

Curl ma specjalną opcję --write-out, w tym:

$ curl -o /dev/null --silent --head --write-out '%{http_code}\n' <url>
200
  • -o /dev/null wyrzuca zwykłe wyjście
  • --silent wyrzuca miernik postępu
  • --head wysyła żądanie HEAD HTTP zamiast GET
  • --write-out '%{http_code}\n' drukuje wymagany kod stanu

Aby to zakończyć w pełnym skrypcie Bash:

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

(Czytelnicy o orlich oczach zauważą, że wykorzystuje to jeden proces zwijania na adres URL, co nakłada kary za rozwidlenie i połączenia TCP. Byłoby szybciej, gdyby wiele adresów URL zostało połączonych w jednym zawinięciu, ale nie ma miejsca na zapisanie potwornego powtórzenia opcji wymaganych do zrobienia tego przez curl).

Phil
źródło
Bardzo dobrze. Czy mogę wykonać to polecenie na każdym adresie URL w moim pliku?
Manu
1
@Manu: Tak, zredagowałem moją odpowiedź, aby pokazać jeden możliwy sposób zakończenia polecenia curl. Zakłada się, że url-list.txt zawiera jeden adres URL w każdym wierszu.
Phil
1
Nie wiem, dlaczego skrypt z góry i odpowiedź zawsze daje mi 000 na wyjściu, ale jak uruchamiam komendę tylko raz bez pętli to działa ...
Karol F
1
@KarolFiturski Miałem ten sam problem (który prawdopodobnie już naprawiłeś, ale na wypadek, gdyby ktoś się na to natknął ...) w moim przypadku miałem powrót karetki na końcach linii mojego pliku wejściowego, powodując, że adresy URL wyglądały jak http://example.com/\rpodczas przechodzenia przez pętlę
Jordan Robinson
1
Miałem ten problem i udało mi się go naprawić, przełączając końcówkę wiersza z typu Windows na typ Linux.
Tristan
38
wget --spider -S "http://url/to/be/checked" 2>&1 | grep "HTTP/" | awk '{print $2}'

drukuje tylko kod stanu

user551168
źródło
9
+1 Pokazuje wiele kodów po przekierowaniu adresu URL, każdy w nowym wierszu.
Ashfame
Musiałem pozbyć się --spidera, aby działał z żądaniem, które próbowałem wykonać, ale działa.
amitavk
30

Rozszerzenie odpowiedzi udzielonej już przez Phila. Dodanie do tego równoległości jest nie do pomyślenia w bash, jeśli używasz xargs do wywołania.

Tutaj kod:

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

-n1 : użyj tylko jednej wartości (z listy) jako argumentu wywołania curl

-P10 : Utrzymaj przy życiu 10 procesów zwijania w dowolnym momencie (tj. 10 równoległych połączeń)

Sprawdź write_outparametr w instrukcji curl, aby uzyskać więcej danych, które możesz wyodrębnić za jego pomocą (czasy itp.).

Na wypadek, gdyby komuś to pomogło, to jest połączenie, którego obecnie używam:

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

Po prostu umieszcza zbiór danych w pliku csv, który można zaimportować do dowolnego narzędzia biurowego.

estani
źródło
2
Równoległość, wejście do pliku i csv. Dokładnie to, czego szukałem.
Agey
Genialny, sprawił, że mój dzień.
xlttj
To jest niesamowite, właśnie tego szukałem, dziękuję. Jedno pytanie, jak można uwzględnić tytuł strony w wynikach CSV?
MitchellK
@estani - stackoverflow.com/users/1182464/estani jak można umieścić tytuł strony w pliku .csv. Przepraszamy za ponowne opublikowanie, zapomniałem oznaczyć Cię tagiem, aby otrzymać powiadomienie o tym pytaniu. Wielkie dzięki.
MitchellK
@MitchellK to w ogóle nie obsługuje zawartości wywołania http. Jeśli „tytuł strony” (cokolwiek to jest) znajduje się w adresie URL, możesz go dodać. Jeśli nie, musisz przeanalizować całą stronę, aby wyodrębnić jej „tytuł” ​​(zakładając, że masz na myśli stronę html pobraną przez http). Poszukaj innych odpowiedzi przy przepełnieniu stosu lub zadaj to konkretne pytanie.
estani
15

Opiera się to na szeroko dostępnym wget, obecnym prawie wszędzie, nawet w Alpine Linux.

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

Objaśnienia są następujące:

--quiet

Wyłącz wyjście Wgeta.

Źródło - strony podręcznika wget

--spider

[...] nie pobierze stron, po prostu sprawdź, czy tam są. […]

Źródło - strony podręcznika wget

--server-response

Wydrukuj nagłówki wysłane przez serwery HTTP i odpowiedzi przesłane przez serwery FTP.

Źródło - strony podręcznika wget

Nie mówią o --server-responsetym, że te nagłówki są drukowane do standardowego błędu (sterr) , stąd potrzeba przekierowania do stdin.

Dane wyjściowe wysyłane na standardowe wejście możemy przesłać potokiem, awkaby wyodrębnić kod stanu HTTP. Ten kod to:

  • druga ( $2) niepusta grupa znaków:{$2}
  • w pierwszej linii nagłówka: NR==1

A ponieważ chcemy, aby go wydrukować ... {print $2}.

wget --server-response --spider --quiet "${url}" 2>&1 | awk 'NR==1{print $2}'
Salathiel Genèse
źródło
1
Użyłem tego z2>&1 | head -1 | awk '{ print $2 }'
Evhz
7

Użyj, curlaby pobrać tylko nagłówek HTTP (nie cały plik) i przeanalizować go:

$ curl -I  --stderr /dev/null http://www.google.co.uk/index.html | head -1 | cut -d' ' -f2
200
dogbane
źródło
curl mówi mi 200, kiedy wget mówi 404 ... :(
Manu
Te -Iprzyczyny flag zwijać, aby złożyć zamówienie HEAD HTTP, który jest traktowany oddzielnie od normalnego HTTP GET przez niektóre serwery i może w ten sposób zwracać różne wartości. Polecenie powinno nadal działać bez niego.
lambshaanxy
4

wget -S -i *file* dostanie nagłówki z każdego adresu URL w pliku.

Przefiltruj jednak specjalnie grepdla kodu stanu.

colinross
źródło
1

Znalazłem narzędzie „webchk” napisane w Pythonie. Zwraca kod stanu dla listy adresów URL. Https://pypi.org/project/webchk/

Wynik wygląda następująco:

▶ 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)

Mam nadzieję, że to pomoże!

Yura Loginov
źródło
0

Ze względu na https://mywiki.wooledge.org/BashPitfalls#Non-atomic_writes_with_xargs_-P (dane wyjściowe z równoległych zadań xargsprzy mieszanym ryzyku), użyłbym GNU Parallel zamiast xargsrównolegle:

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

W tym konkretnym przypadku użycie może być bezpieczne, xargsponieważ dane wyjściowe są tak krótkie, więc problem z użyciem xargspolega raczej na tym, że jeśli ktoś później zmieni kod na coś większego, nie będzie to już bezpieczne. Lub jeśli ktoś czyta to pytanie i uważa, że ​​może zastąpić curlcoś innym, to również może nie być bezpieczne.

Ole Tange
źródło