@kyanny's blog

My life. Opinions are my own.

はてなブログで書いた記事数と日数を数えるカウンターを AWS Lambda + Amazon API Gateway で作った

https://blog.kyanny.me/about や管理画面で見られる記事数と日数は、はてなダイアリーをインポートしたものと合算された数字になっている。はてなブログで書いた記事数と日数だけ別にカウントしたかったので、そういうのを作った。

  • https://blog.kyanny.me/about をスクレイピングして記事数と日数を取得する
  • はてなダイアリーで書いていた記事数と日数を引くと、お目当ての数字がわかる
  • その数字を公開する API を作り、 XHR で取得して整形して表示するブログパーツ的なスクリプトを設置する

以下の AWS Lambda 関数を作る。ランタイムは Ruby 2.5 を選んだ。数字を抜き出す正規表現はかなり雑(m オプションをつけてないので dd の行が複数行になるとマッチしなくなる)

require 'json'
require 'net/http'
require "uri"

def lambda_handler(event:, context:)
    # TODO implement
    s = Net::HTTP.get URI("https://blog.kyanny.me/about")
    e, d = s.scan(/<dd>(.*?)<\/dd>/).flatten.map(&:to_i)
    res = {
        entries: e - 1087,
        days: d - 724,
    }
    #{ statusCode: 200, body: JSON.generate(res) }
    { statusCode: 200, body: res }
end

API Gateway で先ほどの Lambda 関数をバックエンドとする API を作成し、デプロイする。 CORS を有効にするのを忘れずに。この API を GET すると JSON を返す。

$ curl -i https://pysw78m6qi.execute-api.ap-northeast-1.amazonaws.com/production
HTTP/2 200
date: Wed, 20 Feb 2019 17:11:27 GMT
content-type: application/json
content-length: 53
x-amzn-requestid: 8e6d862e-3532-11e9-968f-272bbd75e610
access-control-allow-origin: *
x-amz-apigw-id: VaKJxHCCNjMFXyw=
x-amzn-trace-id: Root=1-5c6d8a3e-f9ee779e09af7a1a42ea8256;Sampled=0

{"statusCode":200,"body":{"entries":1805,"days":905}}

はてなブログのデザインカスタマイズで、サイドバーに HTML モジュールを設置して、以下のコードを貼り付ける。

<script>
var xhr = new XMLHttpRequest();
xhr.responseType = "json";
xhr.addEventListener("load", function() {
  var entries = this.response.body.entries;
  var days = this.response.body.days;
  document.write("はてなブログをはじめてからの記事数: " + entries);
  document.write("はてなブログをはじめてからの日数: " + days);
});
xhr.open("GET", "https://pysw78m6qi.execute-api.ap-northeast-1.amazonaws.com/production");
xhr.send()
</script>

できあがり

f:id:a666666:20190221021211p:plain

キリ番とったらメールで通知したりする機能も増やしてみたい。 Lambda 関数の定期実行とかでできるだろうか。

はてなブログにブログパーツとして設置するだけなら、 AWS など使わず JavaScript だけでたぶんできる。 Same Origin なのでなにもせずに XHR が通るはずなので。でも、 API Gateway を使ってみたかったので、あえて回りくどいやり方にした。