私は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プロジェクトへのパスを正しく定義するにはどうすればよいですか?(それが問題である場合)
主な誤解は、パッケージパスと設定モジュールパスの違いだと思います。外部スクリプトからDjangoのモデルを使用するには、_Django_SETTINGS_MODULE
_を設定する必要があります。次に、このモジュールはimportableでなければなりません(つまり、設定パスが_myproject.settings
_の場合、_from myproject import settings
_ステートメントはa python Shell)。
Django内のほとんどのプロジェクトはデフォルトのPYTHONPATH
の外のパスに作成されるため、プロジェクトのパスをPYTHONPATH
環境変数に追加する必要があります。
完全に機能する(そして最小限の)Djangoモデルを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)
_
_INSTALLED_APPS
_の_myweb/settings.py
_にmyapp
を追加します。
_# 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
_
ここから、基本的に、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
を使用していると想定しています)。
それは十分です。完全を期すために、完全に機能するプロジェクトの基本的なスパイダーとパイプラインを次に示します。
クモを作成します。
_$ 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
_
Rhoの答えはとても良さそうですが、私はDjango Models(aka Django ORM)without本格的なDjangoプロジェクトは、「Djangoデータベース」の使用のみを示しているため、DjangoItemは使用していません。
以下はScrapy 0.18.2とDjango 1.5.2。で動作します。以下では、私のスクレイピープロジェクトをスクラップと呼びます。
以下をスクレイピー_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行目はスクラップ設定ファイルを指しています。確かに、_Django_SETTINGS_MODULE
_と_settings.configure
_の使用は少し奇妙に思えますが、必要な_manage.py
_コマンドの1つである_$ python ./manage.py syncdb
_で機能します。
_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)
_
あなたの_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
_を使用してすべてのフィールドをアンパックできます。
それでおしまい!