Lzh on GitHub

Logging (日志记录)

注意

scrapy.log 及其函数已被弃用,取而代之的是对 Python 标准 logging 的显式调用。请继续阅读以了解新的日志系统。

Scrapy 使用 logging 进行事件日志记录。我们将提供一些简单的示例让您入门,但对于更高级的用例,强烈建议您彻底阅读其文档。

日志记录开箱即用,并且可以通过日志设置中列出的 Scrapy 设置进行一定程度的配置。

当运行命令时,Scrapy 调用 scrapy.utils.log.configure_logging() 来设置一些合理的默认值并处理日志设置中的那些设置,因此如果您像从脚本运行 Scrapy 中描述的那样从脚本运行 Scrapy,建议手动调用它。

Log levels (日志级别)

Python 的内置日志记录定义了 5 个不同的级别来指示给定日志消息的严重性。以下是标准级别,按严重性递减顺序排列:

  • logging.CRITICAL – 用于严重错误(最高严重性)
  • logging.ERROR – 用于常规错误
  • logging.WARNING – 用于警告消息
  • logging.INFO – 用于信息性消息
  • logging.DEBUG – 用于调试消息(最低严重性)

How to log messages (如何记录消息)

这是一个如何使用 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__ 变量来确保为正在处理的任何模块拥有自定义记录器,__name__ 变量会填充当前模块的路径:

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

另请参阅

Logging from Spiders (从爬虫记录日志)

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)

Logging configuration (日志配置)

记录器本身不管理通过它们发送的消息如何显示。对于此任务,可以将不同的“处理程序”附加到任何记录器实例,它们会将这些消息重定向到适当的目标,例如标准输出、文件、电子邮件等。

默认情况下,Scrapy 根据以下设置设置和配置根记录器的处理程序。

Logging settings (日志设置)

这些设置可用于配置日志记录:

  • LOG_FILE
  • LOG_FILE_APPEND
  • LOG_ENABLED
  • LOG_ENCODING
  • LOG_LEVEL
  • LOG_FORMAT
  • LOG_DATEFORMAT
  • LOG_STDOUT
  • LOG_SHORT_NAMES

前几个设置定义了日志消息的目标。如果设置了 LOG_FILE,则通过根记录器发送的消息将重定向到使用 LOG_ENCODING 编码的名为 LOG_FILE 的文件。如果未设置且 LOG_ENABLEDTrue,则日志消息将显示在标准错误输出中。如果设置了 LOG_FILELOG_FILE_APPENDFalse,则该文件将被覆盖(丢弃以前运行的输出,如果有的话)。最后,如果 LOG_ENABLEDFalse,则不会有任何可见的日志输出。

LOG_LEVEL 确定要显示的最低严重级别,具有较低严重性的消息将被过滤掉。它范围包括日志级别中列出的可能级别。

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

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

Command-line options (命令行选项)

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

  • --logfile FILE 覆盖 LOG_FILE
  • --loglevel/-L LEVEL 覆盖 LOG_LEVEL
  • --nologLOG_ENABLED 设置为 False

另请参阅

Custom Log Formats (自定义日志格式)

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

class scrapy.logformatter.LogFormatter[source]

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

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

方法输出的字典键:

  • level 是该操作的日志级别,您可以使用 Python logging 库中的那些:logging.DEBUGlogging.INFOlogging.WARNINGlogging.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, # 将级别从 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 | Failure | None, spider: Spider) -> LogFormatterResult[source]

当项目在通过项目管道时被删除时记录消息。

item_error(item: Any, exception: BaseException, response: Response | Failure | 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 版开始新增。

Advanced customization (高级自定义)

由于 Scrapy 使用 stdlib logging 模块,您可以使用 stdlib logging 的所有功能自定义日志记录。

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

2016-12-16 22:00:06 [scrapy.spidermiddlewares.httperror] INFO: Ignoringresponse <500 https://quotes.toscrape.com/page/1-34/>: HTTP status codeis 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 module (scrapy.utils.log 模块)

scrapy.utils.log.configure_logging(settings: Settings | dict[bool | float | int | str | None, Any] | None = None, install_root_handler: bool = True) -> None[source]

初始化 Scrapy 的日志记录默认值。

参数:

  • settings (dictSettings 对象或 None) – 用于为根记录器创建和配置处理程序的设置(默认值:None)。
  • install_root_handler (bool) – 是否安装根日志处理程序(默认值:True)。

此函数执行以下操作:

  • 通过 Python 标准日志记录路由警告和 Twisted 日志记录
  • 分别为 Scrapy 和 Twisted 记录器分配 DEBUG 和 ERROR 级别
  • 如果 LOG_STDOUT 设置为 True,则将 stdout 路由到日志

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

使用 Scrapy 命令或 CrawlerProcess 时,configure_logging 会自动调用,但在使用 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