2016-01-06 3 views
1

Я использую celerydjango-celery), чтобы позволить пользователю запускать периодические скресты через администратора django. Это часть более крупного проекта, но я отбросил этот вопрос до минимального примера.Сельдерей, Django и Scrapy: импорт ошибок из приложения django

Во-первых, сельдерей/сельдерей бегают демонами. Если вместо этого я запускаю их с celery -A evofrontend worker -B -l info из моего проекта django project, то У меня нет проблем странно.

Когда я бег сельдерей/celerybeat как демоны, однако после этого я получаю странное сообщение об ошибке импорта:

[2016-01-06 03:05:12,292: ERROR/MainProcess] Task evosched.tasks.scrapingTask[e18450ad-4dc3-47a0-b03d-4381a0e65c31] raised unexpected: ImportError('No module named myutils',) 
Traceback (most recent call last): 
    File "/home/lee/Desktop/pyco/evo-scraping-min/venv/local/lib/python2.7/site-packages/celery/app/trace.py", line 240, in trace_task 
    R = retval = fun(*args, **kwargs) 
    File "/home/lee/Desktop/pyco/evo-scraping-min/venv/local/lib/python2.7/site-packages/celery/app/trace.py", line 438, in __protected_call__ 
    return self.run(*args, **kwargs) 
    File "evosched/tasks.py", line 35, in scrapingTask 
    cs = CrawlerScript('TestSpider', scrapy_settings) 
    File "evosched/tasks.py", line 13, in __init__ 
    self.crawler = CrawlerProcess(scrapy_settings) 
    File "/home/lee/Desktop/pyco/evo-scraping-min/venv/local/lib/python2.7/site-packages/scrapy/crawler.py", line 209, in __init__ 
    super(CrawlerProcess, self).__init__(settings) 
    File "/home/lee/Desktop/pyco/evo-scraping-min/venv/local/lib/python2.7/site-packages/scrapy/crawler.py", line 115, in __init__ 
    self.spider_loader = _get_spider_loader(settings) 
    File "/home/lee/Desktop/pyco/evo-scraping-min/venv/local/lib/python2.7/site-packages/scrapy/crawler.py", line 296, in _get_spider_loader 
    return loader_cls.from_settings(settings.frozencopy()) 
    File "/home/lee/Desktop/pyco/evo-scraping-min/venv/local/lib/python2.7/site-packages/scrapy/spiderloader.py", line 30, in from_settings 
    return cls(settings) 
    File "/home/lee/Desktop/pyco/evo-scraping-min/venv/local/lib/python2.7/site-packages/scrapy/spiderloader.py", line 21, in __init__ 
    for module in walk_modules(name): 
    File "/home/lee/Desktop/pyco/evo-scraping-min/venv/local/lib/python2.7/site-packages/scrapy/utils/misc.py", line 71, in walk_modules 
    submod = import_module(fullpath) 
    File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module 
    __import__(name) 
    File "retail/spiders/Retail_spider.py", line 16, in <module> 
ImportError: No module named myutils 

т.е. паука испытывают проблемы импортирования из приложения Джанго проекта, несмотря на добавление соответствующих вещей системного журнал, и делать django.setup().

Я подозреваю, что это может быть вызвано «круговой импорта» во время инициализации, но я не уверен (см here для заметок на ту же ошибку)

сельдерея демон конфигурации

Для Полнота скрипты celeryd и celerybeat конфигурации:

# /etc/default/celeryd 
CELERYD_NODES="worker1" 

CELERY_BIN="/home/lee/Desktop/pyco/evo-scraping-min/venv/bin/celery" 

CELERY_APP="evofrontend" 
DJANGO_SETTINGS_MODULE="evofrontend.settings" 

CELERYD_CHDIR="/home/lee/Desktop/pyco/evo-scraping-min/evofrontend" 

CELERYD_OPTS="--concurrency=1" 

# Workers should run as an unprivileged user. 
CELERYD_USER="lee" 
CELERYD_GROUP="lee" 

CELERY_CREATE_DIRS=1 

и

# /etc/default/celerybeat 
CELERY_BIN="/home/lee/Desktop/pyco/evo-scraping-min/venv/bin/celery" 

CELERY_APP="evofrontend" 
CELERYBEAT_CHDIR="/home/lee/Desktop/pyco/evo-scraping-min/evofrontend/" 

# Django settings module 
export DJANGO_SETTINGS_MODULE="evofrontend.settings" 

В основном они основаны на the generic ones, с настройками Django, которые были выбраны и использовались в корзине для сельдерея в моем виртуальном пространстве, а не в системе.

Я также использую сценарии init.d, которые являются the generic ones.

Структура проекта

Что касается проекта: он живет в /home/lee/Desktop/pyco/evo-scraping-min. Все файлы под ним имеют право собственности lee:lee. реж содержит как Scrapy (ево-ритейл) и проект Django (evofrontend), которые живут под ней и полная структура дерева выглядит как

├── evofrontend 
│   ├── db.sqlite3 
│   ├── evofrontend 
│   │   ├── celery.py 
│   │   ├── __init__.py 
│   │   ├── settings.py 
│   │   ├── urls.py 
│   │   └── wsgi.py 
│   ├── evosched 
│   │   ├── __init__.py 
│   │   ├── myutils.py 
│   │   └── tasks.py 
│   └── manage.py 
└── evo-retail 
    └── retail 
     ├── logs 
     ├── retail 
     │   ├── __init__.py 
     │   ├── settings.py 
     │   └── spiders 
     │    ├── __init__.py 
     │    └── Retail_spider.py 
     └── scrapy.cfg 

проект Django соответствующие файлы

теперь соответствующие файлы : evofrontend/evofrontend/celery.py выглядит

потенциально соответствующих настроек из файла настроек Django, evofrontend/evofrontend/settings.py являются

import os 
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) 

INSTALLED_APPS = (
    ... 
    'djcelery', 
    'evosched', 
) 

# Celery settings 
BROKER_URL = 'amqp://guest:[email protected]//' 
CELERY_ACCEPT_CONTENT = ['json'] 
CELERY_TASK_SERIALIZER = 'json' 
CELERY_RESULT_SERIALIZER = 'json' 
CELERY_TIMEZONE = 'Europe/London' 
CELERYD_MAX_TASKS_PER_CHILD = 1 # Each worker is killed after one task, this prevents issues with reactor not being restartable 
# Use django-celery backend database 
CELERY_RESULT_BACKEND = 'djcelery.backends.database:DatabaseBackend' 
# Set periodic task 
CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler" 

tasks.py в приложении планирования, evosched, выглядит (это просто запускает паука Scrapy с помощью соответствующих настроек после изменения реж)

# evofrontend/evosched/tasks.py 
from __future__ import absolute_import 
from celery import shared_task 
from celery.utils.log import get_task_logger 
logger = get_task_logger(__name__) 
import os 
from scrapy.crawler import CrawlerProcess 
from scrapy.utils.project import get_project_settings 
from django.conf import settings as django_settings 


class CrawlerScript(object): 
    def __init__(self, spider, scrapy_settings): 
     self.crawler = CrawlerProcess(scrapy_settings) 
     self.spider = spider # just a string 

    def run(self, **kwargs): 
     # Pass the kwargs (usually command line args) to the crawler 
     self.crawler.crawl(self.spider, **kwargs) 
     self.crawler.start() 


@shared_task 
def scrapingTask(**kwargs): 

    logger.info("Start scrape...") 

    # scrapy.cfg file here pointing to settings... 
    base_dir = django_settings.BASE_DIR 
    os.chdir(os.path.join(base_dir, '..', 'evo-retail/retail')) 
    scrapy_settings = get_project_settings() 

    # Run crawler 
    cs = CrawlerScript('TestSpider', scrapy_settings) 
    cs.run(**kwargs) 

evofrontend/evosched/myutils.py просто содержит (в данном мин примере) :

# evofrontend/evosched/myutils.py 
SCRAPY_XHR_HEADERS = 'SOMETHING' 

проект Scrapy соответствующие файлы

В комплекте проекта Scrapy файл настроек выглядит

# evo-retail/retail/retail/settings.py 
BOT_NAME = 'retail' 

import os 
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) 

SPIDER_MODULES = ['retail.spiders'] 
NEWSPIDER_MODULE = 'retail.spiders' 

и (в этом мин примере) паук просто

# evo-retail/retail/retail/spiders/Retail_spider.py 
from scrapy.conf import settings as scrapy_settings 
from scrapy.spiders import Spider 
from scrapy.http import Request 
import sys 
import django 
import os 
import posixpath 
SCRAPY_BASE_DIR = scrapy_settings['PROJECT_ROOT'] 
DJANGO_DIR = posixpath.normpath(os.path.join(SCRAPY_BASE_DIR, '../../../', 'evofrontend')) 
sys.path.insert(0, DJANGO_DIR) 
os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'evofrontend.settings') 
django.setup() 
from evosched.myutils import SCRAPY_XHR_HEADERS 

class RetailSpider(Spider): 

    name = "TestSpider" 

    def start_requests(self): 
     print SCRAPY_XHR_HEADERS 
     yield Request(url='http://www.google.com', callback=self.parse) 

    def parse(self, response): 
     print response.url 
     return [] 

EDIT:

я обнаружил через много пробной версии и ошибки, если приложение, которое я пытаюсь импортировать, находится в моей настройке django INSTALLED_APPS, тогда с ошибкой импорта не получается, но если я удалю t он отсюда, то я больше не получаю ошибку импорта (например, удаляя evosched от INSTALLED_APPS, тогда импорт в паук проходит через штраф ...). Очевидно, это не решение, но может быть ключом.

EDIT 2

Я положил печать sys.path непосредственно перед импортом терпит неудачу в пауке, результат был

/home/lee/Desktop/pyco/evo-scraping-min/evofrontend/../evo-retail/retail 
/home/lee/Desktop/pyco/evo-scraping-min/venv/lib/python2.7 
/home/lee/Desktop/pyco/evo-scraping-min/venv/lib/python2.7/plat-x86_64-linux-gnu 
/home/lee/Desktop/pyco/evo-scraping-min/venv/lib/python2.7/lib-tk 
/home/lee/Desktop/pyco/evo-scraping-min/venv/lib/python2.7/lib-old 
/home/lee/Desktop/pyco/evo-scraping-min/venv/lib/python2.7/lib-dynload 
/usr/lib/python2.7 
/usr/lib/python2.7/plat-x86_64-linux-gnu 
/usr/lib/python2.7/lib-tk 
/home/lee/Desktop/pyco/evo-scraping-min/venv/local/lib/python2.7/site-packages 
/home/lee/Desktop/pyco/evo-scraping-min/evofrontend 
/home/lee/Desktop/pyco/evo-scraping-min/evo-retail/retail` 

EDIT 3

Если я import evosched то print dir(evosched), я вижу «задачи», и если я захочу включить такой файл, я также могу увидеть «модели», поэтому импорт из м моделей. Однако я не вижу «myutils». Даже from evosched import myutils терпит неудачу, а также сбой, если оператор помещается в функцию ниже, а не как глобальную (я думал, что это может вызвать круговую проблему импорта ...). Прямой import evosched работает ... возможно import evosched.utils будет работать. Еще не пробовали ...

ответ

0

Кажется, демон сельдерея работает с использованием питона системы, а не двоичного файла python внутри виртуального.Вы должны использовать

# Python interpreter from environment. 
ENV_PYTHON="$CELERYD_CHDIR/env/bin/python" 

Как уже упоминалось here сказать celeryd для запуска с помощью питона внутри virtualenv.

+0

Darn, я думал, что вы что-то сделали с этим, но я добавил его в '/ etc/default/celeryd' после установки' CELERYD_CHDIR', а затем перезапустил все, и я все равно получаю ту же ошибку импорта. Просто дважды проверьте, что это не проблема. Я также сделал «print» Python bin - это% s '% sys.executable' перед проблемной линией импорта и в журналах сельдерея, я вижу, что «Python bin is/home/lee/Desktop/pyco/evo-scraping-min/venv/bin/python « – fpghost

+0

Я обнаружил множество проб и ошибок, что если приложение, которое я пытаюсь импортировать, находится в настройке django« INSTALLED_APPS », тогда он не работает с импортом ошибка, но если я удалю приложение оттуда, то больше не получаю ошибку импорта (например, удаление «evosched» из «INSTALLED_APPS», тогда импорт в паук проходит через штраф ...) – fpghost

+0

Сом кажется, что сельдерей неспособен чтобы найти только конкретное приложение в вашей структуре. Если вы удалите 'evosched',' evosched/tasks.py' никогда не будет использоваться, и поэтому python никогда не попытается импортировать 'retail/spiders/Retail_spider.py'. Но это бесполезно, потому что теперь приложение для скрипирования ничего не делает. – AbdealiJK