คุณหยุด 'wget' หลังจากที่ได้รับ 404 ได้อย่างไร


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 ครั้งแรกหรือไม่ (หรือดียิ่งขึ้นสองในแถวในกรณีที่มีไฟล์หายไปในช่วงด้วยเหตุผลอื่น) คำตอบไม่จำเป็นต้องใช้การขยายรั้ง; ลูปก็ดีเช่นกัน


1
ในสถานการณ์แบบเรียลไทม์คุณอาจต้องการให้ทุก URL ทราบสถานะ 1, 2 or even n failuresไม่ใช่วิธีที่ถูกต้องเมื่อคุณรู้[begin .. end]ดัชนี ทำไมคุณจะระบุ[1..200]ช่วงเมื่อคุณรู้ว่ามีเพียง 100 [1..100]ภาพใน ฉันเดาว่าคุณสามารถลอง GNU parallelเพื่อขอให้พร้อมกันเพื่อเร่งกระบวนการ
SparKot

1
@SparKot ที่สำคัญคือผมไม่ได้รู้ว่ามีเพียง 100 ภาพบนเซิร์ฟเวอร์ฉันต้องการสคริปต์เพื่อดาวน์โหลดเป็นภาพมากเท่าที่จะสามารถอยู่ในชุดจนกว่าจะได้คิดออกที่ท้ายที่สุดก็คือ
IQAndreas

คำตอบ:


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 ในบรรทัดเดียวกับifs)
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 ครั้งก่อนที่มันจะหยุด แต่มันจะไม่เป็นสองแถวก็จะเป็นถ้ามันล้มเหลวเป็นครั้งที่สองในวง

เหตุผลที่ใช้16และ24มีเหตุผลนั่นคือผลรวมของรหัสส่งคืน
wget ตอบกลับด้วยรหัสส่งคืน8เมื่อได้รับรหัสตอบกลับที่สอดคล้องกับข้อผิดพลาดจากเซิร์ฟเวอร์ดังนั้นจึง16เป็นผลรวมหลังจากข้อผิดพลาด 2 ข้อ

การหยุดเมื่อความล้มเหลวเกิดขึ้นเพียงสองครั้งในแถวเดียวสามารถทำได้โดยการรีเซ็ตขีด จำกัด เมื่อใดก็ตามที่wgetสำเร็จเช่นเมื่อรหัสส่งคืนเป็น 0


รายการรหัสส่งคืน wget สามารถพบได้ที่นี่ - http://www.gnu.org/software/wget/manual/html_node/Exit-Status.html


2
แม้ว่ามันจะสามารถสรุปจากคำตอบที่คุณอาจต้องการอย่างชัดเจนชี้ให้เห็นว่าข้อผิดพลาด 404 กลับรหัสทางออกของ8จึงหมายเลขมายากลของและ16 24
IQAndreas

1
ฉันได้อัปเดตคำตอบแล้ว
ล.ค. Lawrence

1
ขอบคุณสำหรับ$?! มีประโยชน์มาก!
neverMind9

2

ด้วย GNU Parallel สิ่งนี้ควรทำงาน:

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

จากเวอร์ชัน 20140722 คุณสามารถมี "สองต่อเนื่อง" ได้ - การรับประกัน: - สูง 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แฟล็กเพื่อพิมพ์ HTTP Response Headers บน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

ในงูหลามคุณสามารถทำได้

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.