6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

3ヶ月ほど前に使う機会があったGoogle Custom Search JSON APIの使い方をまとめた記事です。

手順

前提条件:

Googleアカウントを所持していること

1. 検索エンジンIDの作成

右上の追加ボタンをクリックします
スクリーンショット 2024-12-14 9.25.01.png

検索エンジン名を任意のものにします。
今回は特定のサイトのみの検索結果にし、https://qiita.comにして追加します。

特定のサイトは、複数サイトを選択することができ、論文のみの検索にするときためにはhttps://scholar.google.comhttps://www.openaire.euなどを複数追加するといいと思います。

スクリーンショット 2024-12-14 9.27.01.png

エンジン名と検索対象が追加できると同じ画面下の作成ボタンをクリックして作成!
作成が完了し、画面が変わるとカスタマイズボタンをクリック

概要ページで基本的な情報や、検索対象などを確認することができます。
検索エンジンIDは後でコード内で使用します。
スクリーンショット 2024-12-14 9.46.45.png

2. APIキーの取得

APIキーを作成します。上記のリンク内にあるキーを取得のボタンをクリックし

スクリーンショット 2024-12-14 10.05.50.png

Create a new projectでAPIキーを作成します。
スクリーンショット 2024-12-14 10.07.02.png

任意のプロジェクト名を入力しNextボタンをクリック
スクリーンショット 2024-12-14 10.08.50.png

作成が完了すると以下の画面が表示されます。
SHOW KEYをクリックしてAPIキーを表示することができます。
このAPIキーは後でコード内で使用します。
スクリーンショット 2024-12-14 10.10.26.png

実装

まず、プロジェクトのディレクトリを作成し、VSCodeで開きます。

mkdir custom_search_demo
cd custom_search_demo
code .

rootディレクトリmain.goを作成します。
main.goファイルは、Google Custom Search APIを利用するために、主に以下の機能を実装しています。

  • Ginフレームワークを使用したウェブサーバーの設定
  • 検索リクエストを処理するエンドポイントの作成
  • APIから取得した検索結果を返すロジック
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"

	"github.com/gin-gonic/gin"
	"github.com/joho/godotenv"
)

// SearchRequest は検索リクエストを表す構造体です
type SearchRequest struct {
	Query string `json:"query" binding:"required"`
}

// SearchResult は検索結果を表す構造体です
type SearchResult struct {
	Items []SearchItem `json:"items"`
}

// SearchItem は検索結果の各アイテムを表す構造体です
type SearchItem struct {
	Title   string `json:"title"`
	Link    string `json:"link"`
	Snippet string `json:"snippet"`
}

func main() {
	r := gin.Default()

	// エンドポイントの設定
	r.POST("/search", handleSearch)

	// ポートの設定
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	// サーバーの起動
	r.Run(":" + port)
}

// handleSearch は検索リクエストを処理するハンドラーです
func handleSearch(c *gin.Context) {
	// request body から検索クエリを取得
	var req SearchRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"リクエストが正しくありません": err.Error()})
		return
	}

	// Google Custom Search API を使って検索を実行
	results, err := performGoogleSearch(c, req.Query)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"ハンドラー内でエラーが発生しました": err.Error()})
		return
	}

	// レスポンスを返す
	c.JSON(http.StatusOK, results)
}

// performGoogleSearch は Google Custom Search API を使って検索を実行します
func performGoogleSearch(ctx context.Context, query string) (*SearchResult, error) {
	// env ファイルの読み込み
	err := godotenv.Load()
	if err != nil {
		fmt.Println(".envファイルの読み込みに失敗しました")
	}

	// Google Custom Search API のエンドポイントのsetup
	baseURL := "https://www.googleapis.com/customsearch/v1"
	apiKey := os.Getenv("GOOGLE_API_KEY")
	searchEngineID := os.Getenv("SEARCH_ENGINE_ID")
	if apiKey == "" || searchEngineID == "" {
		return nil, fmt.Errorf("APIキーまたは検索エンジンIDが設定されていません")
	}

	// エンドポイントを作成
	req, err := http.NewRequestWithContext(ctx, "GET", baseURL, nil)
	if err != nil {
		return nil, fmt.Errorf("エンドポイントの作成に失敗しました: %v", err)
	}

	// クエリパラメータを設定
	q := req.URL.Query()
	q.Set("key", apiKey)
	q.Set("cx", searchEngineID)
	q.Set("q", query) // 検索クエリ

	// URL にクエリパラメータをセット
	req.URL.RawQuery = q.Encode()

	// クライアントの作成
	client := &http.Client{}

	// Google Custom Search API にリクエストを送信
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("”リクエストの送信に失敗しました: %v", err)
	}
	defer resp.Body.Close()

	// Google Custom Search API からのレスポンスをチェック
	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("API からのレスポンスがエラーです: %s", body)
	}

	// レスポンスのデコード
	var searchResponse struct {
		Items []SearchItem `json:"items"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&searchResponse); err != nil {
		return nil, fmt.Errorf("デコードに失敗しました: %v", err)
	}

	// 検索結果を返す
	return &SearchResult{
		Items: searchResponse.Items,
	}, nil
}

コード補足

今回のデモでは使用していませんが、検索するものをソート(日付順)や言語などを細かく設定できます。
以下のリンクにそれらのリファレンスがあるので参考にしてください。

https://developers.google.com/custom-search/v1/reference/rest/v1/cse/list?hl=ja

プロジェクトの依存関係を初期化します。

  • go mod init demoでGoモジュールを作成
  • go mod tidyで必要な依存パッケージを自動的にダウンロードし、go.modファイルを更新
go mod init demo
go mod tidy

環境変数ファイル(.env)では、セキュリティを考慮して以下の情報を設定します。

  • GOOGLE_API_KEY: Google Custom Search APIにアクセスするための認証キー
  • SEARCH_ENGINE_ID: 特定の検索エンジン(この場合はQiitaサイト)用の識別子
.env
GOOGLE_API_KEY=api_key
SEARCH_ENGINE_ID=engin_id

動作確認

今回はPostmanで動作確認をします。

エンドポイント:POST

http://localhost:8080/search

リクエストボディー

{
    "query": "きーたん"
}

スクリーンショット 2024-12-14 23.09.44.png

こんな感じでqiita内で「きーたん」が出てくる検索結果を取り出すことができます。

おわりに

Google Custom Search JSON APIは、検索したいドメインなどを絞ることによってwebサービスやスクレイピングなどに活用できるとても使い勝手がいいAPIです。是非皆さんも試してみてはいかがでしょうか?

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?