Как загрузить отложенный файл через HTTP в Ruby?

Я использую следующую функцию Ruby для загрузки различных файлов через HTTP:

def http_download(uri, filename)
  bytes_total = nil
  begin
    uri.open(
      read_timeout: 500,
      content_length_proc: lambda { |content_length|
        bytes_total = content_length
      },
      progress_proc: lambda { |bytes_transferred|
        if bytes_total
          print("\r#{bytes_transferred} of #{bytes_total} bytes")
        else
          print("\r#{bytes_transferred} bytes (total size unknown)")
        end
      }
    ) do |file|
      open filename, 'w' do |io|
        file.each_line do |line|
          io.write line
        end
      end
    end
  rescue => e
    puts e
  end
end

Я также хочу скачать файлы (csv, kml, zip, geojson) из этот сайт. Однако настроена какая-то задержка. Когда я нажимаю ссылку для скачивания в браузере, требуется некоторое время, пока не появится окно загрузки. Я предполагаю, что файл должен быть обработан на сервере, прежде чем его можно будет обслужить.

Как я могу изменить свой сценарий, чтобы учесть задержку?

Я использую Руби 2.2.2.


person JJD    schedule 02.07.2015    source источник
comment
Привет, какая у тебя версия Руби? Я запускаю ваш код, используя Ruby 2.2.2, получил исключение при вызове закрытого метода «open». И я открыл веб-сайт, вы нажимаете кнопку «Загрузить набор данных»? Я не сталкивался с задержкой, о которой вы упомянули, просто URL-адрес веб-сайта добавляет .csv, .kml, .zip и несколько параметров запроса.   -  person ifyouseewendy    schedule 02.07.2015
comment
Да, последняя версия. Да, ссылки скрыты под кнопкой «Загрузить набор данных». Может быть, они буферизуют его на сервере сейчас, когда я нажал на него. Попробуйте другой набор данных, возможно.   -  person JJD    schedule 02.07.2015
comment
Я обнаружил, что для набора данных при первом запросе он возвращает JSON, который представляет статус, например. { status: "processing", processing_time: 0, count: 0 }, { status: "processing", processing_time: 9.58, count: 0 }. И после обработки вы скачаете файл. Поэтому я думаю, что вы можете просто добавить судью и повторить попытку обработки.   -  person ifyouseewendy    schedule 02.07.2015
comment
Правильный. Что вы подразумеваете под добавлением судьи?   -  person JJD    schedule 02.07.2015


Ответы (1)


Вот модификация согласно сообщению и комментарию:

require 'open-uri'

def http_download(uri, filename)
  bytes_total = nil
  index = 1
  begin
    open(
      uri,
      read_timeout: 500,
      content_length_proc: lambda { |content_length|
        bytes_total = content_length
      },
      progress_proc: lambda { |bytes_transferred|
        if bytes_total
          print("\r#{bytes_transferred} of #{bytes_total} bytes")
        else
          print("\r#{bytes_transferred} bytes (total size unknown)")
        end
      }
    ) do |io|
      # if "application/json" == io.content_type
      if io.is_a? StringIO
        raise " --> Failed, server is processing. Retry the request ##{index}"
      else # Tempfile
        puts "\n--> Succeed, writing to #{filename}"
        File.open(filename, 'w'){|wf| wf.write io.read}
      end
    end
  rescue => e
    puts e
    return if e.is_a? OpenURI::HTTPError # Processing error

    index += 1
    return if index > 10

    sleep index and retry
  end
end
person ifyouseewendy    schedule 03.07.2015
comment
Потрясающий! Я заметил один незначительный случай, когда загрузка представляет собой файл JSON — я добавил ссылку выше. - person JJD; 03.07.2015
comment
Большой! Я попробовал скрипт на другом сервере (kml). Там он почему-то не работает, хотя вроде бы тот же механизм задержки. Вы видите причину? - person JJD; 06.07.2015
comment
Извините, я сделал свою работу, и я не думаю, что смогу исправить вам все дела. - person ifyouseewendy; 06.07.2015
comment
Понял. Хотя мне кажется это та же установка сервера. Вот почему странно, что данные не возвращаются. - person JJD; 06.07.2015