2017-11-23 20 views
1

私は大量のデータをダウンロードするために治療を使用しています。私は、デフォルトの16同時リクエストを使用します。 ガイドとして、私は共有変数でデータを収集するパイプライン方法process_itemを使用します。そしてclose_spiderにデータをSQLに保存します。 大きすぎるウェブサイトを読み込むと、すべてのシステムメモリが失われます。 この問題を回避するにはどうすればよいですか?治療のベストプラクティス

私はopen_spiderメソッドで準備した1つのDB接続を使用しましたが、すべてprocess_itemで同時に使用することはできませんでした。

答えて

1

パイプラインにスクレイプされたアイテムのリストを作成し、そのリストのサイズがNより大きい場合は、DB関数を呼び出してデータを保存します。私のプロジェクトの100%作業用コードです。 close_spider()を参照してください。スパイダーが閉鎖された時点で、self.itemsにはN個未満のアイテムがある可能性がありますので、self.itemsの残りのデータもスパイダーが閉じられるとDBに保存されます。

from scrapy import signals 

class YourPipeline(object): 

    def __init__(self): 
     self.items = [] 

    def process_item(self, item, spider): 

     self.items.extend([ item ]) 

     if len(self.items) >= 50: 
      self.insert_current_items(spider) 
     return item 

    def insert_current_items(self, spider): 
     for item in self.items: 
      update_query = ', '.join(["`" + key + "` = %s " for key, value in item.iteritems()]) 

      query = "SELECT asin FROM " + spider.tbl_name + " WHERE asin = %s LIMIT 1" 

      spider.cursor.execute(query, (item['asin'])) 

      existing = spider.cursor.fetchone() 

      if spider.cursor.rowcount > 0: 

       query = "UPDATE " + spider.tbl_name + " SET " + update_query + ", date_update = CURRENT_TIMESTAMP WHERE asin = %s" 

       update_query_vals = list(item.values()) 
       update_query_vals.extend([existing['YOUR_UNIQUE_COLUMN']]) 


       try: 
        spider.cursor.execute(query, update_query_vals) 
       except Exception as e: 
        if 'MySQL server has gone away' in str(e): 
         spider.connectDB() 
         spider.cursor.execute(query, update_query_vals) 
        else: 
         raise e 

      else: 

       # This ELSE is likely never to get executed because we are not scraping ASINS from Amazon website, we just import ASINs into DB from another script 
       try: 
        placeholders = ', '.join(['%s'] * len(item)) 
        columns = ', '.join(item.keys()) 
        query = "INSERT INTO %s (%s) VALUES (%s)" % (spider.tbl_name, columns, placeholders) 
        spider.cursor.execute(query, item) 
       except Exception as e: 
        if 'MySQL server has gone away' in str(e): 
         spider.connectDB() 
         spider.cursor.execute(query, item) 
        else: 
         raise e 


     self.items = [] 



    def close_spider(self, spider): 
     self.insert_current_items(spider) 
+0

つまり、多くの同時リクエストもあります。それらのすべてがself.itemsのサイズを1ずつ増やします。そのサイズが50になると、最も近いprocess_itemリフレッシュ・リストが表示されます。しかし、insert_current_itemsがまだ実行中で、他の50項目がself.itemsで収集され、次に他のものが収集される場合はどうなりますか?ですから、同時に動作するinsert_current_itemsメソッドがいくつかありますか? – user2572790

+1

'self.items'はグローバル変数ですので、何度も同時にprocess_itemメソッドが呼び出されても、問題はありません – Umair

+0

はい、spider.cursor.execute(query、update_query_vals)メソッドの問題を意味します。それは同時に何度も働く? – user2572790