【问题标题】:Building a RESTful Flask API for Scrapy为 Scrapy 构建 RESTful Flask API
【发布时间】:2015-12-19 21:12:27
【问题描述】:

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

以下代码适用于第一个 http 请求,但是在 twisted reactor 停止后,它不会重新启动。我什至可能没有以正确的方式解决这个问题,但我只想在 Heroku 上放置一个 RESTful scrapy API,到目前为止我能想到的就是我所能想到的。

有没有更好的方法来构建这个解决方案?或者我怎样才能让scrape_it 在不停止扭曲反应器(无法再次启动)的情况下返回?

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))

【问题讨论】:

  • 能否提供回溯错误或其他信息?另外为什么不删除这条线d.addBoth(lambda _: reactor.stop()) 并在reactor.run() 之后调用reactor.stop 我假设它出错了,因为当它进入函数时reactor 可能处于启动状态或停止状态。不能保证。
  • 为什么要使用 Scrapy?还有其他方法可以废弃页面
  • @ahmed 我的问题是建立一个异步队列来拉出许多页面,然后爬出这些页面上的链接。你会为此推荐什么?

标签: python heroku flask scrapy twisted


【解决方案1】:

我认为没有一种好方法可以为 Scrapy 创建基于 Flask 的 API。 Flask 不是一个合适的工具,因为它不是基于事件循环的。更糟糕的是,Twisted reactor(Scrapy 使用)can't 在单个线程中被多次启动/停止。

假设 Twisted reactor 没有问题,您可以启动和停止它。它不会让事情变得更好,因为您的 scrape_it 函数可能会阻塞很长一段时间,因此您将需要许多线程/进程。

我认为要走的路是使用 Twisted 或 Tornado 等异步框架创建 API;它将比基于 Flask(或基于 Django)的解决方案更有效,因为 API 将能够在 Scrapy 运行蜘蛛时为请求提供服务。

Scrapy 基于 Twisted,因此使用 twisted.web 或 https://github.com/twisted/klein 会更直接。但是 Tornado 也不难,因为你可以让它使用 Twisted 事件循环。

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

作为 Scrapy-Tornado 集成的示例,检查 Arachnado - here 是有关如何将 Scrapy 的 CrawlerProcess 与 Tornado 的应用程序集成的示例。

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

【讨论】:

    【解决方案2】:

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

    • 客户端向基于 Flask 的服务器发送请求,其中包含要抓取的 URRL,以及在抓取完成时通知客户端的回调 url(此处的客户端是其他 Web 应用)
    • 使用 Celery 在后台运行 Scrapy。蜘蛛会将数据保存到数据库中。
    • 爬虫完成后,后台服务会调用回调url通知客户端。

    【讨论】:

    • 你能帮我理解回调 url 的想法吗?我一直跟着你,但我不知道如何实现它......谢谢顺便说一句,这是一个很棒的想法
    • 这是您的客户端将如何知道爬虫是否完成的方式。仅当您的客户是网站时才有用。如果你不使用回调,你的客户端会定期检查爬虫是否完成。
    猜你喜欢
    • 2015-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-17
    • 2013-11-07
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    相关资源
    最近更新 更多