404を取得した後、「wget」をどのように停止しますか?


12

でブレース展開を使用するとwget、連番の画像を簡単に取得できます。

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

これは、番号の最初の10個のファイルフェッチ90.jpgする99.jpgだけで罰金を、しかし、100.jpg以降返し404:ファイルが見つかりません(私はサーバー上に保存された100枚の画像を持っている)エラーが発生しました。これらの{00..200}存在しないファイルは、存在しないファイルが100個あるなど、より大きな範囲を使用する場合、より「問題」になり、スクリプトの実行時間が増加し、わずかな負担(または少なくとも煩わしさ)になることさえあります。サーバー。

wget最初の404エラーを受け取った後に停止する方法はありますか?(または、別の理由で範囲内にファイルが欠落している場合は、続けて2つ続けてください)中括弧の展開を使用する必要はありません。ループも結構です。


1
リアルタイムのシナリオでは、すべてのURLをヒットしてステータスを知ることができます。インデックス1, 2 or even n failuresを知っているときは、正しい方法ではありません[begin .. end]。に[1..200]100枚の画像しかないことがわかっているのに、なぜ範囲を指定するのですか[1..100]parallelプロセスを高速化するために、同時リクエストに対してGNU を試すことができると思います。
SparKot 14

1
@SparKot ॐ重要なのは、サーバー上に100の画像しかないことを知らないことです。シリーズの最後がどこにあるかがわかるまで、スクリプトがシリーズ内の画像をできるだけ多くダウンロードするようにします。
IQAndreas 2014

回答:


9

ループに満足している場合:

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

それはwget失敗するまで、そしてbreakループから抜けるまで、展開内の各URLに対して実行されます。

続けて2つの失敗が必要な場合は、少し複雑になります。

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

&&とでは||なくで少し縮小できますがif、かなり見苦しくなります。

wgetそのために何かが組み込まれているとは思いません。


を使用elifして2番目の例をより明確にすることをお勧めできますか?おそらくこのような何か?gist.github.com/IQAndreas/84cae3f0193b67691ff2(sをthen sと同じ行に配置することを除いて、1行だけ追加されますif
IQAndreas

けっこうだ。一行翻訳は今ほど簡単ではありませんが、とにかくあまり良くありません。
Michael Homer

9

この$?変数を使用して、wgetの戻りコードを取得できます。ゼロ以外の場合は、エラーが発生したことを意味し、しきい値に達するまで集計すると、ループから抜け出す可能性があります。

私の頭の上にあるこのようなもの

#!/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

forループは少し整理できますが、一般的な考え方は理解できます。

をに変更する$threshold -eq 16-eq 24、停止する前に3回失敗することになりますが、連続して2回ではなく、ループで2回失敗した場合です。

16および24が使用される理由は、戻りコードの合計です。
wgetは8、サーバーからのエラーに対応する応答コードを受け取ったときの戻りコードで応答するため、162つのエラー後の合計になります。

失敗が連続して2回だけ発生したときの停止は、wget成功するたびに、つまり戻りコードが0のときにしきい値をリセットすることによって実行できます。


wgetの戻りコードのリストは、ここで見つけることができます- http://www.gnu.org/software/wget/manual/html_node/Exit-Status.html


2
それは答えから推定することができますが、明示的に404エラーが終了コードを返すことを指摘したい場合があります8、したがって、マジックナンバー1624
IQAndreas 14

1
私は私の答えを更新しました
ローレンス14

1
ありがとう$?!非常に便利!
-neverMind9

2

GNU Parallelでは、これは機能するはずです。

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

バージョン20140722以降では、「2つの行を連続して」ほぼ失敗する可能性があります。--halt 2%を指定すると、ジョブの2%が失敗します。

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

1

IMOは、wgetの終了コード/ステータスに焦点を当てているので、ユースケースによっては単純すぎる場合があるため、ここでは、HTTPステータスコードと詳細な意思決定を考慮したものを示します。

wgetコマンドの-S/--server-responseHTTP応答ヘッダーを出力するためのフラグを提供しますSTDERR-これを抽出して操作できます。

#!/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

Pythonでは次のことができます

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)

さらに処理したい場合は、サブプロセスのドキュメントをチェックしてください。https://docs.python.org/2/library/subprocess.html


を検出するためのcheck_output魔法がない限り-私はここに適切なチェックがあるとは思わないので、実際には質問に答えません。wget404
shalomb 2017年

それは、ドキュメントを読んでください。stdoutまたはstderrの出力をチェックします。wgetには404の特定のコードがあります
briankip
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.