Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为Scrapy构建RESTful烧瓶API_Python_Heroku_Flask_Scrapy_Twisted - Fatal编程技术网

Python 为Scrapy构建RESTful烧瓶API

Python 为Scrapy构建RESTful烧瓶API,python,heroku,flask,scrapy,twisted,Python,Heroku,Flask,Scrapy,Twisted,API应该允许包含用户想要刮取的URL的任意HTTP get请求,然后Flask应该返回刮取的结果 下面的代码适用于第一个http请求,但在twisted reactor停止后,它不会重新启动。我甚至可能没有按照正确的方式来做,但我只想在Heroku上安装一个RESTful scrapy API,到目前为止我所能想到的就是这些 是否有更好的方法来构建此解决方案?或者,我如何允许刮除它返回而不停止扭曲反应器(不能再次启动) 从烧瓶导入烧瓶 导入操作系统 导入系统 导入json 从n_grams.s

API应该允许包含用户想要刮取的URL的任意HTTP get请求,然后Flask应该返回刮取的结果

下面的代码适用于第一个http请求,但在twisted reactor停止后,它不会重新启动。我甚至可能没有按照正确的方式来做,但我只想在Heroku上安装一个RESTful scrapy API,到目前为止我所能想到的就是这些

是否有更好的方法来构建此解决方案?或者,我如何允许
刮除它
返回而不停止扭曲反应器(不能再次启动)

从烧瓶导入烧瓶
导入操作系统
导入系统
导入json
从n_grams.spider.n_gram_spider导入NGramsSpider
#胶状原料药
从twisted.internet导入
进口羊瘙痒
从scrapy.crawler导入CrawlerRunner
从scrapy.xlib.pydispatch导入调度程序
从刮擦进口信号
app=烧瓶(名称)
def刮除(url):
项目=[]
def添加_项目(项目):
items.append(项目)
runner=CrawlerRunner()
d=runner.crawl(NGramsSpider,[url])

d、 addtwith(lambda:reactor.stop())#我认为没有一种好方法可以为Scrapy创建基于烧瓶的API。Flask不是一个合适的工具,因为它不是基于事件循环的。更糟糕的是,Scrapy使用的Twistedreactor在一个线程中可以启动/停止多次

假设扭曲电抗器没有问题,你们可以启动和停止它。它不会让事情变得更好,因为你的
scrape\u It
函数可能会阻塞很长一段时间,因此你需要很多线程/进程

我认为应该使用异步框架(比如Twisted或Tornado)创建API;它将比基于Flask(或基于Django)的解决方案更有效,因为当Scrapy运行spider时,API将能够服务于请求

Scrapy基于Twisted,因此使用Twisted.web或更简单。但龙卷风也不难,因为你们可以使用扭曲事件循环

有一个名为的项目,它的功能与您想要实现的非常类似——它是一个针对Scrapy的HTTP API。ScrapyRT基于Twisted

作为Scrapy Tornado集成检查的一个示例,是一个如何将Scrapy的CrawlerProcess与Tornado的应用程序集成的示例


如果您真的想要基于烧瓶的API,那么在单独的进程中开始爬网和/或使用芹菜之类的队列解决方案是有意义的。这样你就失去了大部分的效率;如果你这样做,你也可以使用requests+BeautifulSoup。

我上周一直在做类似的项目,它是SEO服务API,我的工作流程如下:

  • 客户机向基于Flask的服务器发送一个请求,请求中包含一个要刮取的URRL和一个回调url,以便在刮取完成时通知客户机(这里的客户机是另一个web应用程序)
  • 使用芹菜在后台运行Scrapy。spider会将数据保存到数据库中
  • 当爬行器完成时,backgound服务将通过调用回调url通知客户端

能否提供回溯错误或其他信息?另外,为什么不删除这一行
d.addBoth(lambda:reactor.stop())
并在
reactor.run()之后调用reactor.stop()
我假设它出错了,因为当它进入函数时,reactor可能处于启动状态或停止状态。不能保证。你为什么要用刮痧?还有其他方法可以废弃吗pages@ahmed我的问题是构建一个异步队列来拉取多个页面,然后向外扩展到这些页面上的链接。你有什么建议吗?你能帮我理解回调url的想法吗?我会一直跟踪到这一点,但我不知道如何实现这一点。。。谢谢,顺便说一句,这是一个很棒的想法,这是你的客户如何知道爬虫是否完成的。只有当你的客户是一个网站时,它才有用。如果不使用回调,客户端将定期检查爬虫程序是否已完成。
from flask import Flask
import os
import sys
import json

from n_grams.spiders.n_gram_spider import NGramsSpider

# scrapy api
from twisted.internet import reactor
import scrapy
from scrapy.crawler import CrawlerRunner
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals

app = Flask(__name__)


def scrape_it(url):
    items = []
    def add_item(item):
        items.append(item)

    runner = CrawlerRunner()

    d = runner.crawl(NGramsSpider, [url])
    d.addBoth(lambda _: reactor.stop()) # <<< TROUBLES HERE ???

    dispatcher.connect(add_item, signal=signals.item_passed)

    reactor.run(installSignalHandlers=0) # the script will block here until the crawling is finished


    return items

@app.route('/scrape/<path:url>')
def scrape(url):

    ret = scrape_it(url)

    return json.dumps(ret, ensure_ascii=False, encoding='utf8')


if __name__ == '__main__':
    PORT = os.environ['PORT'] if 'PORT' in os.environ else 8080

    app.run(debug=True, host='0.0.0.0', port=int(PORT))