スキップしてメイン コンテンツに移動

無料でGoogle検索を自動化する

プログラムから自動でGoogle検索して、結果を収集したい時がたまにある。

今回は、Google App Engine と、Google Custom Search APIを使って、Google検索を自動化する方法をメモ。サンプルでは、価格.comのレビューのみを取得するフォームを作ってみた。

Google Custom Search API は、Google Custom Search サービスを外部から操作できるAPI。100リクエスト/日まで無料だ。それ以上リクエストしたい場合は、1000リクエスト毎に5ドル支払えば検索可能となる。1日100件ぐらいであれば、Google Appe Engine側も無料範囲で十分まかなえる量だ。

Custom Search APIを有効にする

まずは、Custom Search APIが使えるように、有効化とAPIキーを取得する。

Google Developers Console にログインして、該当のプロジェクトを選択し、「APIと認証」から「API」メニューを選択する。
APIメニューを選択

APIの一覧からCustom Search APIを探し、右のボタンを押す。
APIの有効化

ちなみに、100リクエスト/日以上検索したい場合は、API名を選択後に表示される画面で割り当てを選択し・・・
API割り当ての選択

ここのSet billable limitsから、1日のリクエスト可能数を引き上げる事ができる。(※プロジェクトの課金を有効にしておく必要がある。)
enter image description here

続いてAPIにアクセスするためのキーを取得する。「APIと認証」から「認証情報」を選択する。
認証情報

次に表示される画面で、「新しいキーを作成」から「サーバーキー」を選択する。OAuthは、例えばユーザー情報を取得するようなAPIを使用する時に選択する。今回は検索のみを使用するので、サーバーキーでOKだ。
新しいサーバーキーの作成

許可IPアドレスの設定は今回空欄とした。特定のIPアドレスのサーバーからのみキーを有効としたい場合は設定する。
許可IPアドレスの設定

これでキーが作成できた。このキーはプログラムからAPIへ接続する際に使用する。
APIキーの完成

Google Custom Searchを作成する

APIキーを取得したら次は Google Custom Search で検索エンジンを作成する。Custom Search APIはここで作成した検索エンジンを操作するAPIだ。

Google Custom Search へアクセスし、新しい検索エンジンを作る。
新しい検索エンジンの作成

検索対象のサイトドメインを登録する。かならず1つのドメインを指定する必要がある。今回はとりあえず kakaku.com(あとで変更する) を入力し、検索エンジンの名前を指定。
ドメインの登録

これで検索エンジンが完成。コントロールパネルへアクセスする。
検索エンジンの完成

ここから検索エンジンのIDを取得しておく、IDもAPIキー同様にプログラムからAPIへアクセスする場合に必要。
enter image description here

今回は、価格.comのレビューのみを取得する事が目的なので、その他のページがヒットしないよう、レビューページのURLのみをターゲットにする。対象サイトを選択して・・・
enter image description here

レビューページのURLを入力する。商品IDなど動的に変わる部分は*でワイルドカード指定ができる。
enter image description here

これで、価格.comのレビューページだけがヒットする検索エンジンが完成した。あとはこいつをプログラムから呼び出す処理を実装する。

検索処理を実装する

まずはキーワードを入力するフォーム。

<form role="form" method="post" action="search">
  <div class="form-group">
    <label for="keyword">検索キーワード</label>
      <input type="text" id="keyword" name="keyword">
  </div>
    <button type="submit" class="btn btn-default">検索</button>
</form>

次にリクエストハンドラ。キーワードを取得して、しかるべきパラメータでAPIのURLへ送信。戻り値はJSON。※APIの詳細は、Google公式ドキュメントを参照。

import json
import logging
import urllib
from google.appengine.api import urlfetch
from lib.controller import *


class Top(Controller):
    def get(self):
        self.draw_template('front/cse/top.html')


class Search(Controller):
    def post(self):

        # キーワードを得る(URLエンコードしておく)
        keyword = self.request.get('keyword')
        keyword = urllib.quote(keyword.encode('utf-8'))

        # リクエストパラメータ組み立て
        url = 'https://www.googleapis.com/customsearch/v1'
        url += '?key=%s' % '生成したAPIキー'
        url += '&cx=%s' % '作成した検索エンジンID'
        url += '&q=%s' % keyword

        # 検索
        result = urlfetch.fetch(url)

        logging.info(url)

        items = list()
        if not 200 <= result.status_code <= 299:
            # エラー
            logging.error('google custom search error: $s' % str(result.status_code))
            logging.error(result.content)
        else:
            # 結果を得る
            content_dict = json.loads(result.content)
            items = content_dict.get('items', list())

        self.set_template_value('items', items)
        self.draw_template('front/cse/search.html')


url_map = [
    ('/cse/top', Top),
    ('/cse/search', Search),
]

application = webapp.WSGIApplication(url_map, debug=True)

itemsに検索結果のリストが格納される。

Googleは、商品情報や、レビュー、レシピなど、特定の情報については、ルールに従ってHTML(構造化データ)を組んでおけば、意味のある情報としてインデックスしてくれる。たとえば、レビューのタイトルや評価の星の数などだ。

価格.comやヨドバシなどそれなりのショッピングサイトは、この構造化データに準じてサイト構築してくれており、これらのサイトに対して検索した Custom Search API の戻り値も構造化されていて参照しやすい。

つまり、戻されたJSONデータの中には、レビューのタイトル、本文(一部)、評価数(星の数)が、(ほぼ)おなじキー名で格納されているので取り出しやすいのだ。

ちょっと話は脱線したけど、ここまでできれば後はcronで自動化したりと自由自在だ。

実はこの構造化データの値も条件としてフィルタリングできるので、「価格.comの星1つのレビューのみ抽出」といった事も可能となる。この方法はまた次の機会に。。。

コメント

  1. Alternative energy sources like windmills are designed using metallic fabrication. Fabrication processes are best traveling underwear used to shape blades of windmills that may harness the ability of the wind to create electricity. There is hardly any trade that doesn’t use metallic fabrication or instruments and equipment created by metallic fabrication.

    返信削除

コメントを投稿

このブログの人気の投稿

Moduleをdispach.yamlで振り分ける方法

Google App Engineには、アプリケーション内の機能をグループ化できる Modules というしくみがある。Moduleごとに、インスタンスのスペックやスケールのルールが設定できるため、フロントエンドとバックオフィス、バックグラウンドジョブといった用途別にModuleを作成すると良さそうだ。また、どのModuleが使われるかは、URL(パス)で振り分けることができる。今回はその方法のメモ。 Moduleのyamlファイルの作成 今回は、以下の3つのModuleを作ってみる。 ・フロントエンド用(app.yaml) default ・バックオフィス用(back.yaml) ・JOB用(job.yaml) まずは各Moduleのyamlファイルを作成する。 app.yaml application: gcp-memo module: default version: 1 runtime: python27 api_version: 1 threadsafe: true instance_class: F1 (以下省略) admin.yaml application: gcp-memo module: admin version: 1 runtime: python27 api_version: 1 threadsafe: true instance_class: F1 (以下省略) job.yaml application: gcp-memo module: job version: 1 runtime: python27 api_version: 1 threadsafe: true instance_class: B1 basic_scaling: max_instances: 2 idle_timeout: 10m (以下省略) dispatch.yamlファイルの作成 続いて、これらのModuleを振り分けるdispatch.yamlを作成する。今回は、パスが/admin/に一致すればadminモジュールへ、/job/に一致すればjobモジュールが使用されるようにする。dispatch.yamlは、アプリケーションのルートディレクトリに配置する必要がある。Moduleのyamlファイルについては、ルート...

Managed Virtual Machine に望むこと

先日2014年4月22日に行われた、Google Cloud Platformセッションの模様がYoutubeに公開されてた。 地方民はこういうイベントになかなか参加できないので、動画配信はほんとに助かる。ありがたや。。。 動画の中で語られている Managed VM は地味だけど、なにげにすごい機能だと思う。GAEでできなかったほとんどの事がこれで解決できるかもしれない。 ただ、個人的に Managed VMでは、(スケールアウトしなくていいので)固定IPも使えるようになってほしい。なぜなら、Google App Engineで外部のシステムと連携するとき、相手側でIPアドレス制限されている事がある。だから、連携前にあらかじめこちらのIPアドレスを教えておくのだけど、GAEはPaaSなのでその範囲も広いし、いつ変わるかわからない。まぁ、IPアドレス制限という方法自体がすでに時代遅れな感じではあるけど。 ともかく、GAEではそういうシステムと連携する時は、間にGAEでないサーバーを中継させておく必要がある。なので、このためだけにOSやApacheのメンテが発生する。これは、ほんとにアホらしいことだ。もし、Managed VMで固定IPが使えれば、対外部システムとの処理だけそのインスタンスで行えばいいし、中継サーバーも不要になるので、だいぶ楽になるのだ。 Googleさん、よろしくおねがいします。

Google App Engineでファイルを保存する方法3つ

Google App Engineでは、通常のWebアプリケーションのように、サーバー上のファイルシステムへアクセスすることができない。別の方法でファイルの読み書きをする事になるけど、方法はいくつかあるので、それぞれの方法と長所短所をまとめてみた。サンプルと全てのソースコードはこちら。( サンプル / ソースコード ) 方法1:BlobPropertyを使う ndb(db)のBlobProperty(https://developers.google.com/appengine/docs/python/ndb/properties)ではバイナリデータをそのまま格納できる。 まずは保存するModelの定義を実装する。 from google.appengine.ext import ndb class UserFileModel(ndb.Model):     """     ファイル格納モデル     """     file_data = ndb.BlobProperty()                  # ファイルデータ 続いて、アップロードフォーム。 <form> <div class="form-group"> <input id="exampleInputFile" name="file_data" type="file" />     </div> <button class="btn btn-default" type="submit">保存</button> </form> アップロードハンドラを実装。リクエストされたデータをそのまま突っ込むだけ。 def post(self):         file_data = self.request.get('file_data')         user_file = UserFileMod...