2014-06-24 214 views
4

有沒有一種很好的方法來使用python下載大量文件?此代碼足以快速下載大約100個左右的文件。但我需要下載300,000個文件。很明顯,他們都是非常小的文件(或者我不會下載他們的300,000 :)),所以真正的瓶頸似乎是這個循環。有人有想法嗎?也許使用MPI或線程?使用python下載很多文件

我只需要與瓶頸住在一起嗎?或者有更快的方法,可能甚至不使用python?

(I包括只是爲了完整性起見代碼的完整開頭)

from __future__ import division 
import pandas as pd 
import numpy as np 
import urllib2 
import os 
import linecache 

#we start with a huge file of urls 

data= pd.read_csv("edgar.csv") 
datatemp2=data[data['form'].str.contains("14A")] 
datatemp3=data[data['form'].str.contains("14C")] 

#data2 is the cut-down file 

data2=datatemp2.append(datatemp3) 
flist=np.array(data2['filename']) 
print len(flist) 
print flist 

###below we have a script to download all of the files in the data2 database 
###here you will need to create a new directory named edgar14A14C in your CWD 

original=os.getcwd().copy() 
os.chdir(str(os.getcwd())+str('/edgar14A14C')) 


for i in xrange(len(flist)): 
    url = "ftp://ftp.sec.gov/"+str(flist[i]) 
    file_name = str(url.split('/')[-1]) 
    u = urllib2.urlopen(url) 
    f = open(file_name, 'wb') 
    f.write(u.read()) 
    f.close() 
    print i 
+1

'multiprocessing'將允許您從其他內核獲得一些加速(您將需要將較大的列表分割爲X個較小的列表,並將一個列表分配給每個核心) –

+2

您是否有任何控制權的服務器?您是否可以在需要時讓服務器壓縮併發送有問題的文件? – dawg

+0

@dawg:我不知道,否則在飛行中抓住他們可能是最好的解決方案。 – sfortney

回答

9

通常的圖案與multiprocessing是創建一個功能job()接受參數並且執行一些潛在的CPU結合的工作。

例子:根據你的代碼

from multiprocessing import Pool 

def job(url): 
    file_name = str(url.split('/')[-1]) 
    u = urllib2.urlopen(url) 
    f = open(file_name, 'wb') 
    f.write(u.read()) 
    f.close() 

pool = Pool() 
urls = ["ftp://ftp.sec.gov/{0:s}".format(f) for f in flist] 
pool.map(job, urls) 

這將做一些事情:

  • 創建一個多池,並設置工人爲你的CPU( s)或CPU內核
  • 創建job()函數的輸入列表。
  • 將輸入列表urls映射到job()並等待所有作業完成。

Python的multiprocessing.Pool.map將負責分散你的輸入跨越no。池中的工人。

我已經爲這方面的工作做了另一個有用的整潔的小傢伙就是用progress這樣的:

from multiprocessing import Pool 


from progress.bar import Bar 


def job(input): 
    # do some work 


pool = Pool() 
inputs = range(100) 
bar = Bar('Processing', max=len(inputs)) 
for i in pool.imap(job, inputs): 
    bar.next() 
bar.finish() 

這給你一個很好的進度條在控制檯上爲你們的工作正在取得進展,所以你有一些想法的進步和eta等

我也發現requests庫非常有用,在這裏處理網絡資源和下載內容的API更好。

+0

是的,這看起來像我正在尋找的。謝謝。我會給這個運行並返回並報告。 順便說一句,有沒有一種方法可以指定我要指定給池的內核數量?我在一臺超級計算機上運行它,我不知道是否會佔用所有內核的好形式:) – sfortney

+0

我試着運行上面的代碼,只是沒有欄,它會引發錯誤。 : urllib2.URLError: 任何想法?看來,urllib2無法打開文件。 – sfortney

+0

回答我自己以上的問題後人,我改變了 pool = Pool()到 pool = Pool(processes = 4)作爲一個測試,現在我沒有得到URL錯誤,但我現在得到酸洗錯誤。 PicklingError:不能pickle :屬性查找__builtin __。函數失敗 – sfortney