Flask整合Scrapyrt爬虫进程后子进程挂起问题排查
解决Flask与Scrapy整合时爬虫挂起的问题
我碰到过好几个类似的整合场景,核心问题基本都绕不开Twisted和Flask的事件循环冲突——毕竟两者都想抢占主线程,直接硬凑在一起肯定会“打架”。结合你的描述,大概率是这些细节没处理好:
1. 事件循环冲突:同步Flask阻塞了Twisted
Flask默认用Werkzeug的同步服务器,而Scrapy(包括Scrapyrt)依赖Twisted的异步事件循环。如果直接在Flask的主线程里启动爬虫,Twisted的reactor会被Flask的同步逻辑阻塞,导致爬虫进程挂起。
解决方法:用线程隔离爬虫运行
把爬虫的启动逻辑放到单独的线程里,让Flask主线程和Twisted reactor互不干扰:
from flask import Flask from scrapy.crawler import CrawlerRunner from scrapy.utils.log import configure_logging from twisted.internet import reactor, defer import threading app = Flask(__name__) # 导入你的Scrapy爬虫类 from my_scrapy_project.spiders.my_spider import MySpider # 初始化Scrapy配置 configure_logging() runner = CrawlerRunner(settings={ 'USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'ITEM_PIPELINES': {'my_scrapy_project.pipelines.MyPipeline': 300}, # 这里补充你的Scrapy项目其他配置 }) def run_spider(): @defer.inlineCallbacks def crawl(): yield runner.crawl(MySpider) reactor.stop() # 爬虫完成后停止reactor # 禁用信号处理,避免和Flask的信号冲突 reactor.run(installSignalHandlers=False) @app.route('/start-crawl') def trigger_crawl(): # 启动新线程运行爬虫,不阻塞Flask主线程 threading.Thread(target=run_spider, daemon=True).start() return '爬虫已启动,后台运行中!' if __name__ == '__main__': # 关闭Flask调试模式的自动重载,避免重复启动reactor app.run(debug=True, use_reloader=False)
2. 调试模式的自动重载坑
如果开启了Flask的debug=True,默认的自动重载机制会重启进程,导致Twisted reactor被重复启动,直接引发冲突。一定要加上use_reloader=False避免这个问题。
3. 未正确初始化Scrapy环境
单独运行Scrapyrt时,它会自动加载你的Scrapy项目配置(比如settings.py),但整合到Flask里时,你需要手动初始化这些配置——否则爬虫找不到管道、中间件等依赖,会静默挂起。
进阶方案:让Flask和Scrapyrt共享Twisted事件循环
既然Scrapyrt本身就是基于Twisted的Web服务,你可以直接把Flask app挂载到Twisted的reactor上,让两者共享同一个事件循环,彻底避免冲突:
from flask import Flask from scrapyrt.server import Scrapyrt from twisted.web.wsgi import WSGIResource from twisted.web.server import Site from twisted.internet import reactor app = Flask(__name__) # 添加你的Flask业务路由 @app.route('/') def home(): return '这是Flask的主页,访问/crawl可以触发Scrapy爬虫!' # 初始化Scrapyrt,指定你的Scrapy项目配置 scrapyrt = Scrapyrt(settings_module='my_scrapy_project.settings') # 把Flask资源挂载到Twisted站点 flask_resource = WSGIResource(reactor, reactor.getThreadPool(), app) scrapyrt.root_resource.putChild(b'flask', flask_resource) # 启动整合后的Twisted服务 site = Site(scrapyrt.root_resource) reactor.listenTCP(8080, site) print('服务启动:http://localhost:8080/flask(Flask) | http://localhost:8080/crawl(Scrapyrt)') reactor.run()
这样你既可以用Scrapyrt的原生API触发爬虫,也能正常访问Flask的业务路由,完全不需要分开启动两个终端服务。
内容的提问来源于stack exchange,提问作者8-Bit Borges
相关产品推荐
相关产品推荐

