面倒な調査をGoogle検索APIで解決した話

### 本記事について
[ジーズアカデミー Advent Calendar 2022 カレンダー2](https://qiita.com/advent-calendar/2022/gsacademy
)の18日目の記事です。
昨日17日目は[@ykiyoshima](https://qiita.com/ykiyoshima)さんの[「ジーズで作った課題をドヤ顔で紹介したい」](https://qiita.com/ykiyoshima/items/ccb7caf2c52ac71792db)でした！
彼の作品は音楽への愛に溢れていて、技術も素晴らしく、発表の度に感動していたのを覚えています。
特にJavaScriptメモパッドアプリの課題発表での衝撃はいまだに忘れられません。
記事も読んでほしいですが、GitHubを公開してくれてますので、皆様ぜひ作品に触れていただいて、その衝撃を味わっていただきたいです。
さて、本記事では面倒なメタ情報の調査をGoogle検索APIを使って解決した経緯や方法についてお話しします！


### 誰のための記事？
「競合サイトのコンテンツ調査が面倒だと思っている方」
「SEO対策のキーワード調査が面倒だと思っている方」
「調査の時間を減らして頭で考えたり、構想を練る時間が欲しい方」

### 自己紹介
靴の販売員から真逆のことに挑戦したいと思い、法人向けの営業支援会社へ転職。
コールセンターやMAツールなどの立ち上げに参賀した後、通販のデータサイエンス部署へ転職。
2021年4月G's ACADEMY FUKUOKA 週末集中コースに入学。同年10月卒業。
2022年3月より、UXリサーチャーとして流通小売業界の開発を担う会社へJOIN。
直近はWebやアプリの体験設計に携わる。

### 面倒な調査をGoogle検索APIで解決した話
UXリサーチャーのお仕事では定性調査だけでなく定量調査もあります。
ユーザーの体験設計をする初期の段階で、仮説を立てたり、ユーザーセグメントを検討するために、市場調査や競合調査を行います。
この記事を読んでいる方も、何かの企画やサービスを立ち上げる際、市場調査や競合調査を行われたことがあるのではないでしょうか？
皆様、調査めんどくさくないですか？比較サイトが元々存在するような企画なら多少調査は楽ですが、ググってはGoogleSpreadSheetに貼り付けてを繰り返す作業がめんどくさい！と思った方いらっしゃるのではないでしょうか？お気持ちお察しいたします(私もめんどくさいです！)
SEO対策用の有料ツールなどもありますが、調査の頻度もそこまで高くなく、手軽にできるならやりたい、と思い、Google検索APIでメタ情報を取得してみました。
Google検索APIを利用し、GoogleSpreadsheetに入力されたキーワードに基づいて、Google検索結果の上位１０サイトのtitle、URL、discription、h1、keywordの出現数を取得&書き出しています。
メタ情報はSEO対策はもちろんですが、titleからはどんなワードで検索してほしいか、普段検索されているワードは何か、discriptionからはこのサービスを一言で言うと何か、つまりこのコンテンツは誰の何のためのものなのかを伺い知ることができます。
例えばUdemyのtitle、discriptionを見てみます。
titleとdiscriptionはググった時に表示されるこれです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1695131/09e39f54-9129-5d2e-4c96-d579f3ab2d95.png" width=80%>

title:オンラインコース - いろんなことを、あなたのペースで | Udemy
discription：Udemyは、学びたい人、教えたい人のためのオンラインのマーケットプレイスです。プログラミング、マーケティング、データサイエンスなど、213000以上のコースを5,700万人の受講生が学んでいます。

Udemyは学習プラットフォームサービスです。titleからは「オンラインだから自分のペースで学習できる」、discriptionからは「誰の」（学びたい人、教えたい人)、「何のための」（オンラインマーケットプレイス）が把握できます。そして「213000以上のコースを5,700万人の受講生」とあるので、実績もわかりやすいです。この後にUdemyの競合にあたるpaizaやSchooのtitle、discriptionを比較してみると面白いですよ。このように競合のサービスを分析でしてみるといろんな発見があります。
競合調査で使ってみたい方、興味を持っていただいた方はぜひお試しください。

-  注意事項
    - 自然検索の結果のみを取得します。リスティング広告は取得できません。
    - Web検索結果と取得した結果が若干異なります。参考：https://support.google.com/programmable-search/answer/4513751?hl=ja   　　　　
- 事前準備
Google検索APIキー、カスタム検索エンジンIDの取得については以下のサイトを参考にしました。
https://plus-pm.jp/blog/search-rank-check-use-google-custom-search-api/
- ロジックと実行
GoogleSpreadSheetの拡張機能>Apps Scriptを選択して以下のコードを事前準備で取得した、Google検索APIキー、カスタム検索エンジンID、任意のSpreadSheetのシート名を更新、調査したいワードをSpreadSheetに入力&実行すればOKです。
```javascript
<function getSearchData(){

  //GoogleSpreadSheetから設定情報を読み込む
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName('search'); //search部分はSpreadSheetの任意のシート名に置き換えてください。
  var word = sheet.getRange(3,2).getValue(); //入力されるキーワードの位置を指定してください。
  //上位10件のデータを取得後の結果表示範囲をD8〜J18にしていますが、ご自由に移動してください。
  //既存データの削除
  sheet.getRange(8, 5, 10, 6).clearContent();

  //事前にGoogle検索APIのキー、ID情報を取得しておく
  var apiKey = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; //apiキーを入力してください
  var apiUrl = 'https://www.googleapis.com/customsearch/v1/';
  var query  = '?q='+ encodeURIComponent(word);
  query += '&cx=' + 'XXXXXXXXXXXXXXXXXXXXXX'; //カスタム検索エンジンID
  query += '&key='+apiKey;

  apiUrl = apiUrl + query;

  var response = UrlFetchApp.fetch(apiUrl);
  if (response.getResponseCode() !== 200) {
    throw new Error('エラーのため取得できませんでした');
  } else {
    var res =  JSON.parse(response);
  }

  //データを取得する
  try {

    //データシートを取得する
    var sheet = spreadsheet.getSheetByName('search');//search部分はSpreadSheetの任意のシート名

    //1位から10位のタイトル名
    var titles =[];
    var i = 0;
    for (i = 0; i <10; i++) {
      titles.push([res.items[i]["title"].toString()]);
    }
    sheet.getRange(8,5,10,1).setValues(titles); //配列で書き込む

    //urlを取得する
    var urls = [];
    for (i = 0; i < 10; i++) {
      urls.push([res.items[i]["link"].toString()]);
    }
    sheet.getRange(8,6,10,1).setValues(urls); //配列で書き込む

    //概要を取得する
    var snippets = [];
    for (i = 0; i < 10; i++) {
      snippets.push([res.items[i]["snippet"].toString()]);
    }
    sheet.getRange(8,7,10,1).setValues(snippets); //配列で書き込む

  } catch(e) {
    return e.toString();
  }

  //各htmlからデータの取得ループ実行
  for (var i = 8; i <= 17; i += 1) {
    var url = sheet.getRange(i, 6).getValue();
    try{
      var response = UrlFetchApp.fetch(url);
      var html = response.getContentText('UTF-8');
      var html = html.toLowerCase();
      //文字コードを分岐し、Shift-JISの場合読み直し
      if ( html.indexOf('shift_jis') != -1){
        var sjs = response.getContentText('Shift_JIS');
        //キーワードの出現数をカウント
        var countNum = ( sjs.match( new RegExp( word, "g" ) ) || [] ).length ;
        //h1を取得
        var h1 = sjs.match(/<h1.*>(.*?)<\/h1>/)[1];
        //メタキーワードを取得
        var keywords = sjs.match(/keywords.*.content="(.*?)">/)[1];
      } else {
        //キーワードの出現数をカウント
        var utf = response.getContentText('UTF-8');
        var countNum = ( utf.match( new RegExp( word, "g" ) ) || [] ).length ;
        //h1を取得
        var h1 = utf.match(/<h1.*>(.*?)<\/h1>/)[1];
        //メタキーワードを取得
        var keywords = utf.match(/keywords.*.content="(.*?)">/)[1];
    }
    } catch(e){}
    //取得結果をそれぞれの箇所に格納
    sheet.getRange(i, 8).setValue(h1);
    sheet.getRange(i, 9).setValue(keywords);
    sheet.getRange(i, 10).setValue(countNum);
  }
  Browser.msgBox("入力されたキーワードの上位10サイトのデータ取得が完了しました。");
}
```
- 結果
「プログラミングスクール」というkeywordで実行すると以下のような結果が返ってきます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1695131/5d6ca641-6b15-9725-2f4f-443259303010.png" width=80%>

最後までお読みいただきありがとうございました。
カレンダー1の[12日目](https://qiita.com/broccolibroccolibroccoli/items/6f56e089b53e50182af7)にも記事を書いていますので、そちらも併せて読んでくださったら嬉しいです。

明日と明後日、19日目20日目のカレンダー2の枠が空いています！ぜひ読んでくださったG's関係者の皆様、バトンをつないでくださると嬉しいです！