2015-09-22 47 views
6

Interfejs API powinien umożliwiać arbitralne otrzymywanie żądań HTTP zawierających adresy URL, które użytkownik chce zeskrobać, a następnie Flask powinien zwrócić wyniki skasowania.Budowanie API RESTful Flask dla Scrapy

Poniższy kod działa na pierwsze żądanie HTTP, ale po zatrzymaniu twisted reaktor, nie zostanie ponownie uruchomiony. Być może nie podchodzę do tego w odpowiedni sposób, ale chcę po prostu wstawić na Heroku interfejs RESTful scrapy API i wszystko, co do tej pory udało mi się wymyślić, jest wszystkim, co mogę wymyślić.

Czy istnieje lepszy sposób na zaprojektowanie tego rozwiązania? Albo w jaki sposób mogę pozwolić, aby scrape_it powrócił bez zatrzymywania skręconego reaktora (którego nie można ponownie uruchomić)?

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

Czy możesz podać błąd śledzenia lub cokolwiek? Dlaczego nie wystarczy usunąć wiersz 'd.addBoth (lambda _: reactor.stop())' i wywołać reactor.stop po 'reactor.run()' Zakładam, że to błąd, ponieważ po wejściu do Reaktor funkcyjny może być w stanie początkowym lub zatrzymanym. To nie jest gwarantowane. – AdriVelaz

+0

dlaczego chcesz używać Scrapy? tam inne sposoby na zbieranie stron – ahmed

+0

@ahmed Mój problem polega na budowaniu kolejki asynch do przeciągania wielu stron, a następnie spidering do odnośników na tych stronach. Co byś za to polecił? –

Odpowiedz

16

Myślę, że nie ma dobrego sposobu na stworzenie API do Scrapy opartego na Flask. Flask nie jest odpowiednim narzędziem, ponieważ nie opiera się na pętli zdarzeń. Co gorsza, Twisted Reactor (który używa Scrapy) can't może być uruchamiany/zatrzymywany więcej niż jeden raz w jednym wątku.

Załóżmy, że nie ma problemu z Twisted Reactor i możesz go uruchomić i zatrzymać. To nie sprawi, że rzeczy będą znacznie lepsze, ponieważ twoja funkcja scrape_it może blokować przez dłuższy czas, dlatego będziesz potrzebować wielu wątków/procesów.

Myślę, że droga jest stworzenie ram API za pomocą transmisji asynchronicznej jak skręcone lub Tornado; będzie bardziej wydajny niż rozwiązanie oparte na Flask (lub Django), ponieważ interfejs API będzie w stanie obsłużyć żądania, podczas gdy Scrapy działa z pająkiem.

Scrapy jest oparte na Twisted, więc używanie twisted.web lub https://github.com/twisted/klein może być prostsze. Ale Tornado też nie jest trudne, ponieważ możesz użyć pętli zdarzeń Twisted.

Istnieje projekt o nazwie ScrapyRT, który robi coś bardzo podobnego do tego, co chcesz zaimplementować - jest to API HTTP do Scrapy. ScrapyRT jest oparty na Twisted.

Jako przykład sprawdzenia integracji Scrapy-Tornado Arachnado - here jest przykładem, jak zintegrować CrawlerProcess Scrapy z aplikacją Tornado.

Jeśli naprawdę chcesz Kolba API opartego to mogłoby mieć sens, aby rozpocząć indeksuje w oddzielnych procesach i/lub roztworu użycie kolejki jak seler. W ten sposób tracisz większość wydajności Scrapy; jeśli pójdziesz tą drogą, możesz również użyć zgłoszeń + BeautifulSoup.

3

pracuję nad podobnym projektem w zeszłym tygodniu, to serwis SEO API, mój workflow było tak:

  • Klient wysyła żądanie do serwera Kolba opartej o URRL zeskrobać, a zwrotna url powiadomić klienta, gdy złomowanie odbywa (klient tutaj jest inna aplikacja internetowa)
  • Run Scrapy w tle przy użyciu python-daemon. Pająk zapisze dane w bazie danych.
  • Usługa backgound powiadomi klienta, wywołując adres URL wywołania zwrotnego po zakończeniu działania pająka.
+0

Czy możesz pomóc mi zrozumieć pomysł adresu URL wywołania zwrotnego? Podążam za tobą do tego momentu i nie jestem pewien, jak to zaimplementować ... Dzięki, to świetny pomysł. –

+0

W ten sposób twój klient będzie wiedział, czy robot został ukończony. Jest to przydatne tylko wtedy, gdy klient jest witryną internetową. jeśli nie korzystasz z oddzwaniania, Twój klient okresowo sprawdzi, czy robot przebiegł. – ahmed