Я использую celery
(и django-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
будет работать. Еще не пробовали ...
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
Я обнаружил множество проб и ошибок, что если приложение, которое я пытаюсь импортировать, находится в настройке django« INSTALLED_APPS », тогда он не работает с импортом ошибка, но если я удалю приложение оттуда, то больше не получаю ошибку импорта (например, удаление «evosched» из «INSTALLED_APPS», тогда импорт в паук проходит через штраф ...) – fpghost
Сом кажется, что сельдерей неспособен чтобы найти только конкретное приложение в вашей структуре. Если вы удалите 'evosched',' evosched/tasks.py' никогда не будет использоваться, и поэтому python никогда не попытается импортировать 'retail/spiders/Retail_spider.py'. Но это бесполезно, потому что теперь приложение для скрипирования ничего не делает. – AbdealiJK