Bagaimana Anda berhenti 'wget' setelah mendapat 404?


12

Jika Anda menggunakan ekspansi brace dengan wget, Anda dapat mengambil gambar bernomor urut dengan mudah:

$ wget 'http://www.iqandreas.com/sample-images/100-100-color/'{90..110}'.jpg'

Ini mengambil pertama 10 file bernomor 90.jpguntuk 99.jpgbaik-baik saja, tapi 100.jpgdan seterusnya mengembalikan 404: File tidak ditemukan kesalahan (saya hanya memiliki 100 gambar yang tersimpan di server). File-file yang tidak ada ini menjadi lebih "masalah" jika Anda menggunakan rentang yang lebih besar, seperti {00..200}, dengan 100 file yang tidak ada, itu meningkatkan waktu eksekusi skrip, dan bahkan mungkin menjadi sedikit beban (atau setidaknya gangguan) pada server.

Apakah ada cara untuk wgetberhenti setelah menerima kesalahan 404 pertama? (atau bahkan lebih baik, dua berturut-turut, kalau-kalau ada file yang hilang dalam kisaran karena alasan lain) Jawabannya tidak perlu menggunakan ekspansi penjepit; loop juga baik-baik saja.


1
Dalam skenario waktu nyata, Anda mungkin ingin mengenai setiap URL untuk mengetahui statusnya. 1, 2 or even n failuresbukan cara yang benar ketika Anda tahu [begin .. end]indeks. Mengapa Anda menentukan [1..200]rentang ketika Anda tahu hanya ada 100 gambar di [1..100]. Saya kira Anda dapat mencoba GNU paralleluntuk permintaan simultan untuk mempercepat proses.
SparKot

1
@SparKot ॐ Kuncinya adalah saya tidak tahu hanya ada 100 gambar di server, saya ingin skrip untuk mengunduh gambar sebanyak mungkin dalam seri sampai tahu di mana akhirnya.
IQAndreas

Jawaban:


9

Jika Anda senang dengan loop:

for url in 'http://www.iqandreas.com/sample-images/100-100-color/'{90..110}'.jpg'
do
    wget "$url" || break
done

Itu akan berjalan wgetuntuk setiap URL dalam ekspansi Anda sampai gagal, dan kemudian breakkeluar dari loop.

Jika Anda ingin dua kegagalan berturut-turut, ini menjadi sedikit lebih rumit:

for url in 'http://www.iqandreas.com/sample-images/100-100-color/'{90..110}'.jpg'
do
    if wget "$url"
    then
        failed=
    elif [ "$failed" ]
    then
        break
    else
        failed=yes
    fi
done

Anda bisa mengecilkan itu sedikit dengan &&dan ||bukannya if, tetapi itu menjadi sangat jelek.

Saya tidak percaya wgetada sesuatu yang dibangun untuk melakukan itu.


Bolehkah saya menyarankan menggunakan elifuntuk membuat contoh kedua lebih jelas? Mungkin sesuatu seperti ini? gist.github.com/IQAndreas/84cae3f0193b67691ff2 (itu hanya menambahkan satu baris tambahan, tidak termasuk menempatkan thens pada baris yang sama dengan ifs)
IQAndreas

Cukup adil. Terjemahan satu baris tidak semudah sekarang, tetapi itu tidak terlalu bagus.
Michael Homer

9

Anda bisa menggunakan $?variabel untuk mendapatkan kode pengembalian wget. Jika bukan nol maka berarti terjadi kesalahan dan Anda menghitungnya hingga mencapai ambang batas, maka itu bisa keluar dari loop.

Sesuatu seperti ini dari atas kepalaku

#!/bin/bash

threshold=0
for x in {90..110}; do
    wget 'http://www.iqandreas.com/sample-images/100-100-color/'$x'.jpg'
    wgetreturn=$?
    if [[ $wgetreturn -ne 0 ]]; then
        threshold=$(($threshold+$wgetreturn))
        if [[ $threshold -eq 16 ]]; then
                break
        fi
    fi
done

Untuk loop dapat dibersihkan sedikit, tetapi Anda dapat memahami ide umum.

Mengubah $threshold -eq 16ke -eq 24berarti itu akan gagal 3 kali sebelum akan berhenti, namun itu tidak akan menjadi dua kali berturut-turut, itu akan terjadi jika gagal dua kali dalam loop.

Alasan mengapa 16dan 24digunakan adalah itu adalah total kode pengembalian.
wget merespons dengan kode pengembalian 8ketika menerima kode respons yang sesuai dengan kesalahan dari server, dan dengan demikian 16total setelah 2 kesalahan.

Menghentikan ketika kegagalan hanya terjadi dua kali berturut-turut dapat dilakukan dengan mengatur ulang ambang batas setiap kali wgetberhasil, yaitu ketika kode kembali adalah 0


Daftar kode pengembalian wget dapat ditemukan di sini - http://www.gnu.org/software/wget/manual/html_node/Exit-Status.html


2
Meskipun dapat disimpulkan dari jawabannya, Anda mungkin ingin secara eksplisit menunjukkan bahwa kesalahan 404 mengembalikan kode keluar 8, karenanya angka ajaib dari 16dan 24.
IQAndreas

1
Saya telah memperbarui jawaban saya
Lawrence

1
Terima kasih untuk $?! Sangat berguna!
neverMind9

2

Dengan GNU Parallel ini seharusnya berfungsi:

parallel --halt 1 wget ::: 'http://www.iqandreas.com/sample-images/100-100-color/'{90..110}'.jpg'

Dari versi 20140722 Anda hampir dapat memiliki "dua berturut-turut" -failure: --halt 2% akan memungkinkan 2% dari pekerjaan gagal:

parallel --halt 2% wget ::: 'http://www.iqandreas.com/sample-images/100-100-color/'{90..110}'.jpg'

1

IMO, yang memfokuskan pada wgetkode keluar / status mungkin terlalu naif untuk beberapa kasus penggunaan, jadi di sini adalah salah satu yang mempertimbangkan Kode Status HTTP juga untuk beberapa pengambilan keputusan granular.

wgetmenyediakan -S/--server-responsebendera untuk mencetak Header Respons HTTP pada STDERRperintah - yang dapat kita ekstrak dan tindak lanjuti.

#!/bin/bash

set -eu

error_max=2
error_count=0

urls=( 'http://www.iqandreas.com/sample-images/100-100-color/'{90..110}'.jpg' )

for url in "${urls[@]}"; do
  set +e
  http_status=$( wget --server-response -c "$url" 2>&1 )
  exit_status=$?
  http_status=$( awk '/HTTP\//{ print $2 }' <<<"$http_status" | tail -n 1 )

  if (( http_status >= 400 )); then
    # Considering only HTTP Status errors
    case "$http_status" in
      # Define your actions for each 4XX Status Code below
      410) : Gone
        ;;
      416) : Requested Range Not Satisfiable
        error_count=0  # Reset error_count in case of `wget -c`
        ;;
      403) : Forbidden
        ;&
      404) : Not Found
        ;&
      *)     (( error_count++ ))
        ;;
    esac
  elif (( http_status >= 300 )); then
     # We're unlikely to reach here in case of 1XX, 3XX in $http_status
     # but ..
     exit_status=0
  elif (( http_status >= 200 )); then
     # 2XX in $http_status considered successful
     exit_status=0
  elif (( exit_status > 0 )); then

    # Where wget's exit status is one of
    # 1   Generic error code.
    # 2   Parse error 
    #     - when parsing command-line options, the .wgetrc or .netrc...
    # 3   File I/O error.
    # 4   Network failure.
    # 5   SSL verification failure.
    # 6   Username/password authentication failure.
    # 7   Protocol errors.

    (( error_count++ ))
  fi

  echo "$url -> http_status: $http_status, exit_status=$exit_status, error_count=$error_count" >&2

  if (( error_count >= error_max )); then
    echo "error_count $error_count >= $error_max, bailing out .." >&2
    exit "$exit_status"
  fi

done

-1

Dengan python bisa Anda lakukan

from subprocess import *

def main():
    for i in range(90, 110):
       try :
          url = "url/"+str(i)
          check_output(["wget", url])
       except CalledProcessError:
          print "Wget returned none zero output, quiting"
          sys.exit(0)

Periksa dokumentasi untuk subproses jika Anda ingin melakukan lebih banyak https://docs.python.org/2/library/subprocess.html


Kecuali jika check_outputada sihir di sekitar wgetuntuk mendeteksi 404- Saya tidak percaya ada pemeriksaan yang memadai di sini sehingga tidak benar-benar menjawab pertanyaan.
shalomb

Ya, baca dokumen. Ia memeriksa output di stdout atau stderr. wget memiliki kode khusus untuk 404-an
briankip
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.