通过 public HTTP 自动将大文件检索到 Google 云存储

Automatically retrieving large files via public HTTP into Google Cloud Storage

出于天气处理的目的,我希望在 Google 云存储中自动检索每日天气预报数据。

这些文件可在 public HTTP URL (http://dcpc-nwp.meteo.fr/openwis-user-portal/srv/en/main.home) 上找到,但它们非常大(在 30 到 300 兆字节之间)。文件大小是主要问题。

看了之前的Whosebug题目,尝试了两种都不成功的方法:

1/ 首次尝试通过 Google App Engine 中的 urlfetch

    from google.appengine.api import urlfetch

    url = "http://dcpc-nwp.meteo.fr/servic..."
    result = urlfetch.fetch(url)

    [...] # Code to save in a Google Cloud Storage bucket

但我在 urlfetch 行收到以下错误消息:

DeadlineExceededError:等待来自 URL

的 HTTP 响应时超出截止日期

2/ 通过云存储传输服务的第二次尝试

根据文档,可以通过云存储传输服务直接将 HTTP 数据检索到云存储中: https://cloud.google.com/storage/transfer/reference/rest/v1/TransferSpec#httpdata

但是需要下载前文件的大小和md5。此选项不适用于我的情况,因为该网站不提供这些信息。

3/有什么想法吗?

您是否看到任何将 HTTP 上的大文件自动检索到我的 Cloud Storage 存储桶中的解决方案?

目前,Google 的传输服务需要 MD5 和大小;我们知道,在像您这样的情况下,这可能很难处理,但不幸的是,我们今天没有很好的解决方案。

除非您能够通过自己下载文件(暂时)来获得大小和 MD5,否则我认为这是您能做的最好的事情。

3/ 使用 Compute Engine 实例的解决方法

由于无法使用 App Engine 或直接使用 Cloud Storage 从外部 HTTP 检索大文件,因此我使用了一个始终 运行 Compute Engine 实例的解决方法。

此实例定期检查是否有新的天气文件可用,下载它们并将它们上传到云存储桶。

出于可扩展性、维护和成本方面的原因,我宁愿只使用无服务器服务,但希望:

  • 它在新的 f1-micro Compute Engine 实例上运行良好(不需要额外的软件包,如果 运行 24/7,则每月只需 4 美元)
  • 如果实例和存储桶位于同一区域,则从 Compute Engine 到 Google Cloud Storage 的网络流量是免费的(0 美元/月)

可以使用 curl -I 命令轻松快速地检索文件的 md5 和大小,如此 link https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests.
然后可以将存储传输服务配置为使用该信息。

另一种选择是使用无服务器云函数。它可能看起来像下面 Python 中的内容。

import requests

def download_url_file(url):
    try:
        print('[ INFO ] Downloading {}'.format(url))
        req = requests.get(url)
        if req.status_code==200:
            # Download and save to /tmp
            output_filepath = '/tmp/{}'.format(url.split('/')[-1])
            output_filename = '{}'.format(url.split('/')[-1])
            open(output_filepath, 'wb').write(req.content)
            print('[ INFO ] Successfully downloaded to output_filepath: {} & output_filename: {}'.format(output_filepath, output_filename))
            return output_filename
        else:
            print('[ ERROR ] Status Code: {}'.format(req.status_code))
    except Exception as e:
        print('[ ERROR ] {}'.format(e))
    return output_filename