2

次の Ruby スクリプトを使用して、HTTP 経由でバイナリ ファイルをダウンロードしようとしています。

#!/usr/bin/env ruby
require 'net/http'
require 'uri'

def http_download(resource, filename, debug = false)
  uri = URI.parse(resource)
  puts "Starting HTTP download for: #{uri}"
  http_object = Net::HTTP.new(uri.host, uri.port)
  http_object.use_ssl = true if uri.scheme == 'https'
  begin
    http_object.start do |http|
      request = Net::HTTP::Get.new uri.request_uri
      Net::HTTP.get_print(uri) if debug
      http.read_timeout = 500
      http.request request do |response|
        open filename, 'w' do |io|
          response.read_body do |chunk|
            io.write chunk
          end
        end
      end
    end
  rescue Exception => e
    puts "=> Exception: '#{e}'. Skipping download."
    return
  end
  puts "Stored download as #{filename}."
end

ただし、バイナリではなく HTML ソースをダウンロードします。ブラウザに URL を入力すると、バイナリ ファイルがダウンロードされます。スクリプトが失敗する URL は次のとおりです。

http://dcatlas.dcgis.dc.gov/catalog/download.asp?downloadID=2175&downloadTYPE=KML

次のようにスクリプトを実行します

pry> require 'myscript'
pry> resource = "http://dcatlas.dcgis.dc.gov/catalog/download.asp?downloadID=2175&downloadTYPE=KML"
pry> http_download(resource,"StreetTreePt.KML", true)

どうすればバイナリをダウンロードできますか?

リダイレクト実験

私はこのリダイレクトチェックを見つけましたが、これはかなり合理的に見えます。応答ブロックに統合すると、次のエラーで失敗します。

Exception: 'undefined method `host' for "save_download.asp?filename=StreetTreePt.KML":String'. Skipping download.

上記の「元の」関数では例外は発生しません。

4

1 に答える 1

3

Net::HTTP のドキュメントには、リダイレクトの処理方法が示されています。

次のリダイレクト

各 Net::HTTPResponse オブジェクトは、応答コードのクラスに属しています。

たとえば、すべての 2XX 応答は Net::HTTPSuccess サブクラスのインスタンスであり、3XX 応答は Net::HTTPRedirection サブクラスのインスタンスであり、200 応答は Net::HTTPOK クラスのインスタンスです。応答クラスの詳細については、以下のセクション「HTTP 応答クラス」を参照してください。

case ステートメントを使用すると、さまざまなタイプの応答を適切に処理できます。

def fetch(uri_str, limit = 10)
  # You should choose a better exception.
  raise ArgumentError, 'too many HTTP redirects' if limit == 0

  response = Net::HTTP.get_response(URI(uri_str))

  case response
  when Net::HTTPSuccess then
    response
  when Net::HTTPRedirection then
    location = response['location']
    warn "redirected to #{location}"
    fetch(location, limit - 1)
  else
    response.value
  end
end

print fetch('http://www.ruby-lang.org')

または、それを自動的に処理する Ruby のOpenURIを使用できます。または、縁石の宝石がそれを行います. おそらくTyphoeusHTTPClientも。

質問に表示されているコードによると、取得している例外は次のものからのみ発生します。

http_object = Net::HTTP.new(uri.host, uri.port)

uriこれはURI オブジェクトであるため、ほとんどありません。その問題のヘルプが必要な場合は、完全なコードを表示する必要があります。

于 2013-05-17T20:28:07.497 に答える