エンジニア寿司を支える技術

この記事ははてなデベロッパーアドベントカレンダー 2015の15日目の記事です。昨日は id:nobuoka による UWP アプリ開発に TypeScript + React を導入することの検討 (Node.MSBuild.Npm の紹介) - ひだまりソケットは壊れない でした。


こんにちは、はてなの id:motemen です。普段はコードを書くかたわら、チーフエンジニアとして社内エンジニア向け制度の取り仕切りも行っています。

弊社では、寿司と勉強会とエンジニア - Hatena Developer Blog で紹介されている通り月に一度、はてなブックマークで注目された技術エントリをたたえ寿司を食べるというイベントを催しています(あくまでレクリエーションの一環で、評価などには響きません)。個人的には「毎月寿司」と呼んでいます。

さて、はてなにも新しいエンジニアがどんどん加入し、月づきに話題にのぼるエントリも増加してきました。寿司をはじめた頃は月初に記憶を呼び起こしたり、各人のブログを再チェックしたりして前の月のエントリの集計を行っていたのですが、そろそろこの運用では立ちゆかなくなってきました。そこで最近は Google Spreadsheet を使い、シートに話題になったエンジニアのエントリを追記していくことで集計の手助けとしています。流量は多くても一日に数件で、技術エントリが話題になれば必ず誰かしらの目につくので、そのタイミングで記入するという温かみのある運用でじゅうぶんスケールします。いちシートがひと月になっているので、ふり返りにも便利です。

エントリのメタ情報を取得する

これだけではただのメモですが、シート上に次のようなエントリのメタ情報も自動的に展開するようにしていて、一覧集計をより簡単にしています。使用するのは Google Spreadsheet の関数たちです。

  • タイトル
  • 著者名
  • ブックマーク数

f:id:motemen:20151215135247p:plain

タイトル

記事タイトルのの抽出には、IMPORTXML関数を使用します。これは任意のウェブ上の構造化データからXPathでデータを取りだすものですが、名前とはうらはらに対象が厳密にXMLのフォーマットである必要はないようで、一般的なHTMLのtitleタグの内容も、以下のように抽出できました。

=IMPORTXML(A2,"//title")

A2はエントリURLのセルです)

著者名

記事の著者の抽出にもおなじくIMPORTXML関数が使えます。はてなのエンジニアはだいたいはてなブログを個人ブログとして使っているので、HTML構造を仮定できます。著者名とははてなIDのことにほかなりませんが、これは以下のXPathで取得できるようです(はてなブログチームに確認せず勝手にスクレイピングしているので、今後もこの方法が使えることを保証しません)。

=IMPORTXML(A2,"//span[@class='author vcard']")

はてなブログの記事下部に表示される著者情報ですね。ちなみにmetaタグにも著者情報がありますが、こちらはブログのオーナー情報であり、あなたが今まさに読んでいるこのブログのように、複数人で書くようなブログには適しませんでした。

はてなブックマーク数

記事についたはてなブックマーク数の取得には、はてなブックマーク件数取得APIが利用できます。以下のURLではてなブックマーク数をプレーンテキストとして取得できる、非常にシンプルなAPIです。

% curl http://api.b.st-hatena.com/entry.count?url=http%3A%2F%2Fwww.hatena.ne.jp%2F
5594

こちらは、CSVやTSVをインポートするIMPORTDATA関数で取得します。プレーンテキストの数字は1行1セルのCSVってわけですね。

IMPORTDATA("http://api.b.st-hatena.com/entry.count?url="&SUBSTITUTE(A2,"#","%23"))

こちらのAPIは便利なものですが、ドキュメントにあるとおり以下ご注意ください(Google SpreadsheetのAPIは結果を一定期間キャッシュするようです)

過度なリクエストはサーバーの過負荷ならびにサービスのレスポンス低下に繋がりますので、繰り返しリクエストされる場合は、リクエスト毎に数秒の間隔をあけていただくなど、サーバーリソースの節約にご協力ください。

せっかくなので、セルをはてなブックマークのエントリページにリンクしてしまいましょう。HYPERLINK関数を使います。

HYPERLINK("http://b.hatena.ne.jp/entry/"&A2, IMPORTDATA("http://api.b.st-hatena.com/entry.count?url="&SUBSTITUTE(A2,"#","%23")))

これで前掲のスクリーンショットのような、リッチな表示が実現できました。

その他の対策

以上はあくまではてなブログ上のエントリ向けであり、9割の用途はカバーできますが、想定しないURLが現れた場合には都度対処するほかありません。とはいえコンスタントに良エントリを書く人向けにはきちんとアドホックな対策を入れてますよ!

さきほどのエントリ著者のセルを編集します。URLを雑に検索して、著者が想像できそうなURLならアタリをつけるという処理にします。

=IFERROR(IF(SEARCH("songmu.", A2), "Songmu"),  IMPORTXML(A2,"//span[@class='author vcard']"))

これで自作ブログを使っているエンジニアのエントリ情報もキャッチできますね! ぼくはこれをSongmu対策と呼んでいます。

おわりに

エンジニアを支える毎月寿司が、高度な技術と試行錯誤によって支えられていることが分かっていただけたのではないかと思います。

ところで、そろそろ寿司も飽きてきたなってことでSlackでアンケートしてみました。

f:id:motemen:20151215114517p:plain:w400

来年は餃子になりそうです!!!

明日のアドベントカレンダーは id:yashigani_w です! お楽しみに!