8

我想通过这种方式下载音乐文件:

require 'open-uri'

source_url = "http://soundcloud.com/stereo-foo/cohete-amigo/download"

attachment_file = "test.wav"

open(attachment_file, "wb") do |file|  
  file.print open(source_url).read
end

在该示例中,我想将“Test.wav”更改为真实文件名(例如 JDownloader 程序)。

编辑:我不是指临时文件,我指的是存储在网络中的文件,比如 Jdownloader 得到:“Cohete Amigo - Stereo Foo.wav”

谢谢你的阅读

更新:

我试过这个来存储名称:

attachment_file = File.basename(open(source_url))

我认为这没有意义,但我不知道该怎么做,对不起。

4

2 回答 2

19

文件名存储在名为Content-Disposition. 然而,解码这个字段可能有点棘手。例如,请参阅此处的一些讨论:

如何在 HTTP 中对 Content-Disposition 标头的文件名参数进行编码?

因为您可以通过返回类open-uri的访问器访问所有头字段:metaFile

f = open('http://soundcloud.com/stereo-foo/cohete-amigo/download')
f.meta['content-disposition']
=> "attachment;filename=\"Stereo Foo - Cohete Amigo.wav\""

所以为了解码类似的东西,你可以这样做:

cd = f.meta['content-disposition'].
filename = cd.match(/filename=(\"?)(.+)\1/)[2]
=> "Stereo Foo - Cohete Amigo.wav"

它适用于您的特定情况,如果引号"不存在,它也适用。但是在像 UTF-8 文件名这样更复杂的内容处理情况下,您可能会遇到一些麻烦。但不确定 UTF-8 的使用频率,甚至 soundcloud 是否曾经使用过 UTF-8。所以也许你不需要担心(未经证实或测试)。

您还可以使用更高级的网络爬虫框架,例如Mechanize,并相信它会为您进行解码:

require 'mechanize'

agent = Mechanize.new
file = agent.get('http://soundcloud.com/stereo-foo/cohete-amigo/download')
file.filename
=> "Stereo_Foo_-_Cohete_Amigo.wav"
于 2012-11-15T09:05:01.013 回答
5

File.basename(open(source_url))不起作用,因为open(source_url)返回某种 I/O 句柄,而不是File.basename期望的字符串。

File.basename(source_url)

将有更好的工作机会,除非 URL 使用某种path/to/service/with/parameters/in/line/like/this类型编码。

不过,Ruby 的 URI 库有一些有用的工具可以提供帮助。就像是:

File.basename(URI.parse(source_url).path)

将是一个起点。例如:

require 'uri'

File.basename(URI.parse('http://www.example.com/path/to/file/index.html').path
# => "index.html"

和:

File.basename(URI.parse('http://www.example.com/path/to/file/index.html?foo=bar').path)
# => "index.html"

你知道我是否也可以检索文件大小以及如何?

在本地测试 HTTP 内容的一个好方法是从命令行运行gem server,然后让 gems 启动一个小型 Web 服务器来获取它的文档:

require 'open-uri'

html_doc = open('http://0.0.0.0:8808/') do |io|
  puts io.size
  io.read
end

puts html_doc.size

# => 114350
# => 114350

当您通过 OpenURI 的命令使用块时open,它使您可以访问块变量中有关连接的大量信息,该变量是Tempfile类的一个实例。因此,您可以使用size.

这对于小文件来说是可以的,但是如果您要拉入一个大文件,您可能需要使用 Net::HTTP 进行调查以发送head请求,其中可能包括大小。我说可能,因为有时服务器不知道会返回多少,在动态内容的情况下,或者内容被 CGI 或不费心说的子服务返回的情况下。

使用“head”请求的优点是服务器不返回整个内容,只返回标头。因此,在过去,我使用head, 来提出请求,以查看是否可以获得所需的数据。如果没有,我将被迫使用正常的get.

于 2012-11-15T14:08:10.393 回答