python - tag - templates dirs django
Acceda a los modelos Django con scrapy: definiendo el camino al proyecto Django (2)
Soy nuevo en Python y Django. Actualmente estoy explorando el uso de Scrapy para raspar sitios y guardar datos en la base de datos de Django. Mi objetivo es ejecutar una araña basada en el dominio dado por un usuario.
He escrito una araña que extrae los datos que necesito y los almacena correctamente en un archivo json al llamar
scrapy crawl spider -o items.json -t json
Como se describe en el tutorial de scrapy .
Mi objetivo ahora es lograr que la araña guarde con éxito los datos en la base de datos de Django, y luego trabajar para que la araña se ejecute en función de las entradas del usuario.
Soy consciente de que existen varias publicaciones sobre este tema, como estas: link 1 link 2 link 3
Pero después de haber gastado más de 8 horas tratando de hacer que esto funcione, supongo que no soy el único que todavía tiene problemas con esto. Por lo tanto, intentaré y reuniré todo el conocimiento que he obtenido hasta ahora en esta publicación, así como una posible publicación de una solución de trabajo en un momento posterior. Debido a esto, esta publicación es bastante larga.
Me parece que hay dos soluciones diferentes para guardar datos en la base de datos de Django desde Scrapy. Una es usar DjangoItem , otra es importar los modelos directamente (como se hace aquí ).
No estoy completamente consciente de las ventajas y desventajas de estos dos, pero parece que la diferencia es simplemente que el uso de DjangoItem es más conveniente y más corto.
Qué he hecho:
He añadido:
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/'')
El error que obtengo es:
ImportError: No module named settings
Estoy pensando que estoy definiendo el camino a mi proyecto Django de una manera incorrecta?
También intenté lo siguiente:
setup_django_env(''../../'')
¿Cómo puedo definir la ruta a mi proyecto Django correctamente? (si ese es el problema)
A pesar de que la respuesta de Rho parece muy buena, pensé que compartiría cómo obtuve el tratamiento con Django Models (también conocido como Django ORM) sin un proyecto completo de Django ya que la pregunta solo indica el uso de una "base de datos Django". Además, no uso DjangoItem.
Lo siguiente funciona con Scrapy 0.18.2 y Django 1.5.2. Mi proyecto de scrapy se llama desguace en lo siguiente.
Agregue lo siguiente a su archivo 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'', ) )
Cree un archivo
manage.py
en la misma carpeta que suscrapy.cfg
: este archivo no es necesario cuando ejecuta la araña en sí, pero es muy conveniente para configurar la base de datos. Así que, aquí vamos:#!/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)
Ese es todo el contenido de
manage.py
y esmanage.py
archivo stockmanage.py
que obtienes después de ejecutardjango-admin startproject myweb
pero la cuarta línea apunta a tu archivo de configuración de scrapy. Es cierto que usarDJANGO_SETTINGS_MODULE
ysettings.configure
parece un poco extraño, pero funciona para los comandos de unomanage.py
que necesito:$ python ./manage.py syncdb
.Su
models.py
Your models.py se debe colocar en la carpeta de proyecto de scrapy (es decir,scrapping.models´). After creating that file you should be able to run you
scrapping.models´). After creating that file you should be able to run you
$ python ./manage.py syncdb`. Puede verse así: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)
Your
items.py
ypipeline.py
: Yo solía usar DjangoItem como se describe en la respuesta de Rho, pero me encontré con problemas al ejecutar muchos rastreos en paralelo con scrapyd y el uso de Postgresql. La excepciónmax_locks_per_transaction
fue lanzada en algún punto rompiendo todos los rastreos en ejecución. Además, no me di cuenta de cómo deshacer correctamente unitem.save()
fallidoitem.save()
en la tubería. Para resumir, terminé sin usar DjangoItem, lo que resolvió todos mis problemas. Aquí es cómo:items.py
:from scrapy.item import Item, Field class MyItem(Item): title = Field() description = Field() url = Field()
Tenga en cuenta que los campos deben tener el mismo nombre que en el modelo si desea descomprimirlos cómodamente en el siguiente paso.
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
Como se mencionó anteriormente, si usted nombró todos los campos de sus artículos como lo hizo en su archivo
models.py
, puede usar el**item
para descomprimir todos los campos al crear su objeto MyModel.
¡Eso es!
Creo que el error principal es la ruta del paquete frente a la ruta del módulo de configuración. Para usar los modelos de django a partir de un script externo, debe configurar el DJANGO_SETTINGS_MODULE
. Entonces, este módulo tiene que ser importable (es decir, si la ruta de configuración es myproject.settings
, entonces la declaración from myproject import settings
debería funcionar en un shell de python).
Como la mayoría de los proyectos en django se crean en una ruta fuera de la PYTHONPATH
predeterminada, debe agregar la ruta del proyecto a la variable de entorno PYTHONPATH
.
Aquí hay una guía paso a paso para crear una integración de modelos Django completamente funcional (y mínima) en un proyecto de Scrapy:
Nota: Estas instrucciones funcionan en la fecha de la última edición. Si no funciona para usted, agregue un comentario y describa su problema y las versiones de scrapy / django.
Los proyectos se crearán en el directorio
/home/rolando/projects
.Comience el proyecto django .
$ cd ~/projects $ django-admin startproject myweb $ cd myweb $ ./manage.py startapp myapp
Crea un modelo en
myapp/models.py
.from django.db import models class Person(models.Model): name = models.CharField(max_length=32)
Agregue
myapp
aINSTALLED_APPS
enmyweb/settings.py
.# at the end of settings.py INSTALLED_APPS += (''myapp'',)
Establecer mi configuración de db en
myweb/settings.py
# at the end of settings.py DATABASES[''default''][''ENGINE''] = ''django.db.backends.sqlite3'' DATABASES[''default''][''NAME''] = ''/tmp/myweb.db''
Crea la base de datos.
$ ./manage.py syncdb --noinput Creating tables ... Installing custom SQL ... Installing indexes ... Installed 0 object(s) from 0 fixture(s)
Crea el proyecto de scrapy .
$ cd ~/projects $ scrapy startproject mybot $ cd mybot
Crea un artículo en
mybot/items.py
.
Nota: en las versiones más nuevas de Scrapy, debe instalar scrapy_djangoitem
y usar 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
La estructura de directorio final es esta:
/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
A partir de aquí, básicamente hemos terminado con el código requerido para usar los modelos django en un proyecto de scrapy. Podemos probarlo de inmediato usando el comando scrapy shell
pero tenga en cuenta las variables de entorno requeridas:
$ 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>
Por lo tanto, está funcionando según lo previsto.
Finalmente, es posible que no desee tener que establecer las variables de entorno cada vez que ejecute su bot. Hay muchas alternativas para abordar este problema, aunque lo mejor es que los paquetes de los proyectos se instalan realmente en una ruta establecida en PYTHONPATH
.
Esta es una de las soluciones más simples: agregue estas líneas a su archivo mybot/settings.py
para configurar las variables de entorno.
# Setting up django''s project full path.
import sys
sys.path.insert(0, ''/home/rolando/projects/myweb'')
# Setting up django''s 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()
Nota: Un mejor enfoque para el pirateo de rutas es tener archivos setuptools
basados en setup.py
en ambos proyectos y ejecutar python setup.py develop
que enlazará su ruta de proyecto en la ruta del python (supongo que usa virtualenv
).
Es suficiente. Para completar, aquí hay una araña básica y una tubería para un proyecto completamente funcional:
Crea la araña.
$ cd ~/projects/mybot $ scrapy genspider -t basic example example.com
El código araña:
# 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'')
Cree una tubería en
mybot/pipelines.py
para guardar el artículo.class MybotPipeline(object): def process_item(self, item, spider): item.save() return item
Aquí puede usar
item.save()
si está usando la claseDjangoItem
o importa el modelo django directamente y crea el objeto manualmente. En ambos sentidos, el problema principal es definir las variables de entorno para que pueda usar los modelos django.Agregue la configuración de la tubería a su archivo
mybot/settings.py
.ITEM_PIPELINES = { ''mybot.pipelines.MybotPipeline'': 1000, }
Ejecuta la araña.
$ scrapy crawl example