首页 > 解决方案 > Scrapy - 蜘蛛需要很长时间才能被关闭

问题描述

基本上,我有一个名为的文件,我spiders.py在其中配置了所有蜘蛛,然后使用单个爬虫启动所有蜘蛛。这是这个文件的源代码:

from scrapy import spiderloader
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from navigator import *


def main():
  settings = get_project_settings()
  spider_loader = spiderloader.SpiderLoader.from_settings(settings)
  process = CrawlerProcess(settings=settings)
  for spider_name in spider_loader.list():
      process.crawl(spider_name)

  process.start()


if __name__ == '__main__':
  main()

我想要实现的是使用subprocess模块从另一个脚本中触发此蜘蛛,并在执行 5 分钟后关闭所有蜘蛛(仅使用一个SIGTERM)。负责此目标的文件是monitor.py

from time import sleep
import os
import signal
import subprocess

def main():
  spiders_process = subprocess.Popen(["python", "spiders.py"], stdout=subprocess.PIPE,
                                      shell=False, preexec_fn=os.setsid)
  sleep(300)
  os.killpg(spiders_process.pid, signal.SIGTERM)

if __name__ == '__main__':
  main()

当主线程唤醒时,终端会说2018-07-19 21:45:09 [scrapy.crawler] INFO: Received SIGTERM, shutting down gracefully. Send again to force . 但即使在此消息之后,蜘蛛仍会继续抓取网页。我做错了什么?

OBS:可以在spiders.py不阻塞主进程的情况下触发所有蜘蛛吗?

标签: pythonscrapysubprocess

解决方案


我相信当scrapy收到一个 SIGTERM 时,它会尝试通过首先等待完成所有发送/计划的请求来优雅地关闭。您最好的选择是限制数量或并发请求,使其更快完成(CONCURRENT_REQUESTS/CONCURRENT_REQUESTS_PER_DOMAIN默认情况下分别为 16 和 8),或者发送两个 SIGTERM 来指示scrapy 立即执行不干净的退出。

OBS:是否可以在不阻塞主进程的情况下触发 spiders.py 中的所有蜘蛛?

process.start()启动扭曲的反应器(扭曲的主事件循环),这是一个阻塞调用,为了绕过它并在反应器启动后运行更多代码,您可以安排一个函数在循环内运行。本手册的第一个片段应该给你一个想法:https ://twistedmatrix.com/documents/current/core/howto/time.html 。

但是,如果你这样做,你必须确保你安排的代码也必须是非阻塞的,否则当你暂停循环执行太久时,坏事就会开始发生。所以像这样的东西time.sleep()必须用扭曲的等价物重写。


推荐阅读