我正在构建一个使用Flask和Scrapy的应用程序.访问我的应用程序的根URL时,它会处理一些数据并显示它.另外,如果它还没有运行,我也想(重新)启动我的蜘蛛.由于我的蜘蛛需要大约1.5小时才能完成运行,因此我使用线程将其作为后台进程运行.这是一个最小的例子(你还需要testspiders):
import os from flask import Flask, render_template import threading from twisted.internet import reactor from scrapy import log, signals from scrapy.crawler import Crawler from scrapy.settings import Settings from testspiders.spiders.followall import FollowAllSpider def crawl(): spider = FollowAllSpider(domain='scrapinghub.com') crawler = Crawler(Settings()) crawler.configure() crawler.signals.connect(reactor.stop, signal=signals.spider_closed) crawler.crawl(spider) crawler.start() log.start() reactor.run() app = Flask(__name__) @app.route('/') def main(): run_in_bg = threading.Thread(target=crawl, name='crawler') thread_names = [t.name for t in threading.enumerate() if isinstance(t, threading.Thread)] if 'crawler' not in thread_names: run_in_bg.start() return 'hello world' if __name__ == "__main__": port = int(os.environ.get('PORT', 5000)) app.run(host='0.0.0.0', port=port)
作为旁注,以下几行是我尝试识别我的爬虫程序线程是否仍在运行的临时方法.如果有一种更惯用的方法,我会很感激一些指导.
run_in_bg = threading.Thread(target=crawl, name='crawler') thread_names = [t.name for t in threading.enumerate() if isinstance(t, threading.Thread)] if 'crawler' not in thread_names: run_in_bg.start()
继续讨论问题 - 如果我将上述脚本保存为crawler.py
,运行python crawler.py
并访问localhost:5000
,则会出现以下错误(忽略scrapy的HtmlXPathSelector
弃用错误):
exceptions.ValueError: signal only works in main thread
虽然蜘蛛运行,但它不会停止,因为signals.spider_closed
信号只能在主线程中工作(根据此错误).正如预期的那样,对根URL的后续请求会导致严重错误.
我如何设计我的应用程序以启动我的蜘蛛,如果它还没有爬行,同时立即将控制权返回到我的应用程序(即我不想等待爬虫完成)其他东西?
烧瓶开始长时间运行这样的线程并不是最好的主意.
我建议使用像芹菜或rabbitmq这样的队列系统.您的烧瓶应用程序可以将任务放在您希望在后台执行的队列中,然后立即返回.
然后,您可以让主应用程序之外的工作人员处理这些任务并完成所有操作.