使用scrapy访问Django模型:定义Django项目的路径

Spl*_*urk 33 python django django-models scrapy

我是Python和Django的新手.我目前正在探索使用Scrapy来抓取网站并将数据保存到Django数据库中.我的目标是根据用户提供的域运行蜘蛛.

我写了一个蜘蛛,它提取我需要的数据,并在调用时将其正确存储在json文件中

scrapy crawl spider -o items.json -t json
Run Code Online (Sandbox Code Playgroud)

scrapy教程中所述.

我的目标是让蜘蛛成功地将数据保存到Django数据库,然后根据用户输入让蜘蛛运行.

我知道这个主题上存在各种帖子,例如: 链接1 链接2 链接3

但是我花了超过8个小时试图让它发挥作用,我假设我不是唯一仍然面临这个问题的人.我将尝试收集到目前为止我在这篇文章中获得的所有知识,以及希望稍后发布一个有效的解决方案.因此,这篇文章相当长.

在我看来,有两种不同的解决方案可以从Scrapy将数据保存到Django数据库.一种是使用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/')
Run Code Online (Sandbox Code Playgroud)

我得到的错误是:

ImportError: No module named settings
Run Code Online (Sandbox Code Playgroud)

我在想我是以错误的方式定义了我的Django项目的路径?

我也尝试过以下方法:

setup_django_env('../../') 
Run Code Online (Sandbox Code Playgroud)

如何正确定义Django项目的路径?(如果那是问题)

Rol*_*Max 68

我认为主要的误解是包路径与设置模块路径.要从外部脚本使用django的模型,您需要设置DJANGO_SETTINGS_MODULE.然后,这个模块必须是可导入的(即如果设置路径是myproject.settings,那么该语句from myproject import settings应该在python shell中工作).

由于django中的大多数项目都是在默认路径之外的路径中创建的PYTHONPATH,因此必须将项目的路径添加到PYTHONPATH环境变量中.

以下是创建一个完全工作(和最小)Django模型集成到Scrapy项目的分步指南:

注意:此说明适用于上次编辑的日期.如果它不适合您,请添加评论并描述您的问题和scrapy/django版本.

  1. 项目将在/home/rolando/projects目录中创建.

  2. 启动django项目.

    $ cd ~/projects
    $ django-admin startproject myweb
    $ cd myweb
    $ ./manage.py startapp myapp
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在中创建模型myapp/models.py.

    from django.db import models
    
    
    class Person(models.Model):
        name = models.CharField(max_length=32)
    
    Run Code Online (Sandbox Code Playgroud)
  4. 添加myappINSTALLED_APPSmyweb/settings.py.

    # at the end of settings.py
    INSTALLED_APPS += ('myapp',)
    
    Run Code Online (Sandbox Code Playgroud)
  5. 设置我的数据库设置myweb/settings.py.

    # at the end of settings.py
    DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'
    DATABASES['default']['NAME'] = '/tmp/myweb.db'
    
    Run Code Online (Sandbox Code Playgroud)
  6. 创建数据库.

    $ ./manage.py syncdb --noinput
    Creating tables ...
    Installing custom SQL ...
    Installing indexes ...
    Installed 0 object(s) from 0 fixture(s)
    
    Run Code Online (Sandbox Code Playgroud)
  7. 创建scrapy项目.

    $ cd ~/projects
    $ scrapy startproject mybot
    $ cd mybot
    
    Run Code Online (Sandbox Code Playgroud)
  8. 在中创建一个项目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
Run Code Online (Sandbox Code Playgroud)

最终的目录结构是这样的:

/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
Run Code Online (Sandbox Code Playgroud)

从这里开始,基本上我们完成了在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>
Run Code Online (Sandbox Code Playgroud)

因此,它按预期工作.

最后,您可能不希望每次运行bot时都必须设置环境变量.有很多替代方法可以解决这个问题,尽管最好的是项目的包实际安装在路径集中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()
Run Code Online (Sandbox Code Playgroud)

注意:更好的路径入侵方法是在项目和运行中都有setuptools基于setup.py文件的文件,python setup.py develop这会将你的项目路径链接到python的路径(我假设你使用virtualenv).

足够了.为了完整性,这里是一个基本的蜘蛛和管道,用于完全工作的项目:

  1. 创造蜘蛛.

    $ cd ~/projects/mybot
    $ scrapy genspider -t basic example example.com
    
    Run Code Online (Sandbox Code Playgroud)

    蜘蛛代码:

    # 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')
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建管道mybot/pipelines.py以保存项目.

    class MybotPipeline(object):
        def process_item(self, item, spider):
            item.save()
            return item
    
    Run Code Online (Sandbox Code Playgroud)

    在这里,您既可以使用item.save(),如果你使用的是DjangoItem类或直接导入Django的模型和手动创建的对象.在两种方式中,主要问题是定义环境变量,以便您可以使用django模型.

  3. 将管道设置添加到您的mybot/settings.py文件中.

    ITEM_PIPELINES = {
        'mybot.pipelines.MybotPipeline': 1000,
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 跑蜘蛛.

    $ scrapy crawl example
    
    Run Code Online (Sandbox Code Playgroud)

  • 非常详细的描述,谢谢.工作就像一个魅力.我只遇到一个问题,我不得不将os.environ ['DJANGO_SETTINGS_MODULE'] ='myweb.settings'更改为os.environ ['DJANGO_SETTINGS_MODULE'] ='settings'.因此没有添加myweb前缀,否则它将无法识别模块. (6认同)
  • 这是一个非常完整的答案.我唯一的问题是在scrapy shell步骤中我不得不添加`import django django.setup()` (6认同)
  • 对.`DJANGO_SETTINGS_MODULE`的值很大程度上取决于你如何设置你的python路径变量.这可能会让人感到困惑,因为django和scrapy默认使用项目目录和项目包的相同名称.添加到`sys.path`的路径应该是包含`settings.py`文件的目录的父路径.无论如何,我很高兴这解决了你的问题. (2认同)

Chr*_*ris 5

虽然Rho的答案看起来非常好,但我想我会分享如何使用Django模型(也就是Django ORM)进行 scrapy, 而没有完整的Django项目,因为这个问题只说明了"Django数据库"的使用.我也不使用DjangoItem.

以下适用于Scrapy 0.18.2和Django 1.5.2.我的scrapy项目在下面称为报废.

  1. 将以下内容添加到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',
        )
    )
    
    Run Code Online (Sandbox Code Playgroud)
  2. 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)
    
    Run Code Online (Sandbox Code Playgroud)

    这是完整的内容,manage.py并且几乎就是manage.py您在运行后获得的库存文件,django-admin startproject myweb但第4行指向您的scrapy设置文件.不可否认,使用DJANGO_SETTINGS_MODULE并且settings.configure看起来有点奇怪,但它适用于manage.py我需要的一个命令:$ python ./manage.py syncdb.

  3. models.py 的models.py应该放在你的scrapy项目文件夹中(即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)
    
    Run Code Online (Sandbox Code Playgroud)
  4. 你曾经items.pypipeline.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()
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,如果要像下一步那样方便地解压缩,则字段需要与模型中的名称相同! 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
    
    Run Code Online (Sandbox Code Playgroud)

    如上所述,如果您像在models.py文件中一样命名了所有项目字段,则可以**item在创建MyModel对象时用于解压缩所有字段.

而已!