実装者向けの記事です。
「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で処理を終えましょう。
よろしければどうかご感想を!
※コメントは、サイト管理者による承認後、ページに表示されます。