多处理会减慢我的网页抓取工具的速度?

时间:2013-12-08 18:28:25

标签: python multiprocessing web-crawler

我想下载20个csv文件,其大小全部在一起 - 5MB 这是我的代码的第一个版本:

import os
from bs4 import BeautifulSoup
import urllib.request
import datetime

def get_page(url):
    try:
        return urllib.request.urlopen(url).read()
    except:
        print("[warn] %s" % (url))
        raise

def get_all_links(page):
    soup = BeautifulSoup(page)
    links = []
    for link in soup.find_all('a'):
        url = link.get('href')
        if '.csv' in url:
            return url
    print("[warn] Can't find a link with CSV file!")

def get_csv_file(company):
    link = 'http://finance.yahoo.com/q/hp?s=AAPL+Historical+Prices'
    g = link.find('s=')
    name = link[g + 2:g + 6]
    link = link.replace(name, company)
    urllib.request.urlretrieve(get_all_links(get_page(link)), os.path.join('prices', company + '.csv'))
    print("[info][" + company + "] Download is complete!")

if __name__ == "__main__":
    start = datetime.datetime.now()
    security_list = ["AAPL", "ADBE", "AMD", "AMZN", "CRM", "EXPE", "FB", "GOOG", "GRPN", "INTC", "LNKD", "MCD", "MSFT", "NFLX", "NVDA", "NVTL", "ORCL", "SBUX", "STX"]
    for security in security_list:
        get_csv_file(security)

    end = datetime.datetime.now()
    print('[success] Total time: ' + str(end-start))

此代码会在1.2分钟内将所有大小相同的20个csv文件下载到5MB
然后我尝试使用multiprocessing使其下载速度更快 这是版本2:

if __name__ == "__main__":
    import multiprocessing
    start = datetime.datetime.now()

    security_list = ["AAPL", "ADBE", "AMD", "AMZN", "CRM", "EXPE", "FB", "GOOG", "GRPN", "INTC", "LNKD", "MCD", "MSFT", "NFLX", "NVDA", "NVTL", "ORCL", "SBUX", "STX"]
    for i in range(20):
        p = multiprocessing.Process(target=hP.get_csv_files([index] + security_list), args=(i,))
        p.start()

    end = datetime.datetime.now()
    print('[success] Total time: ' + str(end-start))

但是,不幸的是,版本2会在2.4分钟内将20个csv文件的大小全部下载到5MB

为什么multiprocessing会减慢我的计划?
我做错了什么?
比现在更快下载这些文件的最佳方法是什么?

谢谢?

1 个答案:

答案 0 :(得分:4)

我不知道你试图从你的例子中开始使用Process(我认为你有一些错别字)。我想你想要这样的东西:

processs = []
for security in security_list:
    p = multiprocessing.Process(target=get_csv_file, args=(security,))
    p.start()
    processs.append(p)

for p in processs:
    p.join()

您可以通过这种方式在安全性上进行迭代,为每个安全名称创建一个新进程,并将该进程放在一个列表中。

启动所有进程后,循环遍历它们并等待它们完成,使用join。

使用Pool及其并行映射实现还有一种更简单的方法。

pool = multiprocessing.Pool(processes=5)
pool.map(get_csv_file, security_list)

您创建了一个进程池(如果省略该参数,它将创建一个等于您的处理器数的数字),然后使用map将您的函数应用于列表中的每个元素。游泳池将负责其余的工作。