Làm thế nào bạn dừng 'wget' sau khi nó nhận được 404?


12

Nếu bạn sử dụng mở rộng dấu ngoặc với wget, bạn có thể tìm nạp hình ảnh được đánh số liên tục một cách dễ dàng:

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

Rồi nó lấy 10 file đầu tiên đánh số 90.jpgđể 99.jpgchỉ tốt, nhưng 100.jpgtrở đi trở lại một 404: File không tìm thấy lỗi (tôi chỉ có 100 hình ảnh được lưu trữ trên máy chủ). Các tệp không tồn tại này trở thành "vấn đề" hơn nếu bạn sử dụng phạm vi lớn hơn, chẳng hạn như {00..200}với 100 tệp không tồn tại, nó làm tăng thời gian thực thi của tập lệnh và thậm chí có thể trở thành gánh nặng nhỏ (hoặc ít nhất là gây khó chịu) máy chủ.

Có cách nào wgetđể dừng lại sau khi nhận được lỗi 404 đầu tiên không? (hoặc thậm chí tốt hơn, hai liên tiếp, trong trường hợp có một tệp bị thiếu trong phạm vi vì một lý do khác) Câu trả lời không cần sử dụng mở rộng dấu ngoặc; vòng lặp cũng tốt


1
Trong kịch bản thời gian thực, bạn có thể muốn nhấn mọi URL để biết trạng thái. 1, 2 or even n failureskhông phải là cách đúng đắn khi bạn biết [begin .. end]các chỉ số. Tại sao bạn chỉ định [1..200]phạm vi khi bạn biết chỉ có 100 hình ảnh [1..100]. Tôi đoán bạn có thể thử GNU parallelcho các yêu cầu đồng thời để tăng tốc quá trình.
SparKot

1
@SparKot key Điều quan trọng là tôi không biết chỉ có 100 hình ảnh trên máy chủ, tôi muốn tập lệnh tải xuống càng nhiều hình ảnh càng tốt trong chuỗi cho đến khi tìm ra kết thúc ở đâu.
IQAndreas

Câu trả lời:


9

Nếu bạn hài lòng với một vòng lặp:

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

Điều đó sẽ chạy wgetcho mỗi URL trong bản mở rộng của bạn cho đến khi nó thất bại, và sau đó breakthoát khỏi vòng lặp.

Nếu bạn muốn hai lần thất bại liên tiếp, nó sẽ phức tạp hơn một chút:

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

Bạn có thể thu nhỏ nó một chút với &&||thay vì if, nhưng nó trở nên khá xấu xí.

Tôi không tin wgetcó bất cứ điều gì được xây dựng để làm điều đó.


Tôi có thể đề nghị sử dụng elifđể làm cho ví dụ thứ hai rõ ràng hơn không? Một cái gì đó như thế này có lẽ? gist.github.com/IQAndreas/84cae3f0193b67691ff2 (nó chỉ thêm một dòng bổ sung, không bao gồm đặt thens trên cùng một dòng với ifs)
IQAndreas 22/07/14

Đủ công bằng. Bản dịch một dòng không đơn giản như bây giờ, nhưng dù sao nó cũng không tốt lắm.
Michael Homer

9

Bạn có thể sử dụng $?biến để lấy mã trả về của wget. Nếu nó khác không thì có nghĩa là đã xảy ra lỗi và bạn kiểm tra nó cho đến khi đạt đến ngưỡng, thì nó có thể thoát ra khỏi vòng lặp.

Một cái gì đó như thế này ra khỏi đỉnh đầu của tôi

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

Vòng lặp for có thể được làm sạch một chút, nhưng bạn có thể hiểu ý tưởng chung.

Thay đổi $threshold -eq 16thành -eq 24có nghĩa là nó sẽ thất bại 3 lần trước khi nó dừng lại, tuy nhiên nó sẽ không thành hai lần liên tiếp, sẽ là nếu nó thất bại hai lần trong vòng lặp.

Lý do tại sao 1624được sử dụng là tổng số mã trả về.
wget trả lời với mã trả về 8khi nhận được mã phản hồi tương ứng với lỗi từ máy chủ và do đó 16là tổng số sau 2 lỗi.

Dừng khi thất bại chỉ xảy ra hai lần liên tiếp có thể được thực hiện bằng cách đặt lại ngưỡng bất cứ khi nào wgetthành công, tức là khi mã trả về là 0


Có thể tìm thấy danh sách mã trả về wget tại đây - http://www.gnu.org/software/wget/manual/html_node/Exit-Status.html


2
Mặc dù có thể suy ra từ câu trả lời, bạn có thể muốn chỉ ra một cách rõ ràng rằng một lỗi 404 trả về mã thoát 8, do đó các số ma thuật của 1624.
IQAndreas

1
Tôi đã cập nhật câu trả lời của mình
Lawrence

1
Cảm ơn vì $?! Rất hữu ích!
neverMind9

2

Với GNU Parallel, điều này phải hoạt động:

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

Từ phiên bản 20140722, bạn gần như có thể có "hai liên tiếp" của mình: - tạm dừng 2% sẽ cho phép 2% công việc thất bại:

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

1

IMO, tập trung vào wgetmã thoát / trạng thái có thể quá ngây thơ đối với một số trường hợp sử dụng, vì vậy đây là một trường hợp xem xét Mã trạng thái HTTP cũng như đối với một số quyết định chi tiết.

wgetcung cấp một -S/--server-responsecờ để in ra các Tiêu đề phản hồi HTTP trên STDERRlệnh - mà chúng ta có thể trích xuất và hành động theo.

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

Trong python bạn có thể làm

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)

Kiểm tra tài liệu cho quy trình con nếu bạn muốn làm nhiều hơn https://docs.python.org/2/l Library / sub process.html


Trừ khi check_outputcó một số phép thuật xung quanh wgetđể phát hiện 404- Tôi không tin có những kiểm tra đầy đủ ở đây và vì vậy không thực sự trả lời câu hỏi.
shalomb

Nó làm, đọc các tài liệu. Nó kiểm tra đầu ra trong thiết bị xuất chuẩn hoặc thiết bị xuất chuẩn. wget có một mã cụ thể cho 404's
briankip
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.