キタックCGソリューションセンター

自分で触りたいWeb担のためのTips集

GoogleのCustom Search JSON API を使ってサイト内検索を実装【コーディング編】

2022年04月21日(木)

PV 43

実装者向けの記事です。

「Custom Search JSON API」で検索システムを作る方法。前回の準備編を受けて今回は「コーディング編」です

Custom Search JSON API を使って、Googleの検索エンジンを自分のサイトに仕込み、サイト内検索を作ります

前回の準備編では、「API key」と「検索エンジンID」を取得しました。これらはどちらも半角英数から成る、ごにょごにょとした文字列です。

これらを使っていよいよコーディングしていきましょう。

PHPで作ります

実装のやり方はいろいろあります。今回は、PHPを使ってプログラムを書いていきます。

その時の気分次第で、Javascriptでもいいし、Pythonでもいいと思います。

1:検索窓を作る

一般に検索システムって、「検索ワード入力画面」と「検索結果出力画面」から成りますよね。

まずは「検索ワード入力画面」すなわち「検索窓」を作っていきましょう。

こんなようなの

上記のようなやつです。文字を打ち込んで、検索ボタンをクリックする、やつ。

見た目を整えるにはCSSを頑張ってみてください。ここでは機能の実装部分だけを解説します。

検索窓の実装は簡単で、例えばこんな感じのHTMLがありえそうです。

     
<form action="/custom_search_result/" method="get">
 <input type="text" name="keyword" id="" value="" placeholder="サイト内検索">
 <button type="submit" >検索</button>
</form>
 

普通のformタグです。中身はinputとbuttonタグなので説明割愛。

<form>の action属性にジャンプ先のpathを指定。method属性に”get”を指定します。

そうすると、例えば検索窓に「おだんご」と入力した場合、こんな感じのURLに。

ドメイン名/custom_search_result/?keyword=おだんご

です。/custom_search_result/ページに遷移しつつ、パラメータで検索ワードがくっついてきます。

このくっついてきたパラメータを使って、検索結果を出力します。

2:検索結果を出力する

さあ、ここからが本番です。

検索formからのgetの投げかけの受け皿となる、custom_search_result ページのhtmlに、検索結果出力のプログラムを書いていきましょう。

検索結果のJSONを返す公式

Custom Search API は、基本的には、APIキーと検索エンジンIDとキーワードを投げるとJSON形式で検索結果を返すよ、というシステムです。

https://www.googleapis.com/customsearch/v1?key=【APIkey】&cx=【検索エンジンID】&q=【検索ワード】

この公式の【API key】【検索エンジンID】【検索ワード】をきちんと埋めてブラウザのアドレスバーに打ち込めば、検索結果が表示されることでしょう。

ただこのままではサイト内検索として使えないので、JSONデータをhtmlに整形しつつ、ユーザーフレンドリーに表示されるようにするわけです。

以下はそのためのプログラムです。

準備(定数と変数の定義)

<?php

  //APIキー
  $api_key = "○○○○○○○○○○○○○○○○○○○○";

  //検索エンジンID
  $engine_id = "●●●●●●●●●●●●●●●";

  //URL
  $url = "https://www.googleapis.com/customsearch/v1?";

  //取得スタート位置
  $start = 1;

  //入力されたキーワード
  $query = htmlspecialchars($_GET['keyword'], ENT_QUOTES, 'UTF-8');

?>

使いやすいようにいろいろな情報を変数(あるいは定数)に入れておきます。

APIキー、検索エンジンID、URL(上の公式の前半部)は分かりやすいかと。

取得スタート位置の指定も必要です。現行のAPI仕様だと、検索結果は1回のAPIリクエスト10件ずつ取得できます。スタート位置を1にしておくと、1〜10件目までの結果が取得でき、スタート位置が11なら11〜20件目まで、というふうになります。

一番下の $query には、$_GET で取得した、URL中のgetパラメータを入れます。

?keyword=○○○○ の部分ですね。

ただここは、検索窓にユーザーが入力する文字列が入ってくるところなので、プログラムでそのまま使うにはやや注意が必要です。クロスサイトスクリプティング(XSS)と呼ばれる、悪意ある文字列で攻撃してくる手法の窓になり得るからです。

XSSの対策として、htmlspecialchars( ) という関数で、文字列にエスケープ処理を施します。ここでは詳しく説明しませんが、ユーザー入力文字列をプログラムで扱うときは、こいつを入れておきましょう。

コード完成形

準備編の下に続く、コードの完成形を先に出しちゃいます。

<?php if (empty($query)) : ?>  //【1】キーワードの入力チェック

    <p>検索キーワードを入力してください</p>
	
<?php else : ?>

    <ul>

      <?php for($i = 1; $i <= 10; $i++) : ?> //【2】メインのforループ

        //【3】パラメータを組み立てて、リクエストURLを作る
        <?php
          $param_arr = array(
            'key' => $api_key,
            'cx' => $engine_id,
            'q' => $query,
            'alt' => 'json',
            'start' => $start,
            'excludeTerms' => 'pdf uploads'
          );
          $param = http_build_query($param_arr);
          $request_url = $url . $param;

          //【4】リクエストURL→JSON取得→連想配列に
          $my_json = file_get_contents($request_url, true);
          $my_arr = json_decode($my_json, true);
        ?>
        
        <?php if (empty($my_arr['items'])) : ?> //【5】配列の中身があるかどうかチェック
        
          <p>検索結果は 0 件です。</p>
          <?php break; ?>

//【6】結果の配列をforeachで回して出力         
        <?php else : ?>

          <?php foreach ($my_arr['items'] as $index => $value) : ?>

            <li>
              <dl>
                <dt>
                  <a href="<?= $value['link'];?>"><?= $value['title']; ?></a>
                </dt>
                <dd><a href="<?= $value['link'];?>"><?= h($value['link']);?></a></dd>
                <dd><?= $value['htmlSnippet'] ; ?></dd>
              </dl>
            </li>
            <?php $start++; ?>

          <?php endforeach; ?>

//【7】検索結果、次のグループの有無で処理を決める 
          <?php 
            if(isset($my_arr['queries']['nextPage'][0]['startIndex'])){  
              $start = $my_arr['queries']['nextPage'][0]['startIndex'];
            }else{
              break;
            }
          ?>

        <?php endif; ?>

      <?php endfor; ?>

    </ul>

<?php endif; ?>

それではざっくり解説です。

【1】キーワードの入力チェック

$query つまりパラメータ内にGETできるキーワードがなかったら、「入力してください」と言います。※同ページ内に入力フォームを設置しておきましょう。

【2】メインのforループ

forループです。前述のように、現仕様だと1回のリクエストで10件分の検索結果を取得できます。これを何回回すか。もちろんある分だけ全部、でもいいのですが、APIの利用がある程度以上いくと従量課金になるため、無限に回しすぎるのも危険です。この例だと10回分回すようになっています。

この場合、1回で10件取得 × 10回 = 最高100件 まで検索結果が取得できます。

【3】パラメータを組み立てて、リクエストURLを作る

検索結果JSONを取得するための公式はこれでしたね。

https://www.googleapis.com/customsearch/v1?key=【APIkey】&cx=【検索エンジンID】&q=【検索ワード】

このURLを作りましょう。

構造が「?」の前と後で別れます。「?」の前は、最初に変数「$url」に格納しておきました。

「?」のあとのパラメータ群、これを一旦「$param」という連想配列に入れてしまいます。

このコードです。

$param_arr = array(
  'key' => $api_key,
  'cx' => $engine_id,
  'q' => $query,
  'alt' => 'json',
  'start' => $start,
  'excludeTerms' => 'pdf uploads'
 );

‘key’、’cx’、’q’は公式に出てきました。他の’alt’、’start’、’excludeTerms’は、APIリクエストの際に利用できるオプションのパラメータです。

ちなみに、’alt’は「データ形式(jsonかatom)」’start’は「取得スタート位置」、’excludeTerms’は「検索結果に含めないキーワード」です。他にもいろいろあるので興味あれば公式ドキュメントへ。

$param = http_build_query($param_arr);

ここでは、「http_build_query」というPHPの便利な関数で、連想配列からクエリ文字列を生成しています。

$param の中身は ‘key=○○○&cx=●●●&q=おだんご&alt=json&start=1&excludeTerms=pdf uploads’ となっています。

$request_url = $url . $param;

最終的に、$urlと$paramつなげて、URL($request_url)ができました。

【4】リクエストURL→JSON取得→連想配列に

リクエストURLでJSONを取得し、それをPHPで扱いやすいように連想配列の形にします。

$my_json = file_get_contents($request_url, true);
$my_arr = json_decode($my_json, true);

「file_get_contents」関数で、$request_url のファイルの中身を取得します。この時点ではJSONデータですね。

その後、「json_decode」関数で、JSONを連想配列形式にします。これにより、PHPで扱いやすくなりました。

print_r関数などで、「$my_arr」の中身を確認しておくといいでしょう。けっこう複雑な配列データが取得できているはずです。

【5】配列の中身があるかどうかチェック

ここで一旦、if文で条件分岐。配列の中身、つまり検索結果のデータが有るかどうかで処理を分けます。データがなければ、「検索結果は0件です」と出力して、処理を止めましょう。

<?php if (empty($my_arr['items'])) : ?>
    <p>検索結果は 0 件です。</p>
    <?php break; ?>

【6】結果の配列をforeachで回して出力

検索結果の連想配列を分解し、foreachループで順に出力していきましょう。

<?php foreach ($my_arr['items'] as $index => $value) : ?>

 <li>
  <dl>
   <dt>
    <a href="<?= $value['link'];?>"><?= $value['title']; ?></a>
   </dt>
   <dd><a href="<?= $value['link'];?>"><?= $value['link'];?></a></dd>
   <dd><?= $value['htmlSnippet'] ; ?></dd>
  </dl>
 </li>
 <?php $start++; ?>

<?php endforeach; ?>

PHPのforeach構文は、配列の要素をまとめて処理したいときに便利なループ記法です。

連想配列の場合、こんな公式で展開できます。

foreach (【配列の変数】 as 【各要素のキーが入る変数】 => 【各要素の値が入る変数】 ) {
 // ループ処理
}

今回の場合だと多重構造なのでちょっとだけ複雑です。

$my_arr自体も配列なのですが、$my_arrの一つの値である$my_arr[‘items’]、これもまた配列で、このfoaeachはこの$my_arr[‘items’]という配列を処理します。

$my_arr[‘items’]の中には、link や title、htmlSnippet といったキーが格納されていて、$value[‘△△△’]という書き方で、これらを順に取得し出力していくわけです。

ループの終わりに、$start++; で、スタート位置を1ずつ加算します。

【7】検索結果、次のグループの有無で処理を決める

foreachでの出力が終わりました。締めくくりとして、検索結果の次のグループがあるかどうかをチェックし、あればスタート位置をずらして次の処理を、なければ処理を終える、ということをしましょう。

<?php 
 if(isset($my_arr['queries']['nextPage'][0]['startIndex'])){  
 $start = $my_arr['queries']['nextPage'][0]['startIndex'];
 }else{
  break;
 }
?>

$my_arrにはAPIで取得した全データが、連想配列の形で入っています。【6】ではそのうち、itemsという配列データを使いました。ここではqueries という配列データを使います。

queries という配列の nextPage の最初の startIndex というキーの値を見にいきます。ここに値があれば(isset)、$start(取得開始位置)をstartIndexの値に変更します。

こうすることで、取得開始位置が次のグループにずれます。

[‘queries’][‘nextPage’][0][‘startIndex’] に値がなければ、「この検索結果はこれすべてよ」ということなので、breakで処理を終えましょう。

Share プリーズ
書き手は私

よろしければどうかご感想を!

※コメントは、サイト管理者による承認後、ページに表示されます。

あたたかい感想を書く

メールアドレスが公開されることはありません。

CAPTCHA


キタックCGSCコアメンバー

  • 樋口大輔
  • 小林将太
  • ちゃんまき
  • 高橋どらみ
  • 高橋皓一
  • 笠井
  • 石本
  • 佐藤サバ美
  • 佐久間尭