【问题标题】:Python download without supplying a filename不提供文件名的 Python 下载
【发布时间】:2010-05-08 19:28:35
【问题描述】:

如何使用 python 下载带有进度报告但不提供文件名的文件。

我试过 urllib.urlretrieve 但我似乎必须为下载的文件提供一个文件名才能保存。

例如:

我不想提供这个:

urllib.urlretrieve("http://www.mozilla.com/products/download.html?product=firefox-3.6.3&os=win&lang=en-US", "/tmp/firefox.exe")

就这个:

urllib.urlretrieve("http://www.mozilla.com/products/download.html?product=firefox-3.6.3&os=win&lang=en-US", "/tmp/")

但如果我这样做了,我会收到此错误:

IOError: [Errno 21] Is a directory: '/tmp'

也无法从某个 URL 获取文件名 示例:

http://www.mozilla.com/products/download.html?product=firefox-3.6.3&os=win&lang=en-US

【问题讨论】:

  • 如果您不知道要下载什么,怎么下载?你需要一些标识符。请澄清您的问题。
  • 对不起,我的意思是下载保存为的文件名。我知道网址。我希望这是有道理的。
  • 不确定我是否理解您的问题:您想从给定的 URL 中提取文件名,然后将其用作用户定义目录下的文件名?

标签: python download urllib2 urllib


【解决方案1】:

这是使用 python3 的完整方法,并且在 url 中没有指定文件名:

from urllib.request import urlopen
from urllib.request import urlretrieve
import cgi

url = "http://cloud.ine.ru/s/JDbPr6W4QXnXKgo/download"
remotefile = urlopen(url)
blah = remotefile.info()['Content-Disposition']
value, params = cgi.parse_header(blah)
filename = params["filename"]
urlretrieve(url, filename)

结果你应该得到cargo_live_animals_parrot.jpg文件

【讨论】:

  • 这是最佳答案,因为它考虑到服务器可以选择与 URL 完全不同的文件名。
  • 如果我们被困在 python 2.7 上会有什么选择吗?
【解决方案2】:

在澄清问题后编辑...

urlparse.urlsplit 将获取您打开的 url 并将其拆分为其组成部分,然后您可以获取 path 部分并使用最后一个 /-delimited 块作为文件名。

import urllib, urlparse

split = urlparse.urlsplit(url)
filename = "/tmp/" + split.path.split("/")[-1]
urllib.urlretrieve(url, filename)

【讨论】:

  • 问题是这个 url mozilla.com/products/… 不包含文件名。感谢您的回复!
  • 那么当图片网址不包含扩展名时,您是如何解决的呢?
【解决方案3】:

urlopen,它创建了一个类似文件的对象,可以用来读取数据而不用保存到本地文件:

from urllib2 import urlopen

f = urlopen("http://example.com/")
for line in f:
  print len(line)
f.close()

(我不确定这是否是您要求的。)

【讨论】:

  • 不完全是,我刚刚用一个例子编辑了我的问题希望这会有所帮助谢谢你的回复
【解决方案4】:

您指定的 URL 根本不引用文件。这是一个重定向到运行一些 javascript 的网页,这会导致您的网络浏览器下载文件。我的浏览器从相关 URL 被定向到(镜像)的实际地址是:

http://mozilla.mirrors.evolva.ro//firefox/releases/3.6.3/win32/en-US/Firefox%20Setup%203.6.3.exe

我相信网络服务器有两种方式指定下载文件的名称;

  1. URL 路径的最后一段
  2. Content-Disposition 标头,可以指定要使用的其他文件名

对于您要下载的文件,我认为您只需要 URL 的最后一个路径段(但使用文件的实际 URL,而不是选择要使用哪个镜像文件的网页)。但是对于某些下载,您需要从 Content-Disposition 标头中获取要使用的文件名。

【讨论】:

    【解决方案5】:

    我最终得到了

    os.system('wget -P /tmp http://www.mozilla.com/products/download.html?'
              'product=firefox-3.6.3&os=win&lang=en-US')
    

    【讨论】:

    • 可能您应该添加 --trust-server-names 开关,以便 wget 使用 Content-Disposition 提供的名称。
    【解决方案6】:

    快速浏览一下 firefox 页面上的 javascript 就会发现:

    // 2. Build download.mozilla.org URL out of those vars.
    download_url = "http://download.mozilla.org/?product=";
    download_url += product + '&os=' + os + '&lang=' + lang;
    

    所以只需将您的网址更改为:

    http://www.mozilla.com/products/download.html?product=firefox-3.6.3&os=win&lang=en-US
    

    http://download.mozilla.org/?product=firefox-3.6.3&os=win&lang=en-US
    

    所以现在我将检查标题,看看我们真正得到了什么......

    $ curl -I "http://download.mozilla.org/?product=firefox-3.6.3&os=win&lang=en-US"
    HTTP/1.1 302 Found
    Server: Apache
    X-Backend-Server: pp-app-dist09
    Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0, private
    Content-Type: text/html; charset=UTF-8
    Date: Sat, 08 May 2010 21:02:50 GMT
    Location: http://mozilla.mirror.ac.za/firefox/releases/3.6.3/win32/en-US/Firefox Setup 3.6.3.exe
    Pragma: no-cache
    Transfer-Encoding: chunked
    Connection: Keep-Alive
    Set-Cookie: dmo=10.8.84.200.1273352570769772; path=/; expires=Sun, 08-May-11 21:02:50 GMT
    X-Powered-By: PHP/5.1.6
    

    所以这实际上是一个 302 重定向,所以现在使用 Location 标头中的内容作为您的新 url 来获取实际文件。您需要弄清楚如何发出请求并自行阅读标题(抱歉,我没有太多时间)。解析位置标头后,您可以使用正则表达式删除位置的其余部分以获取文件名以将文件保存到:

    >>> location = 'http://mozilla.mirror.ac.za/firefox/releases/3.6.3/win32/en-US/Firefox Setup 3.6.3.exe'
    >>> re.match('^.*/(.*?)$', location).groups()[0]
    'Firefox Setup 3.6.3.exe'
    

    因此,要获得实际的文件名,您需要自己遵循 302。所需的代码我将留给您,但希望这会为您指明正确的方向。

    【讨论】:

      【解决方案7】:

      urlgrabber.urlgrab() 将使用传递给它的 URL 的基本名称作为文件名。请注意,它将忽略 Content-Disposition 标头。

      【讨论】:

        【解决方案8】:
        import shutil
        import urllib.parse
        import urllib.request
        import os
        
        urls = {
            'just_filename' : 'https://github.com/bits4waves/100daysofpractice-dataset/raw/master/requirements.txt',
            'filename_with_params' : 'https://github.com/bits4waves/resonometer/blob/master/sound/violin-A-pluck.wav?raw=true',
            'no_filename' : 'https://download.mozilla.org/?product=firefox-latest-ssl&os=linux64&lang=en-US',
        }
        
        for url in urls.values():
            with urllib.request.urlopen(url) as response:
                parsed_url_path = urllib.parse.urlparse(response.url).path
                filename = os.path.basename(parsed_url_path)
                with open(filename, 'w+b') as f:
                    shutil.copyfileobj(response, f)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-09-22
          • 2013-03-25
          • 1970-01-01
          • 2013-08-22
          • 2014-08-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多