Как в Python Celery сохранять объекты при последовательных вызовах рабочих процессов?

Я использую Celery для автоматизации очистки экрана. Я использую Selenium, чтобы открыть веб-драйвер Chrome, манипулировать страницей, сохранить некоторые данные, а затем перейти к следующей странице в очереди. Проблема в том, что он создает и ломает веб-драйвер для каждой задачи в очереди, что требует очень много времени и ресурсов.

Как сохранить объекты между вызовами? Я кое-что читал о пуле соединений в Celery, но мне непонятно, как именно это работает — где мне создать веб-драйвер — в файле задач или в основном файле очереди? Если второе, то как рабочие узнают, какой веб-драйвер использовать?

Пример:

скреб.py:

for page in list:  
  scrape.delay(str(row['product_id']), str(row['pg_code']))

Задачи.py:

def scrape:
  # do some stuff

person jwoww    schedule 05.11.2013    source источник
comment
Похоже, вам нужно либо настроить несколько рабочих процессов в Celery, либо объединить доступ к веб-драйверу. Вы пробовали использовать eventlet?   -  person Naftuli Kay    schedule 05.11.2013
comment
Рассматривали ли вы вместо этого использование scrapy? Это фреймворк, специально разработанный для парсинга сайтов и лучше подходящий для этой задачи, чем сельдерей.   -  person Wolph    schedule 05.11.2013
comment
Я исследовал скрапирование, но оно не подошло мне наилучшим образом, так как мне нужно было очистить данные после взаимодействия с некоторыми элементами страницы, управляемыми Javascript. Наилучший практический подход scrapy — имитировать вызовы API и очищать их. Мой вариант использования на самом деле является интеграционным тестом, поэтому тестирование вызовов API возможно, но далеко не идеально.   -  person jwoww    schedule 06.11.2013


Ответы (1)


Поскольку каждый рабочий процесс создает экземпляр задачи как одноэлементный, вы можете кэшировать веб-драйвер в объекте задачи. Документация конкретно предлагает этот подход.

http://docs.celeryproject.org/en/latest/userguide/tasks.html#instantiation

person joshua    schedule 05.11.2013
comment
Ничего себе, это работает удивительно хорошо и было очень просто! Жаль, что это было похоронено в документах в области, которую я бы не стал искать. Любые предложения о том, как закрыть драйвер (или, в случае примера с документами, соединение с БД)? Я хотел бы закрыть его, когда работник будет освобожден, но я не видел в документах, как это указать. В целом, это незначительная проблема для моего варианта использования, но она кажется полезной для полноты картины. - person jwoww; 06.11.2013
comment
Да, может быть трудно найти что-то в документах сельдерея. Вы должны быть в состоянии очистить в методе __del__. - person joshua; 06.11.2013
comment
Можете ли вы помочь понять, как правильно использовать del? Вот что я написал без успеха в рамках моего нового класса ChromeTask: def __del__(self): если self._driver не None: return self._driver.close() не закрывается, так как окна Chrome остаются открытыми. Когда автомасштабирование снова увеличивается, я получаю больше новых окон Chrome в дополнение к оставшимся зомби-окнам. - person jwoww; 10.11.2013
comment
Метод __del__ вызывается, когда объект подвергается сборке мусора. Похоже, сборщик мусора не может закрыть экземпляр хрома. Я не буду вдаваться в подробности о том, как работает автомасштабирование, но вы можете каким-то образом подключиться к нему, чтобы выполнить очистку. - person joshua; 11.11.2013