使用Python并行下载多个文件(或URL)
Python并行下载多个文件(或URL)
在更短的时间内获取更多数据
我们生活在一个大数据的世界中。通常,大数据被组织为一个由多个文件组成的大型数据集。由于下载或获取的负担,获取这些数据通常令人沮丧。幸运的是,只需一点代码,就可以自动化和加速文件下载和获取的过程。
自动化文件下载可以节省大量时间。有几种方法可以使用Python自动化文件下载。下载文件的最简单方法是使用一个简单的Python循环来遍历要下载的URL列表。这种串行方法对于几个小文件来说效果很好,但如果要下载许多文件或大型文件,您将希望使用并行方法来最大化计算资源。
通过并行文件下载程序,您可以更好地利用计算机的资源同时下载多个文件,节省时间。本教程演示了如何在Python中开发一个通用的文件下载函数,并将其应用于使用串行和并行方法下载多个文件。本教程中的代码仅使用Python标准库中可用的模块,因此无需安装任何软件。
导入模块
对于这个示例,我们只需要requests
和multiprocessing
Python模块来并行下载文件。requests
和multiprocessing
模块都可从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和一个文件名。因此,我们将urls
和fns
列表一起压缩为一个元组列表。列表中的每个元组都包含两个元素:一个URL和URL对应的下载文件名。这样,我们可以传递一个包含两个信息的单个参数(元组)。
inputs = zip(urls, fns)
下载URL的函数
现在,我们已经指定了要下载的URL及其关联的文件名,我们需要一个函数来下载这些URL(download_url
)。
我们将向download_url
传递一个参数(arg
)。此参数将是一个可迭代对象(列表或元组),其中第一个元素是要下载的URL(url
),第二个元素是文件名(fn
)。为了可读性,将这些元素分配给变量(url
和fn
)。
现在在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数量。这将确定要并行运行的线程数。
现在使用multiprocessing
的ThreadPool
将inputs
映射到download_url
函数。这里我们使用ThreadPool
的imap_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])
一旦定义了inputs
和download_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。