Замена Python scrapy ReactorNotRestartable

Я пытался создать приложение на Python, используя Scrapy, которое имеет следующие функции:

  • rest api (я сделал это с помощью flask) прослушивает все запросы на сканирование/удаление и возвращает ответ после сканирования (часть сканирования достаточно коротка, поэтому соединение может поддерживаться до завершения сканирования.)

Я могу сделать это, используя следующий код:

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

# set up crawler
crawler = Crawler(SpiderClass,settings=get_project_settings())
crawler.signals.connect(add_item, signal=signals.item_passed)

# This is added to make the reactor stop, if I don't use this, the code stucks at reactor.run() line.
crawler.signals.connect(reactor.stop, signal=signals.spider_closed) #@UndefinedVariable 
crawler.crawl(requestParams=requestParams)
# start crawling 
reactor.run() #@UndefinedVariable
return str(items)

Теперь проблема, с которой я сталкиваюсь, связана с остановкой реактора (что кажется мне необходимым, так как я не хочу зацикливаться на reactor.run()). Я не мог принять дальнейший запрос после первого запроса. После завершения первого запроса я получил следующую ошибку:

Traceback (most recent call last):
  File "c:\python27\lib\site-packages\flask\app.py", line 1988, in wsgi_app
    response = self.full_dispatch_request()
  File "c:\python27\lib\site-packages\flask\app.py", line 1641, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "c:\python27\lib\site-packages\flask\app.py", line 1544, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "c:\python27\lib\site-packages\flask\app.py", line 1639, in full_dispatch_request
    rv = self.dispatch_request()
  File "c:\python27\lib\site-packages\flask\app.py", line 1625, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "F:\my_workspace\jobvite\jobvite\com\jobvite\web\RequestListener.py", line 38, in submitForm
    reactor.run() #@UndefinedVariable
  File "c:\python27\lib\site-packages\twisted\internet\base.py", line 1193, in run
    self.startRunning(installSignalHandlers=installSignalHandlers)
  File "c:\python27\lib\site-packages\twisted\internet\base.py", line 1173, in startRunning
    ReactorBase.startRunning(self)
  File "c:\python27\lib\site-packages\twisted\internet\base.py", line 684, in startRunning
    raise error.ReactorNotRestartable()
ReactorNotRestartable

Что очевидно, так как мы не можем перезапустить реактор.

Итак, мои вопросы:

1) Как я могу обеспечить поддержку следующих запросов на сканирование?

2) Есть ли способ перейти на следующую строку после реактора.run(), не останавливая его?


person sagar    schedule 11.09.2016    source источник
comment
Помогает ли этот ответ?   -  person Tiger-222    schedule 15.09.2016
comment
См. ответы на странице stackoverflow.com/ вопросы/32724537/ и stackoverflow.com/questions/36384286/.   -  person Mikhail Korobov    schedule 15.09.2016
comment


Ответы (2)


Вот простое решение вашей проблемы

from flask import Flask
import threading
import subprocess
import sys
app = Flask(__name__) 

class myThread (threading.Thread):
    def __init__(self,target):
        threading.Thread.__init__(self)
        self.target = target
    def run(self):
        start_crawl()

def start_crawl():
    pid = subprocess.Popen([sys.executable, "start_request.py"])
    return


@app.route("/crawler/start") 
def start_req():
    print ":request"
    threadObj = myThread("run_crawler")
    threadObj.start()
    return "Your crawler is in running state" 
if (__name__ == "__main__"): 
    app.run(port = 5000)

В приведенном выше решении я предполагаю, что вы можете запустить свой сканер из командной строки, используя файл команды start_request.py в оболочке/командной строке.

Теперь мы используем многопоточность в python для запуска нового потока для каждого входящего запроса. Теперь вы можете легко запустить свой экземпляр сканера параллельно для каждого обращения. Просто контролируйте количество потоков с помощью threading.activeCount().

person Dinesh Agrawal    schedule 16.09.2016

Я рекомендую вам использовать систему очередей, такую ​​как Rq (для простоты, но есть и другие).
Вы может иметь функцию зоба:

from twisted.internet import reactor
import scrapy
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging
from scrapy.utils.project import get_project_settings

from spiders import MySpider

def runCrawler(url, keys, mode, outside, uniqueid): 

    runner = CrawlerRunner( get_project_settings() )

    d = runner.crawl( MySpider, url=url, param1=value1, ... )

    d.addBoth(lambda _: reactor.stop())
    reactor.run()

Затем в своем основном коде используйте очередь Rq для сбора выполнений сканера:

# other imports
pool = redis.ConnectionPool( host=REDIS_HOST, port=REDIS_PORT, db=your_redis_db_number)
redis_conn =redis.Redis(connection_pool=pool)  

q = Queue('parse', connection=redis_conn)

# urlSet is a list of http:// or https:// like url's
for url in urlSet:
    job = q.enqueue(runCrawler, url, param1, ... , timeout=600 )

Не забудьте запустить рабочий процесс rq, работающий с тем же именем очереди (здесь parse). Например, выполните в терминальной сессии:

rq worker parse
person Evhz    schedule 15.09.2016