2012-11-23 110 views
15

我正在使用Scrapy來抓取幾個可能共享冗餘信息的網站。Scrapy - 悄悄放下一個項目

對於每一頁我刮,我存儲頁面的URL,它的標題和它的HTML代碼,到mongoDB。 我想避免數據庫中的重複,因此,我實現了一個管道,以檢查是否已經存儲了類似的項目。在這種情況下,我提出了一個DropItem例外。

我的問題是,每當我放棄一個項目時,出現DropItem異常,Scrapy會將項目的全部內容顯示到日誌(標準輸出或文件)中。 當我提取每個抓取頁面的整個HTML代碼時,如果出現丟棄,整個HTML代碼將顯示在日誌中。

我怎樣才能在沒有顯示內容的情況下悄悄地放下一個項目?

謝謝你的時間!

class DatabaseStorage(object): 
    """ Pipeline in charge of database storage. 

    The 'whole' item (with HTML and text) will be stored in mongoDB. 
    """ 

    def __init__(self): 
     self.mongo = MongoConnector().collection 

    def process_item(self, item, spider): 
     """ Method in charge of item valdation and processing. """ 
     if item['html'] and item['title'] and item['url']: 
      # insert item in mongo if not already present 
      if self.mongo.find_one({'title': item['title']}): 
       raise DropItem('Item already in db') 
      else: 
       self.mongo.insert(dict(item)) 
       log.msg("Item %s scraped" % item['title'], 
        level=log.INFO, spider=spider) 
     else: 
      raise DropItem('Missing information on item %s' % (
       'scraped from ' + item.get('url') 
       or item.get('title'))) 
     return item 

回答

16

這樣做的正確方法看起來是實現自定義LogFormatter爲您的項目,並改變丟棄項目的日誌記錄級別。

例子:

from scrapy import log 
from scrapy import logformatter 

class PoliteLogFormatter(logformatter.LogFormatter): 
    def dropped(self, item, exception, response, spider): 
     return { 
      'level': log.DEBUG, 
      'format': logformatter.DROPPEDFMT, 
      'exception': exception, 
      'item': item, 
     } 

然後在你的設置文件,是這樣的:

LOG_FORMATTER = 'apps.crawler.spiders.PoliteLogFormatter' 

我倒黴剛剛返回 「無」,這造成了未來管道例外。

+0

這是去哪裏?中間件?管道? – Xodarap777

+2

@ Xodarap777,我覺得'middlewares.py'文件比較合適。或者你可以創建新的文件,比如'logformatter.py'。這個答案的代碼提供了將代碼放入蜘蛛文件中。 **注意**:此代碼已棄用,但下面的@mirosval的答案已更新工作版本。 – kupgov

10

好吧,我甚至在發佈問題之前找到答案。 我仍然認爲,答案可能對任何有同樣問題的人都有價值。

而是用DropItem異常下降的對​​象,你就必須返回一個無值:

def process_item(self, item, spider): 
    """ Method in charge of item valdation and processing. """ 
    if item['html'] and item['title'] and item['url']: 
     # insert item in mongo if not already present 
     if self.mongo.find_one({'url': item['url']}): 
      return 
     else: 
      self.mongo.insert(dict(item)) 
      log.msg("Item %s scraped" % item['title'], 
       level=log.INFO, spider=spider) 
    else: 
     raise DropItem('Missing information on item %s' % (
      'scraped from ' + item.get('url') 
      or item.get('title'))) 
    return item 
+1

這樣做可以輸出包含字符串「無」,而不是包含下降項的警告級別日誌記錄調試級別的日誌條目。這是'--loglevel = INFO'或以上的公平解決方案。理想情況下,'scrapy.core.scraper.Scraper'應該允許輕鬆訪問'_itemproc_finished'中的輸出配置。 – jah

+0

@jah是正確的。在這種情況下,「jimmytheleaf」的解決方案是正確的。 –

7

在最近的Scrapy版本中,這已經發生了一些變化。我複製從@jimmytheleaf的代碼和固定它與最近Scrapy工作:

import logging 
from scrapy import logformatter 


class PoliteLogFormatter(logformatter.LogFormatter): 
    def dropped(self, item, exception, response, spider): 
     return { 
      'level': logging.INFO, 
      'msg': logformatter.DROPPEDMSG, 
      'args': { 
       'exception': exception, 
       'item': item, 
      } 
     } 
+2

它對我很好!我建議改變''級別':logging.INFO,''level':logging.DEBUG,'並提及'LOG_FORMATTER ='。 012..PoliteLogFormatter''在settings.py文件中 – UriCS