目前我正在研究一个作为 API 运行的蜘蛛项目,因此我对在 HTTP 服务器中运行 scrapy 进行了一些研究。为简单起见,我选择了 Python Klein,基本上遵循以下步骤:
https://github.com/betinacosta/scrapy-klein-tutorial/blob/master/README%5BEN-US%5D.md
目前,我的代码如下所示(Python 3.9):
import json
import os
from klein import Klein
from scrapy import signals
from scrapy.crawler import CrawlerRunner
from twisted.web.server import Site
Site.displayTracebacks = False
class TwistedRunner(CrawlerRunner):
def crawl(self, Spider, *args, **kwargs):
self.items = []
# create spider instance
crawler = self.create_crawler(Spider)
crawler.signals.connect(self.storeItem, signals.item_scraped)
# create deferred crawler-object and register callback
deferred = self._crawl(crawler, *args, **kwargs)
deferred.addCallback(self.getItems)
return deferred
def storeItem(self, item):
self.items.append(item)
def getItems(self, item):
return self.items
def getSpiderResult(output):
"""Format spider result"""
return json.dumps([dict(item) for item in output])
class Router(object):
app = Klein()
scrapeArgument = os.getenv('argument', 'product').encode()
@app.route('/<path:catchall>', methods=['POST', 'GET'])
def catchAll(self, request, catchall):
"""catch-all route"""
request.redirect('/')
@app.route('/', methods=['GET', 'POST'])
def scrape(self, request):
"""Serve request for scrape"""
if self.scrapeArgument not in request.args:
return None
Runner = TwistedRunner()
product=request.args.get(self.scrapeArgument).pop()
a = Runner.crawl(MySpiderCls, product=product)
a.addCallback(getSpiderResult)
return a
if __name__ == '__main__':
Router = Router()
Router.app.run(os.getenv('address', '0.0.0.0'), os.getenv('port', 8080))
这工作正常,正如预期的那样。现在,我很想从这一点上运行多个蜘蛛。文档对此非常清楚:
https://docs.scrapy.org/en/latest/topics/practices.html
但是,当我做类似的事情时
runner = CrawlerRunner()
runner.crawl(MySpider1)
runner.crawl(MySpider2)
d = runner.join()
我看到所有蜘蛛都在运行,但是一旦第一个蜘蛛完成,HTTP 请求就完成了。在这一点上,可能有蜘蛛尚未完成,因此我缺少项目。为了说明这种行为,请参阅一些示例日志:
2021-07-29 21:14:27+0200 [-] save item
2021-07-29 21:14:27+0200 [-] (TCP Port 6024 Closed)
2021-07-29 21:14:27+0200 [-] "127.0.0.1" - - [29/Jul/2021:19:14:27 +0000] "GET /?product=anything HTTP/1.1" 200 3 "-" "curl/7.78.0"
2021-07-29 21:14:27+0200 [-] save item
如您所见,最终保存的项目将永远不会回显给用户,因为请求在上面完成。
有人知道如何从这个设置中运行多个蜘蛛吗?另外,如果根据scrapy-doctrine 有什么我没有做的事情,请告诉我。
谢谢!
答案 0 :(得分:1)
您正在使用 CrawlerRunner
的子类,并且您重载了 crawl()
方法,因此它不会跟踪活动的抓取。您必须添加 self._crawl(...)
,但我不建议这样做,因为您会调用 Scrapy 作者打算私有的函数。
作为学习练习,如果您不更改 TwistedRunner
@app.route('/', methods=['GET', 'POST'])
def scrape(self, request):
ds= set()
Runner = TwistedRunner()
ds.add(Runner.crawl(MySpider1))
ds.add(Runner.crawl(MySpider2))
ds.add(Runner.crawl(MySpider3))
return defer.gatherResults(ds)
由于您的 Runner.crawl()
返回延迟,本示例将它们添加到一个集合中,然后您使用 defer.gatherResults() 等待该集合。
最后,这是你应该做的。不要子类化您自己的 CrawlerRunner
并按原样使用该类。按照 Scrapy 文档中的示例,您将能够使用多个蜘蛛进行抓取。