如何捕获Scrapy请求的特定警告并存入Item的warning字段?
捕获Scrapy TLS证书警告并关联到请求Item
要捕获特定请求的TLS证书警告并存入Item,你需要结合自定义日志过滤器和请求唯一标识来关联警告与请求——因为Scrapy的errback只处理请求级别的错误(比如404、超时等),而警告属于日志系统的输出,并不会触发errback。下面是具体的实现步骤:
1. 给请求添加唯一标识
在发送scrapy.Request时,给每个请求添加一个唯一ID到meta字段中,用来后续关联对应的警告:
import uuid from scrapy import Request # 在爬虫的请求生成方法中 def start_requests(self): target_urls = ["https://example.com"] for url in target_urls: request_id = str(uuid.uuid4()) yield Request( url=url, callback=self.parse, errback=self.errback, meta={ "request_id": request_id, # 用UUID作为请求的唯一标识 "warnings": [] # 用来暂存该请求的警告信息 } )
2. 自定义日志过滤器捕获目标警告
创建一个日志过滤器,专门监听来自scrapy.core.downloader.tls的TLS证书警告,并将警告信息关联到对应的请求:
import logging from scrapy.utils.log import configure_logging class TLSWarningFilter(logging.Filter): def __init__(self, crawler): self.crawler = crawler super().__init__() def filter(self, record): # 只筛选目标警告:来源是scrapy.core.downloader.tls、级别为WARNING、消息匹配证书无效内容 if (record.name == "scrapy.core.downloader.tls" and record.levelno == logging.WARNING and "Remote certificate is not valid for hostname" in record.getMessage()): # Scrapy会自动把当前请求绑定到日志记录的request属性上 request = getattr(record, "request", None) if request and "request_id" in request.meta: # 将警告信息追加到该请求meta的warnings列表中 request.meta["warnings"].append(record.getMessage()) return True # 不拦截日志,让警告正常输出到控制台/日志文件 # 在爬虫的__init__方法中注册这个过滤器 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) configure_logging() # 获取scrapy.core.downloader.tls对应的日志器 tls_logger = logging.getLogger("scrapy.core.downloader.tls") tls_logger.addFilter(TLSWarningFilter(self.crawler))
3. 在回调或errback中存入Item
不管请求成功还是失败,你都可以从request.meta['warnings']中取出捕获到的警告,存入你的Item:
成功回调(parse)示例:
def parse(self, response): item = BaseItem() item['url'] = response.url # 存入警告(如果该请求有TLS证书警告的话) item['warning'] = response.meta.get('warnings', []) yield item
错误回调(errback)示例:
def errback(self, failure): item = BaseItem() item['error'] = failure.type.__name__ item['url'] = failure.request.url # 存入该请求对应的警告信息 item['warning'] = failure.request.meta.get('warnings', []) yield item
关键说明
- Scrapy的日志记录会自动将当前请求绑定到日志的
record.request属性,这是我们能关联警告与请求的核心依据。 - 这个过滤器不会拦截原有日志,只是把警告信息附加到对应请求的meta中,不影响正常的日志输出。
- 如果需要捕获其他类型的警告,只需要修改过滤器中的匹配条件(比如日志来源、消息内容)即可。
内容的提问来源于stack exchange,提问作者Bociek
相关产品推荐
相关产品推荐

