Подтвердить что ты не робот

Доступ к моделям Django с помощью scrapy: определение пути к проекту Django

Я очень новичок в Python и Django. В настоящее время я изучаю использование Scrapy для очистки сайтов и сохранения данных в базе данных Django. Моя цель - запустить паука на основе домена, заданного пользователем.

Я написал паук, который извлекает нужные мне данные и сохраняет их правильно в json файле при вызове

scrapy crawl spider -o items.json -t json

Как описано в уроке .

Теперь моя цель - заставить паук успешно сохранить данные в базе данных Django, а затем работать над тем, чтобы запустить паук на основе пользовательского ввода.

Я знаю, что по этой теме существуют разные должности, такие как: ссылка 1 ссылка 2 ссылка 3

Но, потратив более 8 часов на попытку заставить это работать, я предполагаю, что я не единственный, кто все еще сталкивается с проблемами с этим. Поэтому я попытаюсь собрать все знания, которые я получил до сих пор в этом посте, а также, надеюсь, опубликовать рабочее решение на более позднем этапе. Из-за этого этот пост довольно длинный.

Мне кажется, что есть два разных решения для сохранения данных в базу данных Django от Scrapy. Один из них - использовать DjangoItem, другой - импортировать модели напрямую (как сделано здесь).

Я не совсем понимаю преимущества и недостатки этих двух, но похоже, что разница просто в том, что использование DjangoItem просто более удобно и короче.

Что я сделал:

Я добавил:

def setup_django_env(path):
    import imp, os
    from django.core.management import setup_environ

    f, filename, desc = imp.find_module('settings', [path])
    project = imp.load_module('settings', f, filename, desc)       

    setup_environ(project)

setup_django_env('/Users/Anders/DjangoTraining/wsgi/')

Ошибка, которую я получаю:

ImportError: No module named settings

Я думаю, что я неправильно определяю путь к моему проекту Django?

Я также пробовал следующее:

setup_django_env('../../') 

Как правильно определить путь к моему проекту Django? (если это проблема)

4b9b3361

Ответ 1

Я думаю, что основное заблуждение - путь пакета к пути модуля настроек. Чтобы использовать модели django из внешнего script, вам нужно установить DJANGO_SETTINGS_MODULE. Затем этот модуль должен быть импортируемым (т.е. Если путь настроек myproject.settings, то инструкция from myproject import settings должна работать в оболочке python).

Поскольку большинство проектов в django создаются в пути вне значения по умолчанию PYTHONPATH, вы должны добавить путь к переменной среды PYTHONPATH.

Вот пошаговое руководство по созданию полностью работающей (и минимальной) интеграции моделей Django в проект Scrapy:

Примечание.. Эти инструкции работают в дату последнего редактирования. Если это не сработает для вас, добавьте комментарий и опишите свои проблемы и варианты scrapy/django.

  • Проекты будут созданы в каталоге /home/rolando/projects.

  • Запустите проект django.

    $ cd ~/projects
    $ django-admin startproject myweb
    $ cd myweb
    $ ./manage.py startapp myapp
    
  • Создайте модель в myapp/models.py.

    from django.db import models
    
    
    class Person(models.Model):
        name = models.CharField(max_length=32)
    
  • Добавьте myapp в INSTALLED_APPS в myweb/settings.py.

    # at the end of settings.py
    INSTALLED_APPS += ('myapp',)
    
  • Задайте настройки моего db в myweb/settings.py.

    # at the end of settings.py
    DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'
    DATABASES['default']['NAME'] = '/tmp/myweb.db'
    
  • Создайте базу данных.

    $ ./manage.py syncdb --noinput
    Creating tables ...
    Installing custom SQL ...
    Installing indexes ...
    Installed 0 object(s) from 0 fixture(s)
    
  • Создайте проект scrapy.

    $ cd ~/projects
    $ scrapy startproject mybot
    $ cd mybot
    
  • Создайте элемент в mybot/items.py.

Примечание: В новых версиях Scrapy вам необходимо установить scrapy_djangoitem и использовать from scrapy_djangoitem import DjangoItem.

    from scrapy.contrib.djangoitem import DjangoItem
    from scrapy.item import Field

    from myapp.models import Person


    class PersonItem(DjangoItem):
        # fields for this item are automatically created from the django model
        django_model = Person

Окончательная структура каталогов такова:

/home/rolando/projects
├── mybot
│   ├── mybot
│   │   ├── __init__.py
│   │   ├── items.py
│   │   ├── pipelines.py
│   │   ├── settings.py
│   │   └── spiders
│   │       └── __init__.py
│   └── scrapy.cfg
└── myweb
    ├── manage.py
    ├── myapp
    │   ├── __init__.py
    │   ├── models.py
    │   ├── tests.py
    │   └── views.py
    └── myweb
        ├── __init__.py
        ├── settings.py
        ├── urls.py
        └── wsgi.py

Отсюда, в основном, мы делаем код, необходимый для использования моделей django в проекте scrapy. Мы можем проверить его сразу с помощью команды scrapy shell, но знать о необходимых переменных среды:

$ cd ~/projects/mybot
$ PYTHONPATH=~/projects/myweb DJANGO_SETTINGS_MODULE=myweb.settings scrapy shell

# ... scrapy banner, debug messages, python banner, etc.

In [1]: from mybot.items import PersonItem

In [2]: i = PersonItem(name='rolando')

In [3]: i.save()
Out[3]: <Person: Person object>

In [4]: PersonItem.django_model.objects.get(name='rolando')
Out[4]: <Person: Person object>

Итак, он работает по назначению.

Наконец, вы можете не захотеть устанавливать переменные среды каждый раз, когда вы запускаете своего бота. Существует много альтернатив для решения этой проблемы, хотя лучше всего, что пакеты проектов фактически установлены в пути, установленном в PYTHONPATH.

Это одно из самых простых решений: добавьте эти строки в ваш файл mybot/settings.py, чтобы настроить переменные среды.

# Setting up django project full path.
import sys
sys.path.insert(0, '/home/rolando/projects/myweb')

# Setting up django settings module name.
# This module is located at /home/rolando/projects/myweb/myweb/settings.py.
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'myweb.settings'

# Since Django 1.7, setup() call is required to populate the apps registry.
import django; django.setup()

Примечание.. Лучший подход к хакерству пути состоит в том, чтобы иметь файлы setuptools на основе setup.py в обоих проектах и ​​запускать python setup.py develop, которые свяжут ваш путь проекта с путём python ( Я предполагаю, что вы используете virtualenv).

Этого достаточно. Для полноты, вот основной паук и трубопровод для полностью работающего проекта:

  • Создайте паука.

    $ cd ~/projects/mybot
    $ scrapy genspider -t basic example example.com
    

    Код паука:

    # file: mybot/spiders/example.py
    from scrapy.spider import BaseSpider
    from mybot.items import PersonItem
    
    
    class ExampleSpider(BaseSpider):
        name = "example"
        allowed_domains = ["example.com"]
        start_urls = ['http://www.example.com/']
    
        def parse(self, response):
            # do stuff
            return PersonItem(name='rolando')
    
  • Создайте конвейер в mybot/pipelines.py, чтобы сохранить элемент.

    class MybotPipeline(object):
        def process_item(self, item, spider):
            item.save()
            return item
    

    Здесь вы можете использовать item.save(), если вы используете класс DjangoItem или импортируете модель django напрямую и создаете объект вручную. В обоих случаях основной проблемой является определение переменных среды, поэтому вы можете использовать модели django.

  • Добавьте настройку конвейера в файл mybot/settings.py.

    ITEM_PIPELINES = {
        'mybot.pipelines.MybotPipeline': 1000,
    }
    
  • Запустите паук.

    $ scrapy crawl example
    

Ответ 2

Несмотря на то, что ответ Rho кажется очень хорошим, я подумал, что поделился бы тем, как я получил сеанс работы с Django Models (aka Django ORM) без полноценного проекта Django, поскольку в вопросе говорится только о использовании "базы данных Django". Также я не использую DjangoItem.

Следующее работает с Scrapy 0.18.2 и Django 1.5.2. Мой проект scrapy называется слом в следующем.

  • Добавьте в свой файл settings.py следующий файл

    from django.conf import settings as d_settings
    d_settings.configure(
        DATABASES={
            'default': {
                'ENGINE': 'django.db.backends.postgresql_psycopg2',
                'NAME': 'db_name',
                'USER': 'db_user',
                'PASSWORD': 'my_password',
                'HOST': 'localhost',  
                'PORT': '',
            }},
        INSTALLED_APPS=(
            'scrapping',
        )
    )
    
  • Создайте файл manage.py в той же папке, что и ваш scrapy.cfg: Этот файл не нужен, когда вы запускаете сам паук, но он очень удобен для настройки базы данных. Итак, идем:

    #!/usr/bin/env python
    import os
    import sys
    
    if __name__ == "__main__":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "scrapping.settings")
    
        from django.core.management import execute_from_command_line
    
        execute_from_command_line(sys.argv)
    

    То, что весь контент manage.py и в точности соответствует файлу запаса manage.py, который вы получаете после запуска django-admin startproject myweb, но 4-я строка указывает на ваш файл настроек scrapy. Разумеется, использование DJANGO_SETTINGS_MODULE и settings.configure кажется немного нечетным, но оно работает для одних manage.py команд, которые мне нужны: $ python ./manage.py syncdb.

  • Ваш models.py Ваш файл models.py должен быть помещен в папку проекта проекта (т.е. scrapping.models´). After creating that file you should be able to run you $python./manage.py syncdb`. Это может выглядеть так:

    from django.db import models
    
    class MyModel(models.Model):
        title = models.CharField(max_length=255)
        description = models.TextField()
        url = models.URLField(max_length=255, unique=True)
    
  • Ваши items.py и pipeline.py: Раньше я использовал DjangoItem, как описано в ответе Rho, но у меня возникали проблемы с ним при запуске множества обходов параллельно с scrapyd и использовании Postgresql. Исключение max_locks_per_transaction было брошено в какой-то момент, разбивая все запущенные обходы. Кроме того, я не понял, как правильно откатить неудачный item.save() в конвейере. Короче говоря, я вообще не использовал DjangoItem, который решил все мои проблемы. Вот как это сделать: items.py:

    from scrapy.item import Item, Field
    
    class MyItem(Item):
        title = Field()
        description = Field()
        url = Field()
    

    Обратите внимание, что поля должны иметь то же имя, что и в модели, если вы хотите их легко распаковать, как на следующем шаге! pipelines.py:

    from django.db import transaction
    from models import MyModel
    class Django_pipeline(object):
        def process_item(self, item, spider):
            with transaction.commit_on_success():
                scraps = MyModel(**item)
                scraps.save()
            return item
    

    Как уже упоминалось выше, если вы назвали все поля вашего поля, как в файле models.py, вы можете использовать **item для распаковки всех полей при создании объекта MyModel.

Что это!