日志记录

注意

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")

有快捷方式可以在任何标准5个级别上发出日志消息,还有一个通用的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")

另请参阅

Module logging, HowTo

基础日志教程

Module logging, Loggers

关于日志记录器的进一步文档

从爬虫记录日志

Scrapy 在每个 Spider 实例中提供了一个 logger,可以像这样访问和使用:

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)

该记录器是使用Spider的名称创建的,但您可以使用任何自定义的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_FILELOG_FILE_APPENDFalse,文件将被覆盖(丢弃之前运行的输出,如果有的话)。最后,如果LOG_ENABLEDFalse,将不会有任何可见的日志输出。

LOG_LEVEL 决定了显示的最低严重级别,那些严重级别较低的消息将被过滤掉。它的范围包括在 日志级别 中列出的可能级别。

LOG_FORMATLOG_DATEFORMAT 指定了用于所有消息的格式化字符串。这些字符串可以包含在 logging 的 logrecord 属性文档datetime 的 strftime 和 strptime 指令 中列出的任何占位符。

如果设置了LOG_SHORT_NAMES,则日志将不会显示打印日志的Scrapy组件。默认情况下未设置,因此日志包含负责该日志输出的Scrapy组件。

命令行选项

有一些命令行参数,适用于所有命令,您可以使用这些参数来覆盖一些与日志记录相关的Scrapy设置。

另请参阅

Module logging.handlers

关于可用处理程序的进一步文档

自定义日志格式

可以通过扩展LogFormatter类并为不同的操作设置自定义日志格式,并使LOG_FORMATTER指向您的新类。

class scrapy.logformatter.LogFormatter[源代码]

用于为不同操作生成日志消息的类。

所有方法必须返回一个字典,列出参数levelmsgargs,这些参数将在调用logging.log时用于构建日志消息。

方法输出的字典键:

  • level 是该操作的日志级别,你可以使用来自 python logging library 的那些: logging.DEBUG, logging.INFO, logging.WARNING, logging.ERRORlogging.CRITICAL

  • msg 应该是一个可以包含不同格式化占位符的字符串。 这个字符串,使用提供的 args 进行格式化,将成为该操作的长消息。

  • args 应该是一个元组或字典,包含 msg 的格式化占位符。 最终的日志消息计算为 msg % args

用户可以定义自己的LogFormatter类,如果他们想要自定义每个操作的记录方式,或者如果他们想要完全省略它。为了省略记录一个操作,该方法必须返回None

以下是一个示例,展示了如何创建一个自定义日志格式化程序,以在项目从管道中删除时降低日志消息的严重性级别:

class PoliteLogFormatter(logformatter.LogFormatter):
    def dropped(self, item, exception, response, spider):
        return {
            'level': logging.INFO, # lowering the level from logging.WARNING
            'msg': "Dropped: %(exception)s" + os.linesep + "%(item)s",
            'args': {
                'exception': exception,
                'item': item,
            }
        }
crawled(request: Request, response: Response, spider: Spider) LogFormatterResult[source]

当爬虫找到一个网页时记录一条消息。

download_error(failure: Failure, request: Request, spider: Spider, errmsg: str | None = None) LogFormatterResult[source]

记录来自爬虫的下载错误消息(通常来自引擎)。

版本2.0新增。

dropped(item: Any, exception: BaseException, response: Response | None, spider: Spider) LogFormatterResult[source]

当一个项目在通过项目管道时被丢弃时,记录一条消息。

item_error(item: Any, exception: BaseException, response: Response | None, spider: Spider) LogFormatterResult[source]

当一个项目在通过项目管道时导致错误时,记录一条消息。

版本2.0新增。

scraped(item: Any, response: Response | Failure | None, spider: Spider) LogFormatterResult[source]

当蜘蛛抓取一个项目时记录一条消息。

spider_error(failure: Failure, request: Request, response: Response | Failure, spider: Spider) LogFormatterResult[source]

记录来自蜘蛛的错误消息。

版本2.0新增。

高级定制

因为Scrapy使用了标准库的日志模块,你可以使用标准库日志的所有功能来自定义日志。

例如,假设你正在抓取一个返回许多HTTP 404和500响应的网站,并且你想隐藏所有类似这样的消息:

2016-12-16 22:00:06 [scrapy.spidermiddlewares.httperror] INFO: Ignoring
response <500 https://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)

如果你再次运行这个爬虫,那么来自scrapy.spidermiddlewares.httperror日志记录器的INFO消息将会消失。

你也可以通过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创建的根处理程序上,这是一种方便的方式来过滤项目中不同部分的所有记录器(中间件、爬虫等):

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 模块

scrapy.utils.log.configure_logging(settings: 设置 | dict[Union[bool, float, int, str, NoneType], Any] | None = None, install_root_handler: bool = True) None[source]

初始化Scrapy的日志默认设置。

Parameters:
  • settings (字典, Settings 对象或 None) – 用于创建和配置根日志记录器的处理程序的设置(默认值:None)。

  • install_root_handler (bool) – 是否安装根日志处理程序 (默认值: True)

此函数的功能是:

  • 通过Python标准日志记录路由警告和扭曲日志

  • 将DEBUG和ERROR级别分别分配给Scrapy和Twisted日志记录器

  • 如果LOG_STDOUT设置为True,则将stdout重定向到日志

install_root_handler 为 True(默认值)时,此函数还会根据给定的设置创建根日志记录器的处理程序(参见 日志设置)。您可以使用 settings 参数覆盖默认选项。当 settings 为空或 None 时,将使用默认值。

configure_logging 在使用 Scrapy 命令或 CrawlerProcess 时会自动调用,但在使用 CrawlerRunner 运行自定义脚本时需要显式调用。在这种情况下,虽然不强制要求使用它,但建议使用。

运行自定义脚本时的另一个选项是手动配置日志记录。 为此,您可以使用 logging.basicConfig() 来设置一个基本的根处理程序。

请注意,CrawlerProcess 会自动调用 configure_logging, 因此建议仅在使用 logging.basicConfig() 时与 CrawlerRunner 一起使用。

这是一个关于如何将INFO或更高级别的消息重定向到文件的示例:

import logging

logging.basicConfig(
    filename="log.txt", format="%(levelname)s: %(message)s", level=logging.INFO
)

有关以这种方式使用Scrapy的更多详细信息,请参阅从脚本运行Scrapy