web-dev-qa-db-ja.com

アクセスDjango断片的なモデル:Djangoプロジェクトへのパスを定義する

私はPythonおよびDjangoに非常に慣れています。現在、Scrapyを使用してサイトをスクレイピングし、Djangoデータベースにデータを保存します。私の目標はユーザーが指定したドメインに基づいてスパイダーを実行します。

必要なデータを抽出して、呼び出し時にjsonファイルに正しく保存するスパイダーを作成しました

scrapy crawl spider -o items.json -t json

scrapy tutorial で説明されています。

私の目標は、スパイダーが正常にデータをDjangoデータベースに保存し、ユーザー入力に基づいてスパイダーを実行できるようにすることです。

この件に関して、次のようなさまざまな投稿が存在することを認識しています。 link 1link 2link

しかし、これを機能させるために8時間以上費やしているので、これでまだ問題に直面しているのは私だけではないと思います。そのため、私はこの投稿でこれまでに得たすべての知識を収集し、うまくいけば、後で解決策を投稿するつもりです。このため、この投稿はかなり長くなっています。

データをDjango Scrapyのデータベースに保存する方法は2つあります。1つは DjangoItem を使用する方法で、もう1つはモデルを直接インポートする方法です。 (完了時 ここ )。

私はこれら2つの長所と短所を完全には認識していませんが、違いは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プロジェクトへのパスを正しく定義するにはどうすればよいですか?(それが問題である場合)

34
Splurk

主な誤解は、パッケージパスと設定モジュールパスの違いだと思います。外部スクリプトからDjangoのモデルを使用するには、_Django_SETTINGS_MODULE_を設定する必要があります。次に、このモジュールはimportableでなければなりません(つまり、設定パスが_myproject.settings_の場合、_from myproject import settings_ステートメントはa python Shell)。

Django内のほとんどのプロジェクトはデフォルトのPYTHONPATHの外のパスに作成されるため、プロジェクトのパスをPYTHONPATH環境変数に追加する必要があります。

完全に機能する(そして最小限の)DjangoモデルをScrapyプロジェクトに統合するためのステップバイステップガイドです:

注:この手順は、最後に編集した日付で機能します。それがうまくいかない場合は、コメントを追加して、問題とスクラップ/ Djangoのバージョンを説明してください。

  1. プロジェクトは_/home/rolando/projects_ディレクトリ内に作成されます。

  2. Djangoプロジェクトを起動します。

    _$ cd ~/projects
    $ Django-admin startproject myweb
    $ cd myweb
    $ ./manage.py startapp myapp
    _
  3. _myapp/models.py_でモデルを作成します。

    _from Django.db import models
    
    
    class Person(models.Model):
        name = models.CharField(max_length=32)
    _
  4. _INSTALLED_APPS_の_myweb/settings.py_にmyappを追加します。

    _# at the end of settings.py
    INSTALLED_APPS += ('myapp',)
    _
  5. _myweb/settings.py_でデータベース設定を設定します。

    _# at the end of settings.py
    DATABASES['default']['ENGINE'] = 'Django.db.backends.sqlite3'
    DATABASES['default']['NAME'] = '/tmp/myweb.db'
    _
  6. データベースを作成します。

    _$ ./manage.py syncdb --noinput
    Creating tables ...
    Installing custom SQL ...
    Installing indexes ...
    Installed 0 object(s) from 0 fixture(s)
    _
  7. scrapyプロジェクトを作成します。

    _$ cd ~/projects
    $ scrapy startproject mybot
    $ cd mybot
    _
  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
_

最終的なディレクトリ構造は次のとおりです。

_/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 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に設定されたパスにインストールされていることが最善ですが、この問題に対処するための多くの代替策があります。

これは最も簡単なソリューションの1つです。この行を_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を使用していると想定しています)。

それは十分です。完全を期すために、完全に機能するプロジェクトの基本的なスパイダーとパイプラインを次に示します。

  1. クモを作成します。

    _$ 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')
    _
  2. _mybot/pipelines.py_にパイプラインを作成して、アイテムを保存します。

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

    ここで、DjangoItemクラスを使用している場合はitem.save()を使用するか、Djangoモデルを直接インポートしてオブジェクトを手動で作成します。どちらの方法でもメイン問題は、Djangoモデルを使用できるように環境変数を定義することです。

  3. パイプライン設定を_mybot/settings.py_ファイルに追加します。

    _ITEM_PIPELINES = {
        'mybot.pipelines.MybotPipeline': 1000,
    }
    _
  4. クモを実行します。

    _$ scrapy crawl example
    _
72
R. Max

Rhoの答えはとても良さそうですが、私はDjango Models(aka Django ORM)without本格的なDjangoプロジェクトは、「Djangoデータベース」の使用のみを示しているため、DjangoItemは使用していません。

以下はScrapy 0.18.2とDjango 1.5.2。で動作します。以下では、私のスクレイピープロジェクトをスクラップと呼びます。

  1. 以下をスクレイピー_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',
        )
    )
    _
  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)
    _

    これが_manage.py_の内容全体であり、_manage.py_の実行後に取得する在庫の_Django-admin startproject myweb_ファイルとほぼ同じですが、4行目はスクラップ設定ファイルを指しています。確かに、_Django_SETTINGS_MODULE_と_settings.configure_の使用は少し奇妙に思えますが、必要な_manage.py_コマンドの1つである_$ python ./manage.py syncdb_で機能します。

  3. _models.py_モデル.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)
    _
  4. あなたの_items.py_および_pipeline.py_:Rhoの回答に記述されているDjangoItemを使用していたのですが、scrapydと並行して多数のクロールを実行し、Postgresqlを使用すると、DjangoItemで問題が発生しました。例外_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_ファイルで行ったようにすべての項目フィールドに名前を付けた場合、MyModelオブジェクトの作成時に_**item_を使用してすべてのフィールドをアンパックできます。

それでおしまい!

5
Chris