2016-04-27 19 views
-2

「Gray Hat Hackers Handbook」のpilfer-archive-new.pyスクリプトを使用して、インターネットアーカイブからいくつかのファイルをダウンロードします。スクリプトのソースコードは以下の通りである enter image description hereMemoryError:メモリ不足

#-- 
# 
# Name: pilfer-archive-new (attempt #2) 
# Description: Pilfer Archive.org for files to fuzz. Fixed a few threading issues and organized the code better. 
#    It still needs a little bit of work but thread stability is much better. glhf. 
# Author(s): [email protected] 
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
# POSSIBILITY OF SUCH DAMAGE. 
# 
# 
#-- 



#-- 
# 
# Name: pilfer-archive-new (attempt #2) 
# Description: Pilfer Archive.org for files to fuzz. Fixed a few threading issues and organized the code better. 
#    It still needs a little bit of work but thread stability is much better. glhf. 
# Author(s): [email protected] 
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
# POSSIBILITY OF SUCH DAMAGE. 
# 
# 
#-- 



import re, urllib2, socket, json, os, Queue, sys 
from threading import Thread 

searchQueue,downloadQueue = Queue.Queue(),Queue.Queue() 
log=True 
debug=False 

class Obtain: 
    def file_exists(self,path): 
     if (os.path.exists("repo/%s" % (path)) == True): 
      return True 
     else: 
      return False 
    def file_download(self,path): 
     file = path.split("/")[-1] 
     if (Obtain().file_exists(file) != True): 
      data = urllib2.urlopen(path).read() 
      if ("<html" not in data): 
       fp = open("repo/%s" % (file),"w") 
       fp.write(data) 
       fp.close() 
      if (log == True): print "[*] Wrote %s to file system" % (file) 
     return 

class Discover: 
    def find_available(self,term): 
     data = json.loads(urllib2.urlopen("https://archive.org/advancedsearch.php?q=%s&mediatype=&rows=1&page=1&output=json&save=no#raw" % (term)).read()) 
     numFound = data["response"]["numFound"] 
     return numFound 
    def get_titles(self,term,numFound): 
     data = json.loads(urllib2.urlopen("https://archive.org/advancedsearch.php?q=%s&mediatype=&rows=%d&page=1&output=json&save=no#raw" % (term,numFound)).read()) 
     titles = [] 
     for i in xrange(0,numFound-1): 
         try: 
           if (" " in data["response"]["docs"][i]["title"]): 
             titles.append(data["response"]["docs"][i]["title"].replace(" ","-")) 
           else: 
             titles.append(data["response"]["docs"][i]["title"]) 
      except Exception as e: 
           pass 
     return titles[:500] 
    def get_locations(self,titles): 
     urls = [] 
     for title in titles: 
      try: 
       data = json.loads(urllib2.urlopen("https://archive.org/details/%s&output=json&callback=IAE.favorite" % (title)).read()[13:-1]) 
       url = "https://%s%s" % (data["server"],data["dir"]) 
       urls.append(url) 
      except Exception as e: 
       if (debug == True): print "[*] DEBUG -- Function: Discover().get_locations('%s') Exception: %s" % (title,e) 
       pass 
     return urls[:500] 
    def get_file_links(self,urls): 
     files = {} 
     for url in urls: 
      data = urllib2.urlopen(url).read() 
      files[url] = re.findall(r'href=[\'"]?([^\'" >]+)', data, re.UNICODE|re.MULTILINE) 
      files[url] = files[url][1:] 
     return files 


class Queues: 
    def search_worker(self): 
     item = searchQueue.get() 
     if (item != ""): 
      numFound = Discover().find_available(item) 
      if (log == True): print "[*] Found %d entries for %s" % (numFound,item) 
      titles = Discover().get_titles(item,numFound) 
      if (log == True): print "[*] Found %d titles for %s" % (len(titles),item) 
      urls = Discover().get_locations(titles) 
      if (log == True): print "[*] Found %d urls for %s" % (len(urls),item) 
      files = Discover().get_file_links(urls) 
      total = 0 
      for url in files.iterkeys(): 
           if (total >= 500): 
             searchQueue.queue.clear() 
           else: 
             total+=len(files[url]) 
             for file in files[url]: 
               downloadQueue.put("%s/%s" % (url,file)) 
         if (log == True): print "[*] %d files for %s are in the download queue" % (total,item) 
        searchQueue.queue.clear() 
     return 
    def download_worker(self): 
       while True: 
         url = downloadQueue.get() 
         if (url != ""): 
           Obtain().file_download(url) 
         downloadQueue.task_done() 

def main(): 
    #define file types 
    itemz = ['pdf','zip', 'tar', 'doc'] 
    #itemz = ['3g2', '3gp', '3gp2', '3gpp', 'amv', 'asf', 'avi', 'bin', 'divx','drc','dv','f4v','flv','gxf','iso','m1v','m4v','m2t','m2v','mov','mp2','mp2v','mpa'] 
    #drop terms into queue 
    for item in itemz: 
     searchQueue.put(item) 
    #create a bunch of queue threads 
    for i in xrange(0,len(itemz)-1): 
     t1 = Thread(target=Queues().search_worker(),name="search-%d" % (i)).start() 
     t2 = Thread(target=Queues().download_worker(),name="download-%d" % (i)).start() 
    sys.exit() 

if __name__=="__main__": 
    main() 
私は、(例えばPDFファイルが見つかり、一部10万エントリを)たくさんのファイルをダウンロードしようとすると、しかし、私は次のエラーを取得します

私は同様の問題をここで見つけました:Python: Unpredictable memory error when downloading large files 私はread()の各出現をread(4096)に置き換えると、それでも動作しません。

+0

100kファイルをダウンロードするときに何が起こると思いますか? – TigerhawkT3

+0

@ TigerhawkT3:100k、そうですか?それは900万に近いファイルです。 –

+0

@MattiVirkkunen - 私はちょうど質問の中で ".pdfのために見つかった数十万のエントリ"に行きます。 9百万人がさらに多くなるだろう。 – TigerhawkT3

答えて

2

あなたの問題は、の詳細をインターネットアーカイブ上のすべての単一PDFファイルを一度にメモリにロードしようとしていることです。 1つの文字列として。それは多くの情報です。このプログラムは、すべてのファイルをダウンロードすることになっているように見えるので、

まず第一に、あなたものためにそこにすべての単一のファイルをディスクスペースを持っていますか?

第2に、このような大量のファイルを処理する場合は、データをチャンクで処理する必要があります。ご覧のとおり、APIにはrowspageというパラメータがあります。逐次値をpageとして渡すことにより、ページごとに情報ページをダウンロードすることができます。そうすれば、逆シリアル化されたオブジェクト構造だけでなく、巨大なJSON文字列を一度にメモリに格納する必要はありません。

さらに、乱数を入れて何か「修正」すると思ったら、read()のパラメータが何をするのか分かりません。チャンクを読み込んだ場合は、ストリームの終わりを示す空の結果が得られるまで、複数回読む必要があります。

編集:私はJSONをダウンロードしようとしましたが、約1ギガバイトを払い、 "検索エンジンが無効な情報を返したか、応答しなかった"と報告しました。私はアーカイブがあなたのアイデアを好むとは思わない。

+0

よろしくお願いします。Matti Virkkunen。あなたの答えはTIgerhawkT3よりも優れています。 ScrapyやBeautiful Soupを使ってファイルをダウンロードするためのPythonスクリプトを自分自身で書くつもりだと思う。そのようにして、Webスクレイピングも学ぶことができました。 – user3097712