内容简介:使用logging管理爬虫
这是崔斯特的第二十四篇原创文章
使用日志记录程序运行状态
日志 模块自2.3版本开始便是 Python 标准库的一部分。它被简洁的描述在 PEP 282 。 众所周知,除了 基础日志指南 部分,该文档并不容易阅读。
日志的两个目的:
- 诊断日志 记录与应用程序操作相关的日志。例如,用户遇到的报错信息, 可通过搜索诊断日志获得上下文信息。
- 审计日志 为商业分析而记录的日志。从审计日志中,可提取用户的交易信息, 并结合其他用户资料构成用户报告或者用来优化商业目标。
… 或者打印?
当需要在命令行应用中显示帮助文档时, 打印
是一个相对于日志更好的选择。 而在其他时候,日志总能优于 打印
,理由如下:
- 日志事件产生的 日志记录 ,包含清晰可用的诊断信息,如文件名称、路径、函数名和行号等。
- 包含日志模块的应用,默认可通过根记录器对应用的日志流进行访问,除非您将日志过滤了。
- 可通过
logging.Logger.setLevel()
方法有选择地记录日志, 或可通过设置logging.Logger.disabled
属性为True
来禁用。
库中的日志
日志指南 中含 库日志配置 的说明。由于是 用户 ,而非库来指明如何响应日志事件, 因此这里有一个值得反复说明的忠告:
注解
强烈建议不要向您的库日志中加入除NullHandler外的其它处理程序。
在库中,声明日志的最佳方式是通过 __name__
全局变量: logging 模块通过点(dot)运算符创建层级排列的日志,因此,用 __name__
可以避免名字冲突。
以下是一个来自 requests 资源 的最佳实践的例子 —— 把它放置在您的 __init__.py
文件中
import logging logging.getLogger(__name__).addHandler(logging.NullHandler())
应用程序中的日志
应用程序开发的权威指南, 应用的12要素 ,也在其中一节描述了 日志的作用 。它特别强调将日志视为事件流, 并将其发送至由应用环境所处理的标准输出中。
配置日志至少有以下三种方式:
- 使用INI格式文件:
- 优点: 使用 logging.config.listen() 函数监听socket,可在运行过程中更新配置
- 缺点: 通过源码控制日志配置较少( 例如 子类化定制的过滤器或记录器)。
- 使用字典或JSON格式文件:
- 优点: 除了可在运行时动态更新,在Python 2.6之后,还可通过 json 模块从其它文件中导入配置。
- 缺点: 很难通过源码控制日志配置。
- 使用源码:
- 优点: 对配置绝对的控制。
- 缺点: 对配置的更改需要对源码进行修改。
通过INI文件进行配置的例子
我们假设文件名为 logging_config.ini
。关于文件格式的更多细节,请参见 日志指南 中的 日志配置 部分。
[loggers] keys=root [handlers] keys=stream_handler [formatters] keys=formatter [logger_root] level=DEBUG handlers=stream_handler [handler_stream_handler] class=StreamHandler level=DEBUG formatter=formatter args=(sys.stderr,) [formatter_formatter] format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s
然后在源码中调用 logging.config.fileConfig()
方法:
import logging from logging.config import fileConfig fileConfig('logging_config.ini') logger = logging.getLogger() logger.debug('often makes a very good meal of %s', 'visiting tourists')
通过字典进行配置的例子
Python 2.7中,您可以使用字典实现详细配置。 PEP 391 包含了一系列字典配置的强制和 非强制的元素。
import logging from logging.config import dictConfig logging_config = dict( version = 1, formatters = { 'f': {'format': '%(asctime)s %(name)-12s %(levelname)-8s %(message)s'} }, handlers = { 'h': {'class': 'logging.StreamHandler', 'formatter': 'f', 'level': logging.DEBUG} }, root = { 'handlers': ['h'], 'level': logging.DEBUG, }, ) dictConfig(logging_config) logger = logging.getLogger() logger.debug('often makes a very good meal of %s', 'visiting tourists')
通过源码直接配置的例子
import logging logger = logging.getLogger() handler = logging.StreamHandler() formatter = logging.Formatter( '%(asctime)s %(name)-12s %(levelname)-8s %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(logging.DEBUG) logger.debug('often makes a very good meal of %s', 'visiting tourists')
官方文档说完了,来看看具体的应用。
默认的日志级别设置为 WARNING
(日志级别等级 CRITICAL
> ERROR
> WARNING
> INFO
> DEBUG
> NOTSET
), 小于 WARNING
级别的日志都不输出, 大于等于 WARNING
级别的日志都会输出。
简单的将日志打印到屏幕
#!/usr/bin/env python # -*- coding: utf8 -*- import logging if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='test.log', filemode='w') console = logging.StreamHandler() console.setLevel(logging.WARNING) formatter=logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') console.setFormatter(formatter) logging.getLogger('').addHandler(console) logging.debug('This is DEBUG') logging.info('This is INFO') logging.warning('This is WARNING')
输出:
root : WARNING This is WARNING
test.log
文件中包含:
Mon, 15 Jan 2018 20:19:45 sfda.py [line:90] DEBUG This is DEBUG Mon, 15 Jan 2018 20:19:45 sfda.py [line:91] INFO This is INFO Mon, 15 Jan 2018 20:19:45 sfda.py [line:92] WARNING This is WARNING
注意:由于日志写入模式设置为 w
,因此重复运行时会将之前的日志清空。
logging.basicConfig 函数各参数:
filename: 指定日志文件名 filemode: 和file函数意义相同,指定日志文件的打开模式,’w’或’a’ format: 指定输出的格式和内容,format可以输出很多有用信息,如上例所示: %(levelno)s: 打印日志级别的数值 %(levelname)s: 打印日志级别名称 %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0] %(filename)s: 打印当前执行程序名 %(funcName)s: 打印日志的当前函数 %(lineno)d: 打印日志的当前行号 %(asctime)s: 打印日志的时间 %(thread)d: 打印线程ID %(threadName)s: 打印线程名称 %(process)d: 打印进程ID %(message)s: 打印日志信息 datefmt: 指定时间格式,同time.strftime() level: 设置日志级别,默认为logging.WARNING stream: 指定将日志的输出流,可以指定输出到sys.stderr, sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略
logging 三大模块: Logger
, Handler
, Format
logger
logger
通过 getLogger
函数得到, 可以在不同的模块中使用不同的 logger
import logging logger = logging.getLogger(__name__) logger.debug('some infomation')
Handler
handler
有多种, 可以记录到 console
, 或者到文件, 文件也可以自动 rotate
, 常用的几个 handler
- StreamHandler 打印到终端
- FileHandler 保存到文件
- RotatingFileHandler 保存到文件, 达到一定大小之后备份文件。
- TimedRotatingFileHandler 定时备份
Format
Formatter
对象设置日志信息最后的规则、结构和内容,默认的时间格式为 %Y-%m-%d %H:%M:%S
Scrapy 与 Logging
Scrapy uses Python’s builtin logging system for event logging. We’ll provide some simple examples to get you started, but for more advanced use-cases it’s strongly suggested to read thoroughly its documentation.
Scrapy使用Python的内置日志记录系统进行事件日志记录。 我们将提供一些简单的示例来帮助您开始,但对于更高级的用例,强烈建议您仔细阅读其文档。
Log levels
- logging.CRITICAL - for critical errors (highest severity)
- logging.ERROR - for regular errors
- logging.WARNING - for warning messages
- logging.INFO - for informational messages
- logging.DEBUG - for debugging messages (lowest severity)
How to log messages
quick example
import logging logger = logging.getLogger() logger.warning("This is a warning")
Logging from Spiders
该记录器是使用Spider的名称创建的,但是您可以使用任何您想要的自定义Python记录器。 例如:
import logging import scrapy logger = logging.getLogger('mycustomlogger') class MySpider(scrapy.Spider): name = 'myspider' start_urls = ['https://scrapinghub.com'] def parse(self, response): logger.info('Parse function called on %s', response.url)
在middlewares中应用
import logging logger = logging.getLogger(__name__) class ProxyMiddleware(object): def process_request(self, request, spider): request.meta['proxy'] = random.choice(proxy_list) spider.logger.info('get ip: {}'.format(request.meta['proxy']))
使用Scrapy记录爬取日志
在 settings.py
中修改:
LOG_STDOUT = True LOG_FILE = 'scrapy_log.txt'
然后开始运行爬虫,日志不会打印,会保存到 scrapy_log.txt
文件中。
使用errbacks在请求处理中捕获异常
请求的errback是在处理异常时被调用的函数。
它接收Twisted Failure实例作为第一个参数,可用于跟踪连接建立超时,DNS错误等。
这里有一个爬虫日志记录所有的错误和捕捉一些特定的错误,例子:
import scrapy from scrapy.spidermiddlewares.httperror import HttpError from twisted.internet.error import DNSLookupError from twisted.internet.error import TimeoutError, TCPTimedOutError class ErrbackSpider(scrapy.Spider): name = "errback_example" start_urls = [ "http://www.httpbin.org/", # HTTP 200 expected "http://www.httpbin.org/status/404", # Not found error "http://www.httpbin.org/status/500", # server issue "http://www.httpbin.org:12345/", # non-responding host, timeout expected "http://www.httphttpbinbin.org/", # DNS error expected ] def start_requests(self): for u in self.start_urls: yield scrapy.Request(u, callback=self.parse_httpbin, errback=self.errback_httpbin, dont_filter=True) def parse_httpbin(self, response): self.logger.info('Got successful response from {}'.format(response.url)) # do something useful here... def errback_httpbin(self, failure): # log all failures self.logger.error(repr(failure)) # in case you want to do something special for some errors, # you may need the failure's type: if failure.check(HttpError): # these exceptions come from HttpError spider middleware # you can get the non-200 response response = failure.value.response self.logger.error('HttpError on %s', response.url) elif failure.check(DNSLookupError): # this is the original request request = failure.request self.logger.error('DNSLookupError on %s', request.url) elif failure.check(TimeoutError, TCPTimedOutError): request = failure.request self.logger.error('TimeoutError on %s', request.url)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Python爬虫之使用celery加速爬虫
- python网络爬虫(14)使用Scrapy搭建爬虫框架
- 11、web爬虫讲解2—Scrapy框架爬虫—Scrapy使用
- Nodejs爬虫,使用cheerio+request+phantomjs实现超简单爬虫
- 如何使用Nodejs爬虫看漫画
- Go语言使用chromedp爬虫
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
高质量程序设计艺术
斯皮内利斯 / 韩东海 / 人民邮电出版社 / 2008-1 / 55.00元
在本书中,作者回归技术层面。从Apache web server、BSD版本的Unix system、ArgoUMl、ACE网络编程库等著名开源软件中选取了大量真实C、C++和java语言源代码,直观而深刻的阐述了代码中可能存在的各种质量问题,涉及可靠性、安全性、时间性和空间性、可移植性、可维护性以及浮点运算等方面,很多内容都市独辟蹊径,发前人所未发。正因如此,本书继作者的《代码阅读》之后在获Jo......一起来看看 《高质量程序设计艺术》 这本书的介绍吧!