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,它会自动处理它。或者,Curb gem 会做到这一点。也可能是 TyphoeusHTTPClient

根据您在问题中显示的代码,您得到的异常只能来自:

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

这几乎不可能,因为uri它是一个 URI 对象。如果您需要有关该问题的帮助,则需要显示完整的代码。

于 2013-05-17T20:28:07.497 回答