同时下载多个页面?

问题描述 投票:0回答:5

我想用 Python 编写一个脚本,可以从数据库中获取 url,并同时下载网页以加快速度,而不是等待每个页面一个接一个地下载。

根据 this thread,Python 不允许这样做,因为称为 Global Interpreter Lock 的东西可以防止多次启动相同的脚本。

在投入时间学习 Twisted 框架之前,我想确保没有更简单的方法来完成我上面需要做的事情。

感谢您的任何提示。

python concurrency
5个回答
9
投票

不用担心GIL。对于你的情况来说,这并不重要。

完成您想要的操作的最简单方法是使用 threading 模块和 ASPN 中的线程池实现之一创建线程池。该池中的每个线程都可以使用 httplib 下载您的网页。

另一种选择是使用 PyCURL 模块——它本身支持并行下载,因此您不必自己实现。


7
投票

GIL 阻止您有效地使用线程进行处理器负载平衡。由于这不是处理器负载平衡,而是防止一个 IO 等待停止整个下载,因此 GIL 在此不相关。 *)

因此您需要做的就是创建多个同时下载的进程。您可以使用线程模块或多处理模块来做到这一点。

*)好吧...除非您有千兆位连接,并且您的问题实际上是您的处理器在网络过载之前就过载了。但这里的情况显然不是这样。


3
投票

urllibthreading(或multiprocessing)包拥有完成“蜘蛛”所需的一切。

您要做的就是从数据库获取网址,并为每个网址启动一个线程或进程 抓取网址。

就像示例(错过数据库网址检索):

#!/usr/bin/env python
import Queue
import threading
import urllib2
import time

hosts = ["http://yahoo.com", "http://google.com", "http://amazon.com",
    "http://ibm.com", "http://apple.com"]

queue = Queue.Queue()

class ThreadUrl(threading.Thread):
    """Threaded Url Grab"""
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.queue = queue

    def run(self):
        while True:
            #grabs host from queue
            host = self.queue.get()

            #grabs urls of hosts and prints first 1024 bytes of page
            url = urllib2.urlopen(host)
            print url.read(1024)

            #signals to queue job is done
            self.queue.task_done()

start = time.time()
def main():

    #spawn a pool of threads, and pass them queue instance
    for i in range(5):
        t = ThreadUrl(queue)
        t.setDaemon(True)
        t.start()

    #populate queue with data
    for host in hosts:
        queue.put(host)

    #wait on the queue until everything has been processed
    queue.join()

main()
print "Elapsed Time: %s" % (time.time() - start)

2
投票

我最近解决了同样的问题。 需要考虑的一件事是,有些人不愿意让他们的服务器陷入困境,并会阻止这样做的 IP 地址。 我听说的标准礼貌是页面请求之间的间隔约为 3 秒,但这是灵活的。

如果您从多个网站下载,您可以按域对 URL 进行分组,并为每个网站创建一个线程。 然后在你的线程中你可以做这样的事情:

for url in urls:
    timer = time.time()
    # ... get your content ...
    # perhaps put content in a queue to be written back to 
    # your database if it doesn't allow concurrent writes.
    while time.time() - timer < 3.0:
        time.sleep(0.5)

有时光是得到你的回复就需要整整 3 秒,你不必担心。

当然,如果您只从一个网站下载,这对您没有任何帮助,但它可能会阻止您被阻止。

我的机器处理大约 200 个线程,然后管理它们的开销减慢了进程。 我最终的速度约为每秒 40-50 页。


0
投票

下载是IO,可以使用非阻塞套接字或扭曲来异步完成。这两种解决方案都比线程或多处理更高效。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.