在 Scrapy 中使用 Loguru 记录 log

在 Scrapy 中使用 Loguru 记录 log

Loguru 是我最常使用的 log 记录包。它比 Python 原生的 log 语法更简单,开箱即用,功能俱全,还有漂亮的格式和颜色高亮。非常容易上手。自从用了 Loguru 之后,就没有再用过其他包。

使用思路

最近在学习 Scrapy,在 Scrapy 使用 Loguru 记录 log 的思路其实就是使用 Loguru 拦截 log。

  1. 在配置文件 setting.py 中,添加 InterceptHandler() 类,来拦截 Scrapy 产生的标准 log;

  2. 在需要使用的其他组件文件(如 pipelines.py )中,直接使用 self.logger.info('Hello, xishuo.') 来记录。

Loguru 记录实例

Scrapy 官方文档中的教程为例,爬取名人名言网站 Quotes http://quotes.toscrape.com 的第一页。

创建项目

首先创建一个名为 quotes 的 Scrapy 项目。

scrapy startproject quotes

创建爬虫

进入 quotes 文件夹。

cd quotes

创建名为 QuotesSpider 的爬虫。

scrapy genspider QuotesSpider http://quotes.toscrape.com 

修改 QuotesSpider.py 爬虫文件,爬取网站的名言内容、作者和标签。

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('span small::text').get(),
                'tags': quote.css('div.tags α.tag::text').getall(),
            }

        next_page = response.css('li.next α::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)

修改 items.py 文件,创建 items。

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class QuotesItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    text = scrapy.Field()
    author = scrapy.Field()
    tags = scrapy.Field()

修改 pipelines.py 管道文件,将爬取内容储存为 items.jl json 文件。

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html


# useful for handling different item types with α single interface
from itemadapter import ItemAdapter
import json


class QuotesJsonWritePipeline:
    def open_spider(self, spider):
        self.file = open('items.jl', 'w')

    def close_spider(self, spider):
        self.file.close()

    def process_item(self, item, spider):
        line = json.dumps(ItemAdapter(item).asdict()) + "\n"
        self.file.write(line)
        return item

settings.py 中启用 QuotesJsonWritePipeline 管道。

ITEM_PIPELINES = {
    'quotes.pipelines.QuotesJsonWritePipeline': 300,
}

使用 Loguru

修改配置文件 setting.py ,添加 InterceptHandler() 类。

import logging
from loguru import logger

# 添加 InterceptHandler() 类
class InterceptHandler(logging.Handler):
    def emit(self, record):
        # ✓ corresponding Loguru level if it exists
        try:
            level = logger.level(record.levelname).name
        except ValueError:
            level = record.levelno

        # Find caller from where originated the logged message
        frame, depth = logging.currentframe(), 2
        while frame.f_code.co_filename == logging.__file__:
            frame = frame.f_back
            depth += 1

        logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())

# 使用 InterceptHandler() 类
logging.basicConfig(handlers=[InterceptHandler()], level=0)

# 添加
logger.add("quotes_{time}.log", level="ERROR", rotation="10 MB")

现在,Loguru 已经基本配置好,可以拦截 Scrapy 产生的标准日志。

使用 Loguru 添加 log

之前的设置只是将 Scrapy 产生的标准日志拦截下来,那么,当我们想要在其他组件自行添加一些日志时该怎么使用 Loguru 呢?

我们已经使用 logger.add() 函数添加了 Handle,并进行了配置。后续只需要使用 logger 即可添加一条日志,比如在爬虫管件 QuotesSpider.py 中,添加一条 ERROR 日志:

self.logger.error('Something Wrong.')

整个 QuotesSpider.py 文件即:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
    ]

    def parse(self, response):
        self.logger.error("Something Wrong.")
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('span small::text').get(),
                'tags': quote.css('div.tags α.tag::text').getall(),
            }

        next_page = response.css('li.next α::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)
            

运行爬虫

运行爬虫:

scrapy crawl quotes 

可以看见在项目文件下生成了 1 个新的 log 文件和 1 个爬虫结果 items.jl

quotes
	├── items.jl
	├── quotes
	│   ├── __init__.py
	│   ├── __pycache__
	│   ├── items.py
	│   ├── middlewares.py
	│   ├── pipelines.py
	│   ├── settings.py
	│   └── spiders
	├── quotes_2022-02-20_15-45-42_827004.log
	└── scrapy.cfg

打开 quotes_2022-02-20_15-45-42_827004.log 文件,能看到记录的 ERROR 日志。

2022-02-20 15:45:43.620 | ERROR    | quotes.spiders.QuotesSpider:parse:11 - Something Wrong.
2022-02-20 15:45:44.055 | ERROR    | quotes.spiders.QuotesSpider:parse:11 - Something Wrong.
2022-02-20 15:45:44.501 | ERROR    | quotes.spiders.QuotesSpider:parse:11 - Something Wrong.
2022-02-20 15:45:44.963 | ERROR    | quotes.spiders.QuotesSpider:parse:11 - Something Wrong.
2022-02-20 15:45:45.372 | ERROR    | quotes.spiders.QuotesSpider:parse:11 - Something Wrong.
2022-02-20 15:45:45.797 | ERROR    | quotes.spiders.QuotesSpider:parse:11 - Something Wrong.
2022-02-20 15:45:46.219 | ERROR    | quotes.spiders.QuotesSpider:parse:11 - Something Wrong.
2022-02-20 15:45:46.630 | ERROR    | quotes.spiders.QuotesSpider:parse:11 - Something Wrong.
2022-02-20 15:45:47.051 | ERROR    | quotes.spiders.QuotesSpider:parse:11 - Something Wrong.
2022-02-20 15:45:47.457 | ERROR    | quotes.spiders.QuotesSpider:parse:11 - Something Wrong.

上一篇:根据出生日期算出年龄


下一篇:可观测性-LOG