在Scrapy中用Sentry处理所有异常

9 投票
2 回答
2572 浏览
提问于 2025-04-18 16:58

我在做一个项目,使用的是scrapy这个工具,最近想把sentry集成进来。

我试过用 scrapy-sentry,但是根本没用。

我也尝试过用扩展功能来实现,但只有在爬虫的回调函数出错时才有效(而在pipelines.py和items.py里出错就不行)……

from scrapy import signals

from raven import Client


class FailLogger(object):
    client = Client(settings.get('SENTRY_DSN'))

    @classmethod
    def from_crawler(cls, crawler):
        ext = cls()

        crawler.signals.connect(ext.spider_error, signal=signals.spider_error)
        return ext

    def spider_error(self, failure, response, spider):
        try:
            failure.raiseException()
        except:
            self.client.get_ident(self.client.captureException())

有没有办法可以把错误记录到sentry里(无论是在爬虫、items还是pipelines中),就像在Django里那样?

谢谢。

2 个回答

0

这是一篇旧帖子,不过 scrapy-sentry 可能最适合你的需求。

你可以点击这个链接 https://pypi.org/project/scrapy-sentry/ 查看安装指南。

15

这是一篇旧帖子,但我的回答可能对其他人有帮助。Raven被新的库sentry-python替代(在pip中叫做sentry-sdk)。使用这个新库,解决方案比scrapy-sentry简单而完整。这个新方案的基础是scrapy的日志功能是基于标准库的日志模块。

你可以使用以下非常简单的scrapy扩展来捕捉爬虫内部和外部的异常和错误(包括下载中间件、项目中间件等)。

  1. 在你的scrapy项目的extensions.py文件中添加SentryLogging扩展:
import sentry_sdk
from scrapy.exceptions import NotConfigured

class SentryLogging(object):
    """
    Send exceptions and errors to Sentry.
    """

    @classmethod
    def from_crawler(cls, crawler):
        sentry_dsn = crawler.settings.get('SENTRY_DSN', None)
        if sentry_dsn is None:
            raise NotConfigured
        # instantiate the extension object
        ext = cls()
        # instantiate
        sentry_sdk.init(sentry_dsn)
        # return the extension object
        return ext
  1. 在你的settings.py文件中添加以下几行,以便尽早捕捉异常和错误:
# Enable or disable extensions
# See https://doc.scrapy.org/en/latest/topics/extensions.html
EXTENSIONS = {
    'myproject.extensions.SentryLogging': -1, # Load SentryLogging extension before others
}

# Send exceptions to Sentry
# replace SENTRY_DSN by you own DSN
SENTRY_DSN = "XXXXXXXXXX"

确保将SENTRY_DSN替换为你项目的Sentry DSN。

现在,爬虫内部和外部的错误和异常应该会被发送到Sentry。如果你想进一步自定义发送到Sentry的信息,可以根据它的文档编辑sentry_sdk.init()的调用。

撰写回答