2012-11-23 14 views
15

Używam usługi Scrapy w celu przeszukiwania kilku witryn internetowych, które mogą udostępniać nadmiarowe informacje.Złomowanie - Cicho upuszczanie elementu

Za każdą stronę, którą skrobię, przechowuję URL strony, jej tytuł i kod HTML, w mongoDB. Chcę uniknąć duplikowania w bazie danych, dlatego też wdrażam potok w celu sprawdzenia, czy podobny element jest już przechowywany. W takim przypadku podniosę wyjątek DropItem.

Mój problem polega na tym, że za każdym razem, gdy upuszczam element przez wyjątek, DropItem, Scrapy wyświetli całą zawartość elementu w log (stdout lub plik). Gdy rozpakowuję cały kod HTML każdej skrobanej strony, w przypadku upuszczenia cały kod HTML zostanie wyświetlony w dzienniku.

Jak mogę po cichu upuścić przedmiot bez wyświetlania jego zawartości?

Dziękuję za poświęcony czas!

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 

Odpowiedz

16

Właściwym sposobem na to wydaje się być wdrożenie niestandardowych LogFormatter dla danego projektu, a zmiana poziom rejestrowania upuszczonych przedmiotów.

Przykład:

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, 
     } 

Następnie w pliku ustawień, coś jak:

LOG_FORMATTER = 'apps.crawler.spiders.PoliteLogFormatter' 

miałem pecha właśnie powrocie "None", który spowodował wyjątek w przyszłych rurociągów.

+0

gdzie to się dzieje? Middlewares? Rurociągi? – Xodarap777

+2

@ Xodarap777, Myślę, że plik 'middlewares.py' jest bardziej odpowiedni. Możesz także utworzyć nowy plik, taki jak 'logformatter.py'. Kod z tej odpowiedzi oferuje umieszczenie kodu w pliku z pająkiem. ** Uwaga **: ten kod jest przestarzały, ale odpowiedź @mirosval poniżej zaktualizowała działającą wersję. – kupgov

10

OK, znalazłem odpowiedź, zanim jeszcze opublikuję pytanie. Nadal uważam, że odpowiedź może być cenna dla każdego, kto ma ten sam problem.

Zamiast upuszczenie przedmiotu z DropItem wyjątku, po prostu trzeba zwrócić wartość None:

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

Rozwiązanie to generuje wpis dziennika poziom debugowania zawierającą ciąg „Brak” zamiast wpisu dziennika poziom ostrzegawczy zawierający upuszczony przedmiot. Jest to sprawiedliwe rozwiązanie w '--loglevel = INFO' lub wyżej. Idealnie, 'scrapy.core.scraper.Scraper' powinno umożliwić łatwy dostęp do konfiguracji wyjścia w' _itemproc_finished'. – jah

+0

@jah jest poprawna. Rozwiązanie "jimmytheleaf" jest poprawne w tym przypadku. –

7

W ostatnich wersjach Scrapy zostało to nieco zmienione. I skopiowany kod z @jimmytheleaf i stałe go do pracy z niedawnym 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

Udało się to dla mnie świetne! Sugerowałbym zmianę ''level': logging.INFO,' to' 'level': logging.DEBUG, 'oraz wymienienie' LOG_FORMATTER = '. . .PoliteLogFormatter'' w pliku settings.py – UriCS

Powiązane problemy