如何在收到404后停止“ wget”?


12

如果您将括号扩展用于wget,则可以轻松获取按顺序编号的图像:

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

它获取编号为第10个文件90.jpg99.jpg就好了,但是100.jpg,向前返回404:找不到文件错误(我只有在服务器上存储100张图像)。如果您使用较大的范围,这些不存在的文件将更多地成为“问题”,例如{00..200},使用100个不存在的文件,它会增加脚本的执行时间,甚至可能会给您带来轻微的负担(或至少使人烦恼)服务器。

wget收到第一个404错误后,有什么方法可以停止吗?(或者,最好是连续两个,以防由于其他原因导致范围内文件丢失)。答案不需要使用大括号扩展;循环也很好。


1
在实时方案中,您可能需要点击每个URL才能知道状态。1, 2 or even n failures当您知道[begin .. end]索引时,这不是正确的方法。[1..200]当您知道中只有100张图像时,为什么还要指定范围呢[1..100]?我想您可以尝试parallel同时请求GNU 来加快过程。
SparKot

1
@SparKot ॐ关键是我知道服务器上只有100张图像,我希望脚本下载系列中尽可能多的图像,直到弄清楚结尾是什么为止。
IQAndreas 2014年

Answers:


9

如果您对循环感到满意:

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

该操作将wget在扩展中的每个URL上运行,直到失败,然后break退出循环。

如果您要连续两次失败,则情况会更加复杂:

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使第二个例子更清楚?大概是这样吗?gist.github.com/IQAndreas/84cae3f0193b67691ff2(它仅增加了一条额外的行,不包括将thens 与s放在同一行if
IQAndreas 2014年

很公平。单行翻译现在不是那么简单,但是反正不是很好。
Michael Homer 2014年

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次,将停止,但不会连续两倍,这将是,如果它在循环失败了两次。

使用16和的原因24是返回码的总数。
wget会8在收到来自服务器错误的响应代码时返回一个返回代码,该响应代码16是2次错误后的总数。

通过在wget成功时(即,返回码为0时)重置阈值,可以在故障仅连续出现两次时停止运行。


wget返回代码列表可在此处找到-http: //www.gnu.org/software/wget/manual/html_node/Exit-Status.html


2
虽然可以从答案可以推断,你可能需要明确指出的是,一个404错误返回的退出代码8,因而幻数1624
IQAndreas 2014年

1
我更新了我的答案
劳伦斯

1
谢谢$?!很有用!
neverMind9

2

使用GNU Parallel,这应该可以工作:

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

从版本20140722开始,您几乎可以“连续两次出现”故障:--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-response标志,用于STDERR在命令上打印出HTTP响应标头-我们可以提取并对其执行操作。

#!/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周围有魔术wget可以检测到404-我不相信这里没有足够的检查手段,所以不能真正回答问题。
shalomb

确实如此,请阅读文档。它检查stdout或stderr中的输出。wget具有404的特定代码
briankip
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.