使用Python并行下载多个文件(或URL)

Python并行下载多个文件(或URL)

在更短的时间内获取更多数据

照片由Wesley Tingey在Unsplash上提供

我们生活在一个大数据的世界中。通常,大数据被组织为一个由多个文件组成的大型数据集。由于下载或获取的负担,获取这些数据通常令人沮丧。幸运的是,只需一点代码,就可以自动化和加速文件下载和获取的过程。

自动化文件下载可以节省大量时间。有几种方法可以使用Python自动化文件下载。下载文件的最简单方法是使用一个简单的Python循环来遍历要下载的URL列表。这种串行方法对于几个小文件来说效果很好,但如果要下载许多文件或大型文件,您将希望使用并行方法来最大化计算资源。

通过并行文件下载程序,您可以更好地利用计算机的资源同时下载多个文件,节省时间。本教程演示了如何在Python中开发一个通用的文件下载函数,并将其应用于使用串行和并行方法下载多个文件。本教程中的代码仅使用Python标准库中可用的模块,因此无需安装任何软件。

导入模块

对于这个示例,我们只需要requestsmultiprocessing Python模块来并行下载文件。requestsmultiprocessing模块都可从Python标准库中获得,因此您无需执行任何安装。

我们还将导入time模块,以便跟踪下载单个文件所需的时间,并比较串行和并行下载程序之间的性能。time模块也是Python标准库的一部分。

import requests import time from multiprocessing import cpu_count from multiprocessing.pool import ThreadPool

定义URL和文件名

我将使用包含美国每日降水数据的gridMET NetCDF文件来演示Python中的并行文件下载。

在这里,我在一个列表中指定了四个文件的URL。在其他应用程序中,您可能会以编程方式生成要下载的文件列表。

urls = ['https://www.northwestknowledge.net/metdata/data/pr_1979.nc', 'https://www.northwestknowledge.net/metdata/data/pr_1980.nc', 'https://www.northwestknowledge.net/metdata/data/pr_1981.nc', 'https://www.northwestknowledge.net/metdata/data/pr_1982.nc']

每个URL必须与其下载位置相关联。在这里,我将文件下载到Windows的“Downloads”目录中。我在一个列表中硬编码了文件名,以简化和透明化。根据您的应用程序,您可能希望编写代码来解析输入URL并将其下载到特定目录。

fns = [r'C:\Users\konrad\Downloads\pr_1979.nc', r'C:\Users\konrad\Downloads\pr_1980.nc', r'C:\Users\konrad\Downloads\pr_1981.nc', r'C:\Users\konrad\Downloads\pr_1982.nc']

多进程要求并行函数只有一个参数(有一些解决办法,但我们不在这里讨论)。要下载一个文件,我们需要传递两个参数,一个URL和一个文件名。因此,我们将urlsfns列表一起压缩为一个元组列表。列表中的每个元组都包含两个元素:一个URL和URL对应的下载文件名。这样,我们可以传递一个包含两个信息的单个参数(元组)。

inputs = zip(urls, fns)

下载URL的函数

现在,我们已经指定了要下载的URL及其关联的文件名,我们需要一个函数来下载这些URL(download_url)。

我们将向download_url传递一个参数(arg)。此参数将是一个可迭代对象(列表或元组),其中第一个元素是要下载的URL(url),第二个元素是文件名(fn)。为了可读性,将这些元素分配给变量(urlfn)。

现在在try语句中创建一个语句,在创建文件后检索并将URL写入文件。当文件写入完成后,返回URL和下载时间。如果发生异常,则打印一条消息。

download_url函数是我们代码的核心。它执行实际的下载和文件创建工作。我们现在可以使用这个函数来串行下载文件(使用循环)和并行下载文件。让我们看看这些例子。

def download_url(args):   t0 = time.time()   url, fn = args[0], args[1]   try:     r = requests.get(url)     with open(fn, 'wb') as f:       f.write(r.content)       return(url, time.time() - t0)   except Exception as e:     print('download_url()中的异常:', e)

使用Python循环下载多个文件

为了将URL列表下载到相应的文件中,通过我们创建的可迭代对象(inputs)循环遍历,将每个元素传递给download_url函数。每次下载完成后,我们将打印下载的URL和下载所花费的时间。

所有URL下载完成后,将打印下载所有URL所花费的总时间。

t0 = time.time() for i in inputs:   result = download_url(i)   print('url:', result[0], 'time:', result[1])   print('总时间:', time.time() - t0)

输出:

url: https://www.northwestknowledge.net/metdata/data/pr_1979.nc time: 16.381176710128784 url: https://www.northwestknowledge.net/metdata/data/pr_1980.nc time: 11.475878953933716 url: https://www.northwestknowledge.net/metdata/data/pr_1981.nc time: 13.059367179870605url: https://www.northwestknowledge.net/metdata/data/pr_1982.nc time: 12.232381582260132 总时间: 53.15849542617798

下载每个文件所需的时间在11到16秒之间。总下载时间略低于一分钟。您的下载时间将根据您的特定网络连接而有所不同。

让我们将这种串行(循环)方法与下面的并行方法进行比较。

使用Python并行下载多个文件

首先,创建一个函数(download_parallel)来处理并行下载。该函数(download_parallel)将接收一个参数,即包含URL和关联文件名的可迭代对象(之前创建的inputs变量)。

接下来,获取可用于处理的CPU数量。这将确定要并行运行的线程数。

现在使用multiprocessingThreadPoolinputs映射到download_url函数。这里我们使用ThreadPoolimap_unordered方法,并将其传递给download_url函数和download_url的输入参数(inputs变量)。imap_unordered方法将同时运行download_url,线程数为指定的数量(即并行下载)。

因此,如果有四个文件和四个线程,所有文件可以同时下载,而不是等待一个下载完成后再开始下一个。这可以节省大量处理时间。

download_parallel函数的最后一部分打印了下载的URL和下载每个URL所需的时间。

def download_parallel(args):   cpus = cpu_count()   results = ThreadPool(cpus - 1).imap_unordered(download_url, args)   for result in results:     print('url:', result[0], 'time (s):', result[1])

一旦定义了inputsdownload_parallel,就可以使用一行代码并行下载文件。

download_parallel(inputs)

输出:

url:https://www.northwestknowledge.net/metdata/data/pr_1980.nc 时间(秒):14.641696214675903 url:https://www.northwestknowledge.net/metdata/data/pr_1981.nc 时间(秒):14.789752960205078 url:https://www.northwestknowledge.net/metdata/data/pr_1979.nc 时间(秒):15.052601337432861 url:https://www.northwestknowledge.net/metdata/data/pr_1982.nc 时间(秒):23.287317752838135 总时间:23.32273244857788

请注意,使用这种方法下载每个文件所需的时间更长。这可能是由于网络速度的变化,或者将下载映射到各自线程所需的开销。尽管单个文件的下载时间较长,但并行方法导致总下载时间减少了50%。

可以看出,并行处理可以大大减少多个文件的处理时间。随着文件数量的增加,使用并行下载方法将节省更多时间。

结论

在开发和分析过程中自动化文件下载可以节省大量时间。正如本教程所示,实施并行下载程序可以极大地减少文件获取时间,尤其是当需要大量文件或大文件时。

最初发表于https://opensourceoptions.com。