আমি কীভাবে এইচটিটিপি-র মাধ্যমে বাইনারি ফাইল ডাউনলোড করব?


131

আমি রুবি ব্যবহার করে এইচটিটিপি-র মাধ্যমে কীভাবে একটি বাইনারি ফাইল ডাউনলোড করব এবং সংরক্ষণ করব?

ইউআরএল হল http://somedomain.net/flv/sample/sample.flv

আমি উইন্ডোজ প্ল্যাটফর্মে আছি এবং আমি কোনও বাহ্যিক প্রোগ্রাম না চালানো পছন্দ করব।


আমার সমাধানটি snippets.dzone.com/posts/show/2469 এর উপর ভিত্তি করে তৈরি হয়েছে যা আমি ফায়ারফক্স অ্যাড্রেস বারে রুবি ফাইল ডাউনলোড টাইপের পরে উপস্থিত হয়েছিল ... সুতরাং আপনি এই প্রশ্ন জিজ্ঞাসা করার আগে ইন্টারনেটে কোনও গবেষণা করেছিলেন?
দাউদ

@ দেজউ: আমি গবেষণা করেছি এবং এখানে একটি উত্তর উত্তর পেয়েছি। মূলত আপনি আমাকে দিয়েছেন একই কোড দিয়ে। resp.bodyঅংশ আমাকে বিভ্রান্তিকর আমি ভেবেছিলাম এটা কেবল 'শরীর' প্রতিক্রিয়া অংশ ব্যয় হলেও পুরো / বাইনারি ফাইল সংরক্ষণ করতে চান। আমি এটিও পেয়েছি যে rio.rubyforge.org সহায়ক হতে পারে। তদুপরি আমার প্রশ্নের সাথে কেউ বলতে পারবেন না যে এই ধরণের প্রশ্নের এখনও উত্তর দেওয়া হয়নি :-)
রাদেক

3
শরীরের অংশটি হুবহু পুরো ফাইল। প্রতিক্রিয়া শিরোনাম (HTTP) এবং বডি (ফাইল) থেকে তৈরি করা হয়েছে, সুতরাং আপনি যখন দেহটি সংরক্ষণ করেন আপনি ফাইলটি সংরক্ষণ করেছেন ;-)
দাউদ

1
আরও একটি প্রশ্ন ... আসুন বলি যে ফাইলটি 100MB বড় এবং ডাউনলোডের প্রক্রিয়াটি মাঝখানে বাধাগ্রস্থ হয়। সেখানে কি কিছু রক্ষা হবে? আমি কি ফাইলটি আবার শুরু করতে পারি?
রাদেক

দুর্ভাগ্যক্রমে নয়, কারণ http.get('...')কল একটি অনুরোধ প্রেরণ করে এবং প্রতিক্রিয়া গ্রহণ করে (পুরো ফাইলটি)। খণ্ডগুলিতে একটি ফাইল ডাউনলোড করতে এবং এটি একই সাথে সংরক্ষণ করতে নীচে আমার সম্পাদিত উত্তরটি দেখুন ;-) পুনরায় শুরু করা সহজ নয়, সম্ভবত আপনি সংরক্ষণ করেছেন বাইটগুলি গণনা করুন এবং তারপরে আপনি ফাইলটি পুনরায় ডাউনলোড করার সময় সেগুলি এড়িয়ে যান ( file.write(resp.body)লিখিত বাইটের সংখ্যা ফেরৎ)।
দাউদ

উত্তর:


143

সবচেয়ে সহজ উপায় হ'ল প্ল্যাটফর্ম-নির্দিষ্ট সমাধান:

 #!/usr/bin/env ruby
`wget http://somedomain.net/flv/sample/sample.flv`

সম্ভবত আপনি অনুসন্ধান করছেন:

require 'net/http'
# Must be somedomain.net instead of somedomain.net/, otherwise, it will throw exception.
Net::HTTP.start("somedomain.net") do |http|
    resp = http.get("/flv/sample/sample.flv")
    open("sample.flv", "wb") do |file|
        file.write(resp.body)
    end
end
puts "Done."

সম্পাদনা: পরিবর্তন হয়েছে। ধন্যবাদ.

সম্পাদনা 2: সমাধানটি ডাউনলোড করার সময় কোনও ফাইলের কিছু অংশ সংরক্ষণ করে:

# instead of http.get
f = open('sample.flv')
begin
    http.request_get('/sample.flv') do |resp|
        resp.read_body do |segment|
            f.write(segment)
        end
    end
ensure
    f.close()
end

15
হ্যা আমি জানি. এই কারণেই আমি বলেছিলাম যে এটি তাই a platform-specific solution
দাউদ

1
আরও প্ল্যাটফর্ম-নির্দিষ্ট সমাধান: জিএনইউ / লিনাক্স প্ল্যাটফর্ম সরবরাহ করে wget। ওএস এক্স সরবরাহ করে curl( curl http://oh.no/its/pbjellytime.flv --output secretlylove.flv)। উইন্ডোজ একটি পাওয়ারশেল সমতুল্য আছে (new-object System.Net.WebClient).DownloadFile('http://oh.no/its/pbjellytime.flv','C:\tmp\secretlylove.flv')। ডাউনলোডের মাধ্যমে সমস্ত অপারেটিং সিস্টেমের জন্য উইজেট এবং কার্লের বাইনারি রয়েছে exist আপনার লিখনের কোডটি কেবল আপনার নিজের লভিনের জন্য না থাকলে আমি এখনও স্ট্যান্ডার্ড লাইব্রেরিটি ব্যবহার করার পরামর্শ দিচ্ছি।
fny

1
আর্ট ... নিশ্চিত করুন ... ওপেন ব্লক ফর্মটি ব্যবহার করা হলে শেষের প্রয়োজন হয় না। 'নমুনা.ফ্লাভি' করুন | চ | খুলুন .... f.writ বিভাগ
Lab419

1
অ-পাঠ্য ফাইলটি দুর্নীতিগ্রস্থ হয়।
পল

1
আমি ছিটিয়ে ডাউনলোড ব্যবহার করে Net::HTTP। এবং আমি ফাইলটির অংশটি পেয়েছি তবে প্রতিক্রিয়া পেয়েছি Net::HTTPOK। আমরা ফাইলটি সম্পূর্ণ ডাউনলোড করেছি তা নিশ্চিত করার কোনও উপায় আছে কি?
নিকোলায় কনড্রেটেনকো

118

আমি জানি যে এটি একটি পুরানো প্রশ্ন, তবে গুগল আমাকে এখানে ফেলে দিয়েছে এবং আমি মনে করি আমি এর একটি সহজ উত্তর পেয়েছি।

ইন Railscasts # 179 রায়ান বেটস রুবি মান বর্গ ব্যবহৃত OpenURI অনেক কি ভালো জিজ্ঞাসা করা হল এর কাজ করতে:

( সতর্কতা : অরীক্ষিত কোড You আপনার এটি পরিবর্তন / টুইঙ্কের প্রয়োজন হতে পারে))

require 'open-uri'

File.open("/my/local/path/sample.flv", "wb") do |saved_file|
  # the following "open" is provided by open-uri
  open("http://somedomain.net/flv/sample/sample.flv", "rb") do |read_file|
    saved_file.write(read_file.read)
  end
end

9
open("http://somedomain.net/flv/sample/sample.flv", 'rb')বাইনারি মোডে URL টি খুলবে।
zoli

1
@ ইসার বর্ণনা অনুসারে ওপেন-ইউরি বাফারটি পূরণ করা সম্পর্কে বুদ্ধিমান কিনা কেউ জানে?
gdelfino

1
@ গিলডিফিনো আপনি যদি এর জন্য একটি নতুন প্রশ্ন খোলেন তবে আপনি আরও উত্তর পাবেন। অনেক লোক এটি পড়তে পারে না এমন সম্ভাবনা নেই (এবং এটি স্ট্যাক ওভারফ্লোতে করাও অ্যাপ্রোপিয়েট জিনিস)।
কিকিতো

2
অসাধারণ. আমি HTTP=> HTTPSপুনঃনির্দেশে সমস্যা পেয়েছি এবং জহর ব্যবহার করে কীভাবে সমাধান করবেন তা খুঁজে পেলামopen_uri_redirections
ম্যাথিওলো

1
এফডাব্লুআইডাব্লিউআইডব্লিউআইডাব্লিউআইডব্লিউআইডব্লিউআইডব্লিউআইডব্লিউআইডব্লিউআইডব্লিউআইডাব্লুআইডব্লিউআইডব্লিউআইডব্লিউআইডব্লিউআইডব্লিউআইডব্লিউআইডব্লিউআইডাব্লিউআইডব্লিউআইডাব্লিউআইডব্লিউআইডাব্লিউআইডাব্লিউআইডব্লিউআইবিআইডাব্লিউআইবিআই বিপজ্জনক কারণ এটি লাইব্রেরি কোড সহ সমস্ত কোড বানিয়েছে openযা কলিং কোডটি প্রত্যাশা না করে এমন একটি নতুন দক্ষতার সাথে ব্যবহার করে। আপনার openযেভাবেই ব্যবহারকারীর ইনপুটটি পাস হয়েছে তা বিশ্বাস করা উচিত নয় , তবে আপনাকে এখন দ্বিগুণ যত্নবান হওয়া দরকার।
পদ্ধতি

42

ফাইলটি ব্যবহার করতে আমার রুবি এইচটিপি এখানে open(name, *rest, &block)

require "open-uri"
require "fileutils"

def download(url, path)
  case io = open(url)
  when StringIO then File.open(path, 'w') { |f| f.write(io) }
  when Tempfile then io.close; FileUtils.mv(io.path, path)
  end
end

এখানে প্রধান সুবিধা এটি সংক্ষিপ্ত এবং সহজ, কারণ openভারী উত্তোলন অনেকটাই করে। এবং এটি স্মরণে পুরো প্রতিক্রিয়াটি পড়ে না।

openপদ্ধতি প্রতিক্রিয়া স্ট্রিম হবে> একটি থেকে 1kb Tempfile। আমরা এই জ্ঞানটি ফাইল পদ্ধতিতে এই চর্বি ডাউনলোডটি বাস্তবায়নের জন্য কাজে লাগাতে পারি। দেখুন OpenURI::Bufferবাস্তবায়ন এখানে।

ব্যবহারকারীর সরবরাহিত ইনপুটটি সম্পর্কে সতর্ক থাকুন! open(name, *rest, &block)অনিরাপদ যদি nameব্যবহারকারীর ইনপুট থেকে আসে!


4
এটি সংক্ষিপ্ত এবং সাধারণ হিসাবে মেনে নেওয়া উত্তর হওয়া উচিত এবং মেমরির পুরো ফাইলটি লোড করে না performance + পারফরম্যান্স (এখানে অনুমান)।
নিককোলাসগ

আমি নিককোলাস্গের সাথে একমত আমি এটি ব্যবহার করার চেষ্টা করেছি এবং এটি খুব ভালভাবে কাজ করে। আমি এটিকে কিছুটা সংশোধন করেছিলাম, উদাহরণস্বরূপ, প্রদত্ত ইউআরএল থেকে স্থানীয় পথটি স্বয়ংক্রিয়ভাবে কেটে নেওয়া হবে, সুতরাং "প্যাথ = নীল" এবং তারপরে নীল পরীক্ষা করা; যদি এটি নিল হয়, তবে আমি স্থানীয় পথটি অনুমিত করার জন্য ইউআরএলে ফাইল.ব্যাসনাম () ব্যবহার করি।
শেভি

1
এই সর্বোত্তম উত্তর হতে পারে, কিন্তু ওপেন URI করেনা মেমরি পুরো ফাইল লোড stackoverflow.com/questions/17454956/...
সাইমন Perepelitsa

2
পুনঃটুইট করেছেন আমি এটি আবারও সংশোধন করেছি, এখন একটি সংক্ষিপ্ত ডাউনলোড-টু-ফাইল পদ্ধতি সরবরাহ করছি যা মেমরির মধ্যে পুরো প্রতিক্রিয়াটি পড়ে না । আমার আগের উত্তরটি যথেষ্ট ছিল, কারণ openআসলে প্রতিক্রিয়াটি মেমরির মধ্যে পড়ে না, এটি কোনও প্রতিক্রিয়া> 10240 বাইটের জন্য এটি একটি অস্থায়ী ফাইলে পড়ে reads সুতরাং আপনি সদয় ছিলেন ঠিক কিন্তু না। সংশোধিত উত্তরটি এই ভুল বোঝাবুঝি পরিষ্কার করে এবং আশা করি রুবির শক্তির উপর একটি দুর্দান্ত উদাহরণ হিসাবে কাজ করেছে :)
ওভারব্রাইড

3
কমান্ড EACCES: permission deniedসহ ফাইলের নাম পরিবর্তন করার সময় আপনি যদি ত্রুটি পান তবে এর আগে আপনাকে mvফাইলটি বন্ধ করতে হবে। অংশটি পরিবর্তনের পরামর্শ দিনTempfile then io.close;
ডেভিড ডগলাস

28

রুবির নেট / এইচপি ডকুমেন্টেশনের 3 উদাহরণ ৩ নং উদাহরণটি দেখায় যে কীভাবে এইচটিটিপি-র মাধ্যমে কোনও ডকুমেন্ট ডাউনলোড করা যায় এবং ফাইলটিকে কেবল মেমরিতে লোড না করে আউটপুট করা যায়, যেমন কোনও ফাইলে বাইনারি লেখার সাথে বিকল্প রাখে, যেমন দেজউয়ের উত্তরে দেখানো হয়েছে।

আরও জটিল কেস আরও একই ডকুমেন্টে দেখানো হয়েছে।


বিদ্যমান নথিপত্র এবং আরও উদাহরণগুলিতে ইঙ্গিত করার জন্য +1।
সেম্পেরোস

1
এখানে লিঙ্কটি বিশেষভাবে দেওয়া হয়েছে: রুবি
ডোক.আর.এস.সি.ডি.লি

26

আপনি ওপেন-ইউরি ব্যবহার করতে পারেন, এটি ওয়ান লাইনার

require 'open-uri'
content = open('http://example.com').read

অথবা নেট / এইচটিপি ব্যবহার করে

require 'net/http'
File.write("file_name", Net::HTTP.get(URI.parse("http://url.com")))

10
এটি ডিস্কে লেখার আগে পুরো ফাইলটিকে মেমরির মধ্যে পড়ে, তাই ... এটি খারাপ হতে পারে।
কেজিলপিন

@kgilpin উভয় সমাধান?
ক্রাউসএফএক্স

1
হ্যাঁ, উভয় সমাধান।
এলটিয়ারে

বলেন যে, যে সাথে এসেছেন ঠিক আছে যদি আপনি একটি সংক্ষিপ্ত সংস্করণ (অভিমানী URL এবং ফাইলের নাম ভেরিয়েবল আছে urlএবং fileযথাক্রমে), ব্যবহার open-uriপ্রথম হিসাবে: File.write(file, open(url).read)... ডেড সহজ তুচ্ছ ডাউনলোড ক্ষেত্রে জন্য।
lindes

17

দেজউয়ের উত্তরটির সম্প্রসারণ (সম্পাদনা 2):

File.open(filename,'w'){ |f|
  uri = URI.parse(url)
  Net::HTTP.start(uri.host,uri.port){ |http| 
    http.request_get(uri.path){ |res| 
      res.read_body{ |seg|
        f << seg
#hack -- adjust to suit:
        sleep 0.005 
      }
    }
  }
}

কোথায় filenameএবংurl স্ট্রিং হয়।

sleepকমান্ড একটি হ্যাক করে যায় নাটকীয়ভাবে CPU ব্যবহার কমাতে যখন নেটওয়ার্ক সীমিত ফ্যাক্টর। নেট :: এইচটিটিপি ফলনের আগে বাফার (v1.9.2 এ 16kB) অপেক্ষা করার অপেক্ষা রাখে না, সুতরাং সিপিইউ ব্যস্ত হয়ে পড়ে ছোট ছোট খণ্ডগুলি moving এক মুহুর্তের জন্য ঘুমানো বাফারকে লেখার মধ্যে পূরণ করার সুযোগ দেয় এবং সিপিইউ ব্যবহারটি আমার প্রয়োগের 4-5x পার্থক্যের সাথে কার্ল সমাধানের সাথে তুলনীয়। আরও শক্তিশালী সমাধান এর অগ্রগতি পরীক্ষা করতে পারেf.pos লক্ষ্য নির্ধারণের সময়সীমার করতে এবং সময়সীমার সামঞ্জস্য করতে পারে, বলুন, বাফার সাইজের 95% - বাস্তবে আমি উদাহরণটিতে 0.005 নম্বর পেয়েছি।

দুঃখিত, তবে রুফির বাফারটি পূরণের অপেক্ষার আরও মার্জিত উপায় আমি জানি না।

সম্পাদনা:

এটি এমন একটি সংস্করণ যা বাফারকে সামর্থ্য বা ঠিক নীচে রাখতে স্বয়ংক্রিয়ভাবে নিজেকে সামঞ্জস্য করে। এটি একটি অবাস্তব সমাধান, তবে এটি ঠিক তত দ্রুত বলে মনে হচ্ছে, এবং সিপিইউর মতো সময় কম ব্যবহার করা উচিত, কারণ এটি কার্ল করার জন্য ডাকে।

এটি তিনটি পর্যায়ে কাজ করে। ইচ্ছাকৃতভাবে দীর্ঘ ঘুমের সময় সহ একটি সংক্ষিপ্ত শিক্ষার সময়কাল একটি সম্পূর্ণ বাফারের আকারকে প্রতিষ্ঠিত করে। ড্রপ পিরিয়ড প্রতিটি পুনরাবৃত্তির সাথে ঘুমের সময় দ্রুত হ্রাস করে, এটি কোনও বৃহত্তর ফ্যাক্টর দ্বারা গুণ করে, যতক্ষণ না এটি কোনও আন্ডার-ভরা বাফারটি খুঁজে পায়। তারপরে, স্বাভাবিক সময়কালে, এটি একটি ছোট ফ্যাক্টর দ্বারা উপরে এবং নীচে সামঞ্জস্য হয়।

আমার রুবি কিছুটা মরিচা, তাই আমি নিশ্চিত যে এটি আরও উন্নত হতে পারে। প্রথমত, পরিচালনা করার কোনও ত্রুটি নেই। এছাড়াও, সম্ভবত এটি ডাউনলোড থেকে দূরে কোনও বস্তুর মধ্যে পৃথক করা যেতে পারে, যাতে আপনি কেবল নিজের লুপটিতে কল করতে চান autosleep.sleep(f.pos)? আরও ভাল, নেট :: এইচটিটিপি উত্পাদনের আগে একটি পূর্ণ বাফারের জন্য অপেক্ষা করার জন্য পরিবর্তন করা যেতে পারে:

def http_to_file(filename,url,opt={})
  opt = {
    :init_pause => 0.1,    #start by waiting this long each time
                           # it's deliberately long so we can see 
                           # what a full buffer looks like
    :learn_period => 0.3,  #keep the initial pause for at least this many seconds
    :drop => 1.5,          #fast reducing factor to find roughly optimized pause time
    :adjust => 1.05        #during the normal period, adjust up or down by this factor
  }.merge(opt)
  pause = opt[:init_pause]
  learn = 1 + (opt[:learn_period]/pause).to_i
  drop_period = true
  delta = 0
  max_delta = 0
  last_pos = 0
  File.open(filename,'w'){ |f|
    uri = URI.parse(url)
    Net::HTTP.start(uri.host,uri.port){ |http|
      http.request_get(uri.path){ |res|
        res.read_body{ |seg|
          f << seg
          delta = f.pos - last_pos
          last_pos += delta
          if delta > max_delta then max_delta = delta end
          if learn <= 0 then
            learn -= 1
          elsif delta == max_delta then
            if drop_period then
              pause /= opt[:drop_factor]
            else
              pause /= opt[:adjust]
            end
          elsif delta < max_delta then
            drop_period = false
            pause *= opt[:adjust]
          end
          sleep(pause)
        }
      }
    }
  }
end

আমি sleepহ্যাক পছন্দ করি !
রাদেক

13

এপিআই-বান্ধব লাইব্রেরিগুলির চেয়ে আরও অনেকগুলি রয়েছে Net::HTTP, উদাহরণস্বরূপ httparty :

require "httparty"
File.open("/tmp/my_file.flv", "wb") do |f| 
  f.write HTTParty.get("http://somedomain.net/flv/sample/sample.flv").parsed_response
end

3

আমার সমস্যা ছিল, যদি ফাইলটিতে জার্মান উমলাউট (ä, ö, ü) থাকে। আমি ব্যবহার করে সমস্যাটি সমাধান করতে পারতাম:

ec = Encoding::Converter.new('iso-8859-1', 'utf-8')
...
f << ec.convert(seg)
...

0

যদি আপনি কীভাবে অস্থায়ী ফাইল ডাউনলোড করতে চান, তবে স্টাফ করুন এবং মুছুন এই মণিটি https://github.com/equivalent/pull_tempfile ব্যবহার করে

require 'pull_tempfile'

PullTempfile.transaction(url: 'https://mycompany.org/stupid-csv-report.csv', original_filename: 'dont-care.csv') do |tmp_file|
  CSV.foreach(tmp_file.path) do |row|
    # ....
  end
end
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.