見出し画像

はてブロ oembed を使ってブログのタイトルと投稿者を GAS で取得する

こんにちは、はてブロ (はてなブログ) を使っていますか?
Google Apps Script で はてブロ oembed を使って、はてブロの URL からブログのタイトルと投稿者を取得してくる仕組みを実装しましたので備忘として残します。

ユースケース

弊社のテックブログは はてブロ Pro でホスティングされていまして、各エンジニアやたまに営業が、個人のアカウントを連携して自分の書きたい記事をアップしています。

各人がそれぞれ好きに書けて気楽に使えるのは非常にありがたいことですが、2023 年 7 月現在、300 以上の記事が投稿されていて、Google Analytics 4 (GA4) で誰が何本のブログを書いていて、どれぐらい見てもらえているのか?など集計が難しい状況でした。

GA4 で URL は取得できるため、URL をベースにタイトルと投稿者の情報を機械的に取得してくることにしました。

はてなブログ oEmbed API

以下に仕様が記載されています。

リクエスト制限などは見つけられませんでしたが、本スクリプトを Sleep 無しで回すと BAN されました。会社の IP から行うと迷惑をかけてしまうので、ご自宅でお試しください。

  • Sleep を入れずに回したら 11 回目で 404 エラー

  • 1 秒 Sleep を入れても 11 回目で 404 エラー

  • 9 回目で 3 分の Sleep を入れて回したところ成功

以下、関数を使うと JSON 形式のデータが戻ります。

function getUrlResponse(strUrl) {
  var response = UrlFetchApp.fetch('http://hatenablog.com/oembed?url=https://' + strUrl);
  strContents = response.getContentText();
  jsonContents = JSON.parse(strContents)
  console.log(jsonContents);
  return jsonContents;
}

getUrlResponse("https://hatenablog.com") といった形で投げます。戻るデータは以下のような形です。

{ author_url: 'https://blog.hatena.ne.jp/otanikohei/',
  description: 'こんにちは、AWS チームの尾谷です。今日は、Amazon EFS のクレジットの検証を行いましたのでブログとしてアウトプットしたいと思います。',
  width: '100%',
  blog_url: 'https://techblog.forgevision.com/',
  image_url: 'https://cdn-ak.f.st-hatena.com/images/fotolife/o/otanikohei/20230607/20230607084353.png',
  categories: [ 'AWS', 'Amazon EFS' ],
  blog_title: 'ForgeVision Engineer Blog',
  provider_name: 'Hatena Blog',
  title: 'Amazon EFS の最適なスループットモードは?',
  html: '<iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftechblog.forgevision.com%2Fentry%2Fefs-throughput-mode%2Fabout" title="Amazon EFS の最適なスループットモードは? - ForgeVision Engineer Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe>',
  version: '1.0',
  author_name: 'otanikohei',
  type: 'rich',
  provider_url: 'https://hatenablog.com',
  published: '2023-06-10 09:01:51',
  url: 'https://techblog.forgevision.com/entry/efs-throughput-mode/about',
  height: '190'
}

以下のような形でセルに入力します。

// 関数
response = getUrlResponse(strUrl);

// 入力
sheet.getRange("B" + r).setValue(response.title);
sheet.getRange("C" + r).setValue(response.author_name);

category とか page という特殊ページを除外する

あと、苦労したところで言うと、GA4 が抽出してくる category とか page といった URL は 404 エラーになります。これらの URL をリクエストした際に、ブロックされているのかエラーなのかがすぐに分かりませんでした。
以下のような正規表現の分岐を入れて対応しました。

if (strUrl.match(/\/category\//) != null || strUrl.match(/\?page=/) != null) {
    sheet.getRange("B" + r).setValue("-");
    sheet.getRange("C" + r).setValue("-");
}

コード

こんな感じです。リクエストした際に int_counter で、9 回目で 3 分待機して、22 回目で 6 分待機させています。

function myFunction() {
    var spreadsheet = SpreadsheetApp.openById('スプレッドシートの ID');
    const sheet = spreadsheet.getActiveSheet();

    var lastRow = sheet.getRange(sheet.getMaxRows(), 1).getNextDataCell(SpreadsheetApp.Direction.UP).getRow();
 
    int_counter = 0;
    for (let r = 2; r <= lastRow; r++) {

      strUrl = sheet.getRange("A" + r).getValue();

      if (strUrl.match(/\/category\//) != null || strUrl.match(/\?page=/) != null) {
        sheet.getRange("B" + r).setValue("-");
        sheet.getRange("C" + r).setValue("-");
      }
      strTitle = sheet.getRange("B" + r).getValue();

      strAuthor = sheet.getRange("C" + r).getValue();

      if (strTitle == "" || strAuthor == "") {
        obj_response = getUrlResponse(strUrl);
        int_counter++;

        if (strTitle == ""){
          sheet.getRange("B" + r).setValue(obj_response.title);
        }
        if (strAuthor == ""){
          sheet.getRange("C" + r).setValue(obj_response.author_name);
        }
        if ((int_counter % 22) == 0) {
          Utilities.sleep(300000);
        } else if ((int_counter % 9) == 0) {
          Utilities.sleep(180000);
        }
      }
    }
}

以上です。

この記事が気に入ったらサポートをしてみませんか?