加速urlib.urlretrieve

时间:2016-10-21 00:59:46

标签: python urllib

我正在从互联网上下载图片,事实证明,我需要下载大量图片。我正在使用以下代码片段的版本(实际上循环通过我打算下载和下载图片的链接:

import urllib
urllib.urlretrieve(link, filename)

我每15分钟下载大约1000张图片,根据我需要下载的图片数量非常慢。

为了提高效率,我每隔5秒设置一次超时(仍有很多下载时间更长):

import socket
socket.setdefaulttimeout(5)

除了在计算机集群上运行作业以并行化下载之外,有没有办法让图片下载更快/更有效?

2 个答案:

答案 0 :(得分:2)

我的代码非常天真,因为我没有利用多线程。显然需要响应url请求,但在代理服务器响应时计算机无法进行进一步请求。

进行以下调整,您可以将效率提高10倍 - 还有其他方法可以提高效率,包括scrapy等。

要添加多线程,请使用多处理包执行以下操作:

1)将url检索封装在函数中:

import import urllib.request

def geturl(link,i):
try:
    urllib.request.urlretrieve(link, str(i)+".jpg")
except:
    pass

2)然后创建一个包含所有网址的集合以及下载图片所需的名称:

urls = [url1,url2,url3,urln]
names = [i for i in range(0,len(urls))]

3)从多处理包导入Pool类,并使用这样的类创建一个对象(显然,你将在真实程序的代码的第一行包含所有导入):

from multiprocessing.dummy import Pool as ThreadPool
pool = ThreadPool(100)

然后使用pool.starmap()方法并传递函数和函数的参数。

results = pool.starmap(geturl, zip(links, d))

注意:pool.starmap()仅适用于Python 3

答案 1 :(得分:0)

当程序进入I / O等待时,执行暂停,以便内核可以执行与I / O请求相关的低级操作(这称为context switch),并且直到I / O操作完成。

上下文切换是一项非常繁重的操作。它要求我们保存程序的状态(丢失我们在CPU级别的任何类型的缓存)并放弃使用CPU。之后,当我们被允许再次运行时,我们必须花时间在主板上重新初始化我们的程序并准备好恢复(当然,所有这些都发生在幕后)。

另一方面,对于concurrency,,我们通常会运行一个名为“事件循环”的东西来管理在我们的程序中运行的内容以及何时运行。实质上,事件循环只是需要运行的函数列表。列表顶部的函数运行,然后运行下一个等等。

以下显示了一个事件循环的简单示例:

from Queue import Queue
from functools import partial

eventloop = None

class EventLoop(Queue):
    def start(self):
        while True:
            function = self.get()
            function()

def do_hello():
    global eventloop
    print "Hello"
    eventloop.put(do_world)

def do_world():
    global eventloop
    print "world"
    eventloop.put(do_hello)

if __name__ == "__main__":
    eventloop = EventLoop()
    eventloop.put(do_hello)
    eventloop.start()

如果以上内容似乎是您可以使用的内容,并且您还想了解gevent, tornado,AsyncIO,如何帮助解决您的问题,那么请前往您的(大学图书馆,查看High Performance Python by Micha Gorelick and Ian Ozsvald,阅读第181-202页。

注意:上面的代码和文字来自book提到的。