Python中Scrapy出现failure时如何执行close_spider
最近用 scrapy,因为网站限制,经常抓到一定数量的时候出现:
2018-01-25 23:12:42 [scrapy.core.scraper] ERROR: Error downloading <GET https://XXX.com/id=139988706>;: [<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>]
IP 被限制了,这时 scrapy 会继续的去尝试抓取剩下的页面,耗费时间
我是想如果发现这种情况,就主动发起 close_spider,结束抓取。
请问大婶们,该在哪里进行配置?
yield scrapy.Request(url,self.parse_item) ——这里可以吗?如何配置?
Python中Scrapy出现failure时如何执行close_spider
关注
在Scrapy中,当爬虫因异常或主动关闭时,可以通过close_spider信号来执行清理操作。如果需要在爬虫失败时执行特定逻辑,可以结合spider_closed信号和爬虫的close_reason属性来判断。
下面是一个完整的示例,演示如何在爬虫失败时执行close_spider逻辑:
import scrapy
from scrapy import signals
from scrapy.exceptions import CloseSpider
class MySpider(scrapy.Spider):
name = 'my_spider'
start_urls = ['http://example.com']
@classmethod
def from_crawler(cls, crawler, *args, **kwargs):
spider = super().from_crawler(crawler, *args, **kwargs)
# 连接spider_closed信号
crawler.signals.connect(spider.spider_closed, signal=signals.spider_closed)
return spider
def parse(self, response):
# 模拟失败情况:例如检查特定条件后主动关闭爬虫
if 'error' in response.text:
# 使用CloseSpider异常来关闭爬虫,并指定原因
raise CloseSpider(reason='检测到错误页面')
def spider_closed(self, spider, reason):
# 检查关闭原因
if reason == 'finished':
print("爬虫正常结束")
else:
print(f"爬虫因失败关闭: {reason}")
# 这里执行失败时的清理或记录操作
self.handle_failure(reason)
def handle_failure(self, reason):
# 自定义失败处理逻辑
# 例如:记录日志、发送通知、清理临时文件等
with open('spider_failure.log', 'a') as f:
f.write(f'Spider closed with reason: {reason}\n')
print(f"已记录失败原因: {reason}")
# 运行爬虫的配置示例(通常写在settings.py或启动脚本中)
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
process = CrawlerProcess(get_project_settings())
process.crawl(MySpider)
process.start()
关键点:
- 连接信号:在
from_crawler方法中连接spider_closed信号到自定义方法。 - 判断关闭原因:
spider_closed方法的reason参数会传递爬虫关闭的原因。常见原因包括:'finished':正常完成'shutdown':手动关闭- 自定义原因字符串(如示例中的
'检测到错误页面')
- 主动触发失败:可以通过抛出
CloseSpider异常并指定原因来主动关闭爬虫。 - 失败处理:在
spider_closed中根据reason执行不同的清理或记录操作。
一句话总结: 通过spider_closed信号和close_reason判断失败状态并执行对应清理。
scrapy.Request()有个参数 errback。比如 scrapy.Request(self.url, self.parse, errback=self.handle_error, dont_filter=True) ,当出现错误时就会调用 handle_error()这个函数,在里面关爬虫就可以了。 具体用法可以去官方文档看 Requests and Responses 一节,也可以通过搜索框搜索 errback。
同意楼上,也可以加一个中间件结束
三楼和四楼正解,我想补充一下另一个角度的解决方案,就是用代理。之前我买过[这家]( https://scrapinghub.com/crawlera)的代理,很好用,与 scrapy 的集成度也高,这是一个简单教程: https://support.scrapinghub.com/support/solutions/articles/22000188399-using-crawlera-with-scrapy,从来没有被封过,缺点是有点贵,最便宜的也要 25 刀一个月。
不过我在网上看到有这样一个 scrapy 的代理中间件: https://github.com/aivarsk/scrapy-proxies,需要自己做一些工作,比如去搜集一些免费的代理等等。我没用过这个中间件,不清楚是否好用,但代理既然是免费的,所以质量嘛。。凭楼主自己权衡了 :)
赞同 5 楼的积极解决问题的方案
收到,谢谢大家。
通过大家的回复,我学习到了,自己对 scrapy 的了解仅仅是点,应该好好学习官方文档形成一个大的知识面。
5 楼的方案之前用过,因为价格原因,大大超出了预算。(我要抓取的数据是千万级反复过滤)


