Como você pára o 'wget' depois que ele recebe um 404?

10

Se você usar a expansão de chave com wget , poderá buscar imagens numeradas sequencialmente com facilidade:

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

Ele obtém os 10 primeiros arquivos numerados 90.jpg to 99.jpg , mas 100.jpg e em diante retornam um erro 404: Arquivo não encontrado (eu só tenho 100 imagens armazenadas no servidor). Esses arquivos inexistentes se tornam mais "um problema" se você usar um intervalo maior, como {00..200} , com 100 arquivos inexistentes, aumenta o tempo de execução do script e pode até se tornar um pequeno fardo (ou pelo menos aborrecimento) no servidor.

Existe alguma maneira de wget parar depois de receber seu primeiro erro 404? (ou melhor ainda, dois em linha, caso houvesse um arquivo ausente no intervalo por outro motivo) A resposta não precisa usar a expansão de chave; loops são bons também.

    
por IQAndreas 22.07.2014 / 08:06

5 respostas

9

Se você está feliz com um loop:

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

Isso executará wget para cada URL em sua expansão até que ele falhe e, em seguida, break fora do loop.

Se você quiser duas falhas seguidas, fica um pouco mais complicado:

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

Você pode diminuir um pouco com && e || em vez de if , mas fica bem feio.

Eu não acredito que wget tenha algo embutido para fazer isso.

    
por 22.07.2014 / 08:13
8

Você pode usar a variável $? para obter o código de retorno do wget. Se não for zero, significa que ocorreu um erro e você registra o valor até atingir um limite, então ele pode sair do loop.

Algo como isso fora do topo da minha cabeça

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

O loop for pode ser limpo um pouco, mas você pode entender a ideia geral.

Mudar o $threshold -eq 16 para -eq 24 significaria que iria falhar 3 vezes antes de parar, no entanto não seria duas vezes seguidas, seria se falhasse duas vezes no ciclo.

O motivo pelo qual 16 e 24 são usados é o total dos códigos de retorno.
O wget responde com um código de retorno de 8 quando recebe um código de resposta que corresponde a um erro do servidor e, portanto, 16 é o total após 2 erros.

Parar quando ocorrerem falhas apenas duas vezes seguidas, redefinindo o limite sempre que wget tiver êxito, ou seja, quando o código de retorno for 0

Uma lista de códigos de retorno do wget pode ser encontrada aqui - link     
por 22.07.2014 / 08:13
2

Com o GNU Parallel, isso deve funcionar:

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

A partir da versão 20140722, você pode quase ter sua falha "duas em linha": --halt 2% permitirá que 2% dos trabalhos falhem:

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

O IMO, focando no código / status de saída do wget , pode ser ingênuo demais para alguns casos de uso, então aqui está um que considera o Código de Status HTTP, bem como algumas decisões granulares.

wget fornece um sinal -S/--server-response para imprimir os cabeçalhos de resposta HTTP em STDERR do comando - o qual podemos extrair e agir.

#!/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
    
por 02.07.2017 / 16:55
-1

Em python você pode fazer

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)

Faça o check-out da documentação do subprocesso se quiser fazer mais link

    
por 20.06.2017 / 10:28