Логирование

Примечание

scrapy.log устарел вместе с его функциями в пользу явных вызовов стандартного журналирования Python. Продолжайте читать, чтобы узнать больше о новой системе логирования.

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

Журналирование работает «из коробки», и его можно до некоторой степени настроить с помощью параметров Scrapy, перечисленных в Настройки журнала.

Scrapy вызывает scrapy.utils.log.configure_logging() для установки некоторых разумных значений по умолчанию и обработки данных параметров в Настройки журнала при запуске команд, поэтому рекомендуется вызывать его вручную, если вы запускаете Scrapy из сценариев, как приведено в Запуск Scrapy из скрипта.

Уровни журналирования

Встроенное журналирование Python определяет 5 различных уровней, чтобы указать серьезность данного сообщения журнала. Вот стандартные, перечисленные в порядке убывания:

  1. logging.CRITICAL — для критических ошибок (высшая степень серьезности)

  2. logging.ERROR — для штатных ошибок

  3. logging.WARNING — для предупреждающих сообщений

  4. logging.INFO — для информационных сообщений

  5. logging.DEBUG — для отладочных сообщений (наименьшая серьезность)

Как записывать сообщения

Вот быстрый пример того, как регистрировать сообщение с использованием уровня logging.WARNING:

import logging
logging.warning("This is a warning")

Существуют ярлыки для выдачи сообщений журнала на любом из пяти стандартных уровней, а также есть общий метод logging.log, который принимает заданный уровень в качестве аргумента. При необходимости последний пример можно переписать как:

import logging
logging.log(logging.WARNING, "This is a warning")

Кроме того, вы можете создавать различные «логгеры» для инкапсуляции сообщений. (Например, распространенной практикой является создание разных логгеров для каждого модуля). Данные логгеры можно настраивать независимо, и они позволяют создавать иерархические структуры.

В предыдущих примерах за кулисами используется корневой логгер, который является логгером верхнего уровня, на который распространяются все сообщения (если не указано иное). Использование помощников logging — это просто ярлык для явного получения корневого логгера, так что это также эквивалент последних фрагментов:

import logging
logger = logging.getLogger()
logger.warning("This is a warning")

Вы можете использовать другой логгер, просто получив его имя с помощью функции logging.getLogger:

import logging
logger = logging.getLogger('mycustomlogger')
logger.warning("This is a warning")

Наконец, вы можете гарантировать наличие настраиваемого логгера для любого модуля, над которым вы работаете, используя переменную __name__, которая заполняется текущим путём к модулю:

import logging
logger = logging.getLogger(__name__)
logger.warning("This is a warning")

См.также

Модуль logging, HowTo

Базовое руководство по журналированию

Модуль logging, логгеры

Дополнительная документация по логгерам

Журналирование от пауков

Scrapy предоставляет logger в каждом экземпляре Spider, к которому можно получить доступ и использовать таким образом:

import scrapy

class MySpider(scrapy.Spider):

    name = 'myspider'
    start_urls = ['https://scrapy.org']

    def parse(self, response):
        self.logger.info('Parse function called on %s', response.url)

Данный логгер создаётся с использованием имени Паука, но вы можете использовать любой пользовательский логгер Python, который хотите. Например:

import logging
import scrapy

logger = logging.getLogger('mycustomlogger')

class MySpider(scrapy.Spider):

    name = 'myspider'
    start_urls = ['https://scrapy.org']

    def parse(self, response):
        logger.info('Parse function called on %s', response.url)

Конфигурация журналирования

Сами по себе логгеры не управляют отображением отправленных через них сообщений. Для этой задачи к любому экземпляру логгера могут быть прикреплены различные «обработчики», и они будут перенаправлять данные сообщения в соответствующие места назначения, такие как стандартный вывод, файлы, электронные письма и т. д.

По умолчанию Scrapy устанавливает и настраивает обработчик для корневого логгера на основе настроек ниже.

Настройки журнала

Данные параметры можно использовать для настройки ведения журнала:

Первая пара настроек определяет место назначения для сообщений журнала. Если задано LOG_FILE, сообщения, отправленные через корневой логгер, будут перенаправлены в файл с именем LOG_FILE с кодировкой LOG_ENCODING. Если не задано и LOG_ENABLEDTrue, сообщения журнала будут отображаться при стандартной ошибке. Если задано LOG_FILE, а LOG_FILE_APPENDFalse, файл будет перезаписан (без вывода результатов предыдущих запусков, если таковые были). Наконец, если LOG_ENABLED — это False, не будет никаких видимых выходных данных журнала.

LOG_LEVEL определяет минимальный уровень серьезности для отображения, сообщения с более низким уровнем серьезности будут отфильтрованы. Он варьируется от возможных уровней, перечисленных в Уровни журналирования.

LOG_FORMAT и LOG_DATEFORMAT определяют строки форматирования, используемые в качестве макетов для всех сообщений. Данные строки могут содержать любые заполнители, перечисленные в документация атрибутов logrecord журналирования и datetime директивы strftime и strptime соответственно.

Если задано LOG_SHORT_NAMES, то в журналах не будет отображаться компонент Scrapy, который печатает журнал. По умолчанию он не установлен, поэтому журналы содержат компонент Scrapy, отвечающий за данный вывод журнала.

Параметры командной строки

Для всех команд доступны аргументы командной строки, которые можно использовать для переопределения некоторых параметров Scrapy, касающихся ведения журнала.

  • --logfile FILE

    Заменяет LOG_FILE

  • --loglevel/-L LEVEL

    Переопределяет LOG_LEVEL

  • --nolog

    Устанавливает LOG_ENABLED на False

См.также

Модуль logging.handlers

Дополнительная документация по доступным обработчикам

Пользовательские форматы журналов

Пользовательский формат журнала может быть установлен для различных действий, расширив класс LogFormatter и сделав LOG_FORMATTER указателем на ваш новый класс.

Расширенная настройка

Поскольку Scrapy использует модуль ведения журнала stdlib, вы можете настроить ведение журнала, используя все функции ведения журнала stdlib.

Например, предположим, что вы сканируете веб-сайт, который возвращает множество ответов HTTP 404 и 500, и вы хотите скрыть все подобные сообщения:

2016-12-16 22:00:06 [scrapy.spidermiddlewares.httperror] INFO: Ignoring
response <500 http://quotes.toscrape.com/page/1-34/>: HTTP status code
is not handled or not allowed

Первое, что следует отметить, это название логгера — оно указано в скобках: [scrapy.spidermiddlewares.httperror]. Если вы получаете только [scrapy], то для LOG_SHORT_NAMES, скорее всего, будет установлено значение True; устанавливает значение False и повторно запустить сканирование.

Далее мы видим, что сообщение имеет уровень INFO. Чтобы скрыть это, мы должны установить уровень ведения журнала для scrapy.spidermiddlewares.httperror выше, чем INFO; следующий уровень после INFO — WARNING. Это можно сделать, например, в методе паука __init__:

import logging
import scrapy


class MySpider(scrapy.Spider):
    # ...
    def __init__(self, *args, **kwargs):
        logger = logging.getLogger('scrapy.spidermiddlewares.httperror')
        logger.setLevel(logging.WARNING)
        super().__init__(*args, **kwargs)

Если вы снова запустить данный паук, сообщения INFO от логгера scrapy.spidermiddlewares.httperror пропадут.

Вы также можете фильтровать записи журнала по данным LogRecord. Например, вы можете фильтровать записи журнала по содержимому сообщения, используя подстроку или регулярное выражение. Создать подкласс logging.Filter и снабдите его шаблоном регулярного выражения для фильтрации нежелательных сообщений:

import logging
import re

class ContentFilter(logging.Filter):
    def filter(self, record):
        match = re.search(r'\d{3} [Ee]rror, retrying', record.message)
        if match:
            return False

Фильтр уровня проекта может быть прикреплен к корневому обработчику, созданному Scrapy, это удобный способ отфильтровать все логгеры в разных частях проекта (промежуточное ПО, spider и т. д.):

import logging
import scrapy

class MySpider(scrapy.Spider):
    # ...
    def __init__(self, *args, **kwargs):
        for handler in logging.root.handlers:
            handler.addFilter(ContentFilter())

Кроме того, вы можете выбрать конкретный логгер и скрыть его, не затрагивая другие логгеры:

import logging
import scrapy

class MySpider(scrapy.Spider):
    # ...
    def __init__(self, *args, **kwargs):
        logger = logging.getLogger('my_logger')
        logger.addFilter(ContentFilter())

Модуль scrapy.utils.log