web-dev-qa-db-fra.com

Télécharger une image à partir d'une URL?

J'essaie d'utiliser HTTP :: get pour télécharger une image d'un graphique Google à partir de l'URL que j'ai créée.

C'était ma première tentative:

failures_url  = [title, type, data, size, colors, labels].join("&")

require 'net/http'

Net::HTTP.start("http://chart.googleapis.com") { |http|
  resp = http.get("/chart?#{failures_url")
  open("pie.png" ,"wb") { |file|
    file.write(resp.body)
  }
}

Qui n'a produit qu'un fichier PNG vide.

Pour ma deuxième tentative, j'ai utilisé la valeur stockée dans failure_url dans l'appel http.get().

require 'net/http'

Net::HTTP.start("http://chart.googleapis.com") { |http|
  resp = http.get("/chart?chtt=Builds+in+the+last+12+months&cht=bvg&chd=t:296,1058,1217,1615,1200,611,2055,1663,1746,1950,2044,2781,1553&chs=800x375&chco=4466AA&chxl=0:|Jul-2010|Aug-2010|Sep-2010|Oct-2010|Nov-2010|Dec-2010|Jan-2011|Feb-2011|Mar-2011|Apr-2011|May-2011|Jun-2011|Jul-2011|2:|Months|3:|Builds&chxt=x,y,x,y&chg=0,6.6666666666666666666666666666667,5,5,0,0&chxp=3,50|2,50&chbh=23,5,30&chxr=1,0,3000&chds=0,3000")
  open("pie.png" ,"wb") { |file|
    file.write(resp.body)
  }
}

Et, pour une raison quelconque, cette version fonctionne même si la première tentative contenait les mêmes données dans l'appel http.get(). Quelqu'un sait pourquoi c'est comme cela?

SOLUTION:

Après avoir essayé de comprendre pourquoi cela se produisait, je trouvai " Comment télécharger un fichier binaire sur HTTP? ".

L'un des commentaires mentionne la suppression de http:// dans l'appel Net::HTTP.start(...) sinon le processus échouera. Bien sûr après avoir fait ceci:

failures_url  = [title, type, data, size, colors, labels].join("&")

require 'net/http'

Net::HTTP.start("chart.googleapis.com") { |http|
  resp = http.get("/chart?#{failures_url")
  open("pie.png" ,"wb") { |file|
    file.write(resp.body)
  }
}

ça a marché.

20
Hunter McMillen

J'irais après le fichier en utilisant Open :: URI :

require "open-uri"

File.open('pie.png', 'wb') do |fo|
  fo.write open("http://chart.googleapis.com/chart?#{failures_url}").read 
end

Si je préfère Open :: URI, c'est parce qu'il gère les redirections automatiquement. QUAND Google modifie leur back-end et tente de rediriger l'URL, le code le gérera comme par magie. Il gère également les délais d'attente et les tentatives plus gracieuses si je me souviens bien.

Si vous devez avoir un contrôle de niveau inférieur, consultez l'un des nombreux autres clients HTTP pour Ruby; Net :: HTTP convient à la création de nouveaux services ou lorsqu'un client n'existe pas, mais j'utiliserais Open :: URI ou autre chose que Net :: HTTP jusqu'à ce que le besoin se présente.


L'URL:

http://chart.googleapis.com/chart?chtt=Builds+in+the+last+12+months&cht=bvg&chd=t:296,1058,1217,1615,1200,611,2055,1663,1746,1950,2044,2781,1553&chs=800x375&chco=4466AA&chxl=0:|Jul-2010|Aug-2010|Sep-2010|Oct-2010|Nov-2010|Dec-2010|Jan-2011|Feb-2011|Mar-2011|Apr-2011|May-2011|Jun-2011|Jul-2011|2:|Months|3:|Builds&chxt=x,y,x,y&chg=0,6.6666666666666666666666666666667,5,5,0,0&chxp=3,50|2,50&chbh=23,5,30&chxr=1,0,3000&chds=0,3000

rend l'URI en colère. Je soupçonne qu'il voit des caractères qui devraient être encodés dans des URL. 

À des fins de documentation, voici ce que dit l'URI en essayant d'analyser cette URL telle quelle:

URI::InvalidURIError: bad URI(is not URI?)

Si je commence par encoder l'URI, l'analyse est réussie. Tester davantage avec Open :: URI montre qu'il est capable de récupérer le document à ce moment-là et renvoie 23701 octets.

Je pense que c'est le correctif approprié pour le problème si certains de ces caractères ne sont vraiment pas acceptables pour URIETils sont hors du RFC.

Juste pour information, le Addressable :: URI gem est un excellent remplacement pour l'URI intégré.

54
the Tin Man
    resp = http.get("/chart?#{failures_url")

Si vous avez copié votre code d'origine, il vous manque alors une accolade fermante dans la chaîne de chemin d'accès.

3
George

Votre version d'origine ne possédait pas le nom du paramètre pour chaque paramètre, mais uniquement les données. Par exemple, sur le titre, vous ne pouvez pas simplement soumettre "Constructions + dans + les + derniers + 12 + mois", mais plutôt "chtt = Constructions + dans + les + derniers + 12 + mois".

Essaye ça:

failures_url  = ["title="+title, "type="+type, "data="+data, "size="+size, "colors="+colors, "labels="+labels].join("&")
0
Jonathan M