我认为主要的误解是包路径与设置模块路径。为了从外部脚本使用 django 的模型,您需要设置 DJANGO_SETTINGS_MODULE。然后,这个模块必须是importable(即如果设置路径是myproject.settings,那么from myproject import settings 语句应该在python shell 中工作)。
由于 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)
-
在myweb/settings.py 中将myapp 添加到INSTALLED_APPS。
# at the end of settings.py
INSTALLED_APPS += ('myapp',)
-
在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
从这里开始,基本上我们已经完成了在 scrapy 项目中使用 django 模型所需的代码。我们可以立即使用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'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()
注意:更好的路径黑客方法是在两个项目中都有基于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
如果您使用DjangoItem 类,您可以在这里使用item.save(),或者直接导入django 模型并手动创建对象。这两种方式的主要问题是定义环境变量,以便您可以使用 django 模型。
-
将管道设置添加到您的 mybot/settings.py 文件中。
ITEM_PIPELINES = {
'mybot.pipelines.MybotPipeline': 1000,
}
-
运行蜘蛛。
$ scrapy crawl example