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