ScrapyとGridDBを使ってデータを収集する

はじめに

このブログでは、PythonのライブラリScrapyを使って、任意のウェブサイトからデータを収集する方法について説明します。そして、そのデータをJSONとHTMLファイルに保存します。その後に、そのデータを長期的かつ効率的に利用するために、GridDBに保存する方法についても説明します。

前提条件

この方法では、以下の5つを事前にインストールする必要があります。

  1. Python 3.6+
  2. Scrapy
  3. GridDB
  4. GridDB C-client
  5. GridDB python-client

もしまだインストールされていない場合は、Anaconda Navigatorのインストールをお勧めします。Anacondaには、データサイエンティストが実験するための様々なツールが用意されています。また、仮想環境を利用すれば、実際のシステムパスに干渉することなく、アプリケーションを実行しながら特定のバージョン要件を満たすことができます。

Scrapyを使って新しいプロジェクトを作成する

このチュートリアルでは、Anaconda のコマンドラインインターフェースと Jupyter Notebooks を使用します。これらのツールは、どちらも Anaconda ダッシュボードにあります。

scrapyで新しいプロジェクトを作るのは簡単です。新しいプロジェクトフォルダを作成したいディレクトリ内で、以下のコマンドを入力してください。

scrapy startproject griddb_tutorial

カレントディレクトリに,griddb_tutorialという名前の新しいフォルダが作成されました。このフォルダの中身を見てみましょう。

tree directory_path /F

URLからデータを抽出する

Scrapyでは、ウェブサイトをクロールして情報を抽出するために、Spiderというクラスを使います。この Spider クラスの中で、カスタムコードを書いたり、最初のリクエストを記述したりすることができます。このチュートリアルでは、ウェブサイトquotes.toscrape.comから面白い引用文を収集し、その情報をJSON形式で保存します。

以下のコードは、引用文に関連するテキスト、著者、タグの情報を収集します。

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes_funny"
    start_urls = [
        'http://quotes.toscrape.com/tag/humor',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }

このpythonファイルを /griddb_tutorial/spider ディレクトリに保存しておきます。コマンドラインでscrapyに名前を与えてspiderを実行します。そのため、各spiderには個別の名前を使うようにしてください。

ホームディレクトリに戻ってきました。このspiderを実行して、何が得られるか見てみましょう。

scrapy crawl quotes_funny

データの抽出には時間がかかります。実行が完了すると、次のような出力が得られます。

DEBUG: Scraped from <200 http://quotes.toscrape.com/tag/humor/>
{'text': '"The reason I talk to myself is because I'm the only one whose answers I accept."', 'author': 'George Carlin', 'tags': ['humor', 'insanity', 'lies', 'lying', 'self-indulgence', 'truth']}
2021-05-29 21:29:44 [scrapy.core.engine] INFO: Closing spider (finished)

データをJSONに格納する

前のステップで出力されたデータを保存するために、上記のコマンドを変更し、追加のパラメータを渡します。

scrapy crawl quotes_funny -O quotes_funny.json

これにより、ホームディレクトリに quotes_funny.json という名前の新しいファイルが作成されます。なお、-Oコマンドは、既存の同名のファイルを上書きします。既存の JSON ファイルに新しいコンテンツを追加したい場合には、代わりに -o を使用してください。

JSONファイルの内容は以下のようになります。

[
{"text": "\u201cThe person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.\u201d", "author": "Jane Austen", "tags": ["aliteracy", "books", "classic", "humor"]},
{"text": "\u201cAll you need is love. But a little chocolate now and then doesn't hurt.\u201d", "author": "Charles M. Schulz", "tags": ["chocolate", "food", "humor"]},
{"text": "\u201cThe reason I talk to myself is because I\u2019m the only one whose answers I accept.\u201d", "author": "George Carlin", "tags": ["humor", "insanity", "lies", "lying", "self-indulgence", "truth"]}
]

GridDBにデータを格納する

時間的に連続したデータを収集しているのであれば、それをDatabaseに保存するのは賢明なやり方であると言えるでしょう。GridDBは、時系列データを保存することができ、IoTやビッグデータに特別に最適化されています。その高いスケーラビリティは、SQLとNoSQLの両方のインターフェースに対応しています。まずはそれらのチュートリアルに従って設定してください。

scrapyから収集したデータはJSONファイルの形式です。さらに、ほとんどのウェブサイトでは、JSON形式でデータをエクスポートすることができます。そこで、データを環境に読み込むためのpythonスクリプトを書いてみましょう。

JSONファイルからデータを読み込む

import json
f = open('quotes_funny.json',)
data = json.load(f)
print(data[0])

以下のような出力が得られます。

{'text': '"The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking."',
 'author': 'Albert Einstein',
 'tags': ['change', 'deep-thoughts', 'thinking', 'world']}

すべてのキーと値のペアを抽出するには、

for d in data:
    for key, value in d.items():
        print(key, value)

キーと値のペアを抽出したところで、GridDBインスタンスを初期化してみましょう。

GridDB コンテナの初期化

import griddb_python as griddb

factory = griddb.StoreFactory.get_instance()

# Container Initialization
try:
    gridstore = factory.get_store(host=your_host, port=your_port, 
            cluster_name=your_cluster_name, username=your_username, 
            password=your_password)

    conInfo = griddb.ContainerInfo("Dataset_Name",
                    [["attribute1", griddb.Type.STRING],["attribute2",griddb.Type.FLOAT],
                    ....],
                    griddb.ContainerType.COLLECTION, True)
    
    cont = gridstore.put_container(conInfo)   
    cont.create_index("id", griddb.IndexType.DEFAULT)

except griddb.GSException as e:
    for i in range(e.get_error_stack_size()):
        print("[", i, "]")
        print(e.get_error_code(i))
        print(e.get_location(i))
        print(e.get_message(i))

上記のコードにカスタムの詳細を記入してください。今回のケースでは、データタイプは基本的に STRING であることに注意してください。GridDBでサポートされているデータ型の詳細についてはこちらを参照してください。

GridDB コンテナにデータを挿入する

このJSONファイルは、辞書のリストです。それぞれの辞書にはテキスト、著者、タグの3つの属性があります。各カテゴリのアイテムを取得するために、2つのループを実行します。

for d in data:
    for key in d:
        ret = cont.put(d[key])

最終的な挿入スクリプトは以下のようになります。

import griddb_python as griddb

factory = griddb.StoreFactory.get_instance()

# Container Initialization
try:
    gridstore = factory.get_store(host=your_host, port=your_port, 
            cluster_name=your_cluster_name, username=your_username, 
            password=your_password)

    conInfo = griddb.ContainerInfo("Dataset_Name",
                    [["attribute1", griddb.Type.INTEGER],["attribute2",griddb.Type.FLOAT],
                    ....],
                    griddb.ContainerType.COLLECTION, True)
    
    cont = gridstore.put_container(conInfo)   
    cont.create_index("id", griddb.IndexType.DEFAULT)
    
    #Adding data to container
    for d in data:
        for key in d:
            ret = cont.put(d[key])

except griddb.GSException as e:
    for i in range(e.get_error_stack_size()):
        print("[", i, "]")
        print(e.get_error_code(i))
        print(e.get_location(i))
        print(e.get_message(i))

GridDBのpython-clientの公式Githubページでは、デフォルトのクラスタ値を確認することができます。

まとめ

このチュートリアルでは、Webサイトのデータをクロールするスパイダーを作成する方法を紹介しました。収集したデータは、異なるプラットフォーム間で簡単に共有できるようにJSON形式で保存し、その後、このデータをGridDBに格納するための挿入スクリプトを開発しました。

連続したデータを扱う場合、データベースにデータを保存することは非常に重要で、複数のJSONファイルを保存するのは大変な作業です。そのような時にGridDBを使うことで、あらゆる情報を一箇所に保存することが容易になります。これにより、時間を節約し、チームの情報共有の手間を省くことができるようになるでしょう。ぜひ今すぐGridDBを使ってみてください。

ブログの内容について疑問や質問がある場合は Q&A サイトである Stack Overflow に質問を投稿しましょう。 GridDB 開発者やエンジニアから速やかな回答が得られるようにするためにも "griddb" タグをつけることをお忘れなく。 https://stackoverflow.com/questions/ask?tags=griddb

Leave a Reply

Your email address will not be published. Required fields are marked *