Scrapy - тихо отбрасывать предмет

Я использую Scrapy для сканирования нескольких веб-сайтов, которые могут делиться избыточной информацией.

Для каждой страницы, которую я царапаю, я храню URL страницы, ее заголовок и код html, в mongoDB. Я хочу избежать дублирования в базе данных, таким образом, я реализую конвейер, чтобы проверить, сохранен ли подобный элемент. В этом случае я вызываю исключение DropItem.

Моя проблема заключается в том, что всякий раз, когда я удаляю элемент с помощью raison a DropItem exception, Scrapy отобразит весь контент элемента в журнале (stdout или файл). Когда я извлекаю весь 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

Ответы

Ответ 1

Правильный способ сделать это - это реализовать пользовательский 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'

Мне не повезло, просто вернув "Нет", что вызвало исключения в будущих конвейерах.

Ответ 2

Хорошо, я нашел ответ, прежде чем даже опубликовать вопрос. Я все еще думаю, что ответ может быть ценным для тех, кто имеет ту же проблему.

Вместо того чтобы отбрасывать объект с помощью исключения DropItem, вам просто нужно вернуть значение 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

Ответ 3

В последних версиях 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,
            }
        }