この記事では、Speaker Deck上にアップロードしたスライドのページビュー(以下PV)を1日毎に収集し、日付ごとのPVをグラフとして可視化する仕組みをPythonで開発したことについて説明する。
目次
スポンサードリンク
背景
私が勉強会の発表スライドを共有する時、サービスはSpeaker Deckを使っている1。
meow (@meow_noisy) on Speaker Deck
Speaker Deckを使っていて不便な点はいくつかあるが、その中の一つに1日毎のPVが記録されていない点がある。これがないために、どういうタイミングで何のスライドがどれだけ閲覧されているのかを分析できない。
したがって、1日でPVがどれだけ溜まったかを可視化するためにSpeaker Deck用のPVログ収集 & 分析する仕組みをコストを抑えて構築することにした。
アーキテクチャ
speakerdeckからPVを取得して可視化するまでの仕組みの全体像を先に示す。
区分けとしては下記の部分に分けられる
- Speaker DeckのページからPVを取得しファイルに保存する部分
- スクレイピングをAWS Lambdaで行い、S3へ格納する部分
- PVを記録したファイルからレコード単位に変換しDBに格納する部分
- DBからレコードを取得し、PVをグラフとして可視化する
実装したコードは下記のリポジトリに配置している。
以下ではそれぞれの技術要素を説明する。
PVのスクレイピング部分
Speaker Deckにはスライドに関するメトリクスを取れるようなWebAPIもなければメトリクスのファイルダウンロード機能も提供されていない。したがって、ユーザがアップロードしたスライドページのスクレイピングを行い各スライドのPVを収集した。
ローカルでスクレイピングを実行するコードはリポジトリのscrape_speakerdeck_pv.py に該当する。PVを取得したいSpeaker DeckのURLをこのスクリプトに書いた上で、$ python scrape_speakerdeck_pv.py
を実行すると、result
ディレクトリを作成し、その中にスクレイピング結果のtsvファイルを書き込む。
取得対象は、スライドのユニークID(Speaker Deck側が勝手に付与), スライドのタイトル名、PVである。
これを、次のようなフォーマットでtsvファイルで保存する。ファイル名は取得した日付にしている。
たとえば、2021-08-05.tsv
は下記のような内容である。
ad7b2a026bd74e00a2c3915043c7eecb Security Days Spring 2021のOSINTに関する講演4つの簡易まとめ/os_int_webinars2021spr 438 b9cb90f9e11845c9afe619a61c64798b 初心者向けOSINT CTF! Cyber Detective CTFに挑んだ!/cyber_detective_ctf 291 891f7fb535e14a54a85ee8792f734063 画面共有時にセンシティブな情報を意図せず公開してしまう事例の調査/sharing_screen_and_confidential_data 195 ...
もちろん過去のPVは取得できないので、スクレイピングを開始した日からのロギング開始となることに注意されたい。
FaaSによるスクレイピングの定期実行
上記のスクレイピングをかつては手動のトリガーでやっていたがいい加減面倒だったので自動化した。
毎日1回定期実行といえばcrontabが第一に考えられるが、我が家には常時起動しているマシンはないためランニングコストを考慮してFaaSであるAWS Lambdaを使った。tsvのファイルの格納先はS3としている。
まず、LambdaにはS3を参照できるように権限を付与する。
次に実行するPythonの関数を登録する。Lambdaで実行する関数を含むスクリプトはリポジトリの lambda.py に該当する。これをコピーしてLambdaの関数として登録する。
スクレイピングに使用するrequests
、BeautifulSoup
はLambdaのPythonランタイムにはインストールされていないので、レイヤーを作成する。レイヤーの作成の仕方はAWS公式サイトの手順を参考にした。レイヤー作成時に気をつける点としては、python/lib/python3.8/site-package
という構造でパッケージを格納する必要があることである。
この関数を1日1回定期実行するように設定する。すると、S3の指定バケットにtsvが格納される。
あとは、そのバケットを $ aws s3 sync
でローカルと同期すればよい。
Lambdaのエラー通知
Lambdaでエラーが起きた時にSlackに通知が飛ぶようにした。アラートの流れとしては、Lambda→CloudWatchAlarm→SNS Topic→AWS Chatbot→Slackである。これは下記のブログ記事を参考にさせていただき実装した。記事の通りSlackへのアラートをとても簡単に構築できた。
tsvファイルをレコード単位に整形しDBへ挿入
tsvは日付ごとの各スライドのPVが記載されているが、これを各スライドごとの日付ごとのPVに変換してDBに格納する。
これらの作業はAWS GlueとRDSを使えば完全にAWS上で運用することができるが、ランニングコストがばかにならないのでローカルの方にDBを構える。
DBには手軽さを考えてSQLiteを使用した。
DBのER図は下図の通りである。slideテーブルでスライドを、slide_pb_dateテーブルでその日のスライドのPVを保持する。
このスキーマに沿うようにtsvファイルの各レコードを整形し、DBに挿入する。
この処理はリポジトリの insert_records_into_sqliteDB.py に該当する。
$ python insert_records_into_sqliteDB.py
を実行すると、DBにレコードを挿入してくれる。
PlotlyでPVを可視化
この時点で、DBにはスライドに対して日付ごとのレコードが入っている。これをグラフでプロットする。インタラクティブにグラフを操作したかったため、Jupyter Notebookを立ち上げて、Plotlyで可視化する。
これはリポジトリの visualize.ipynb をJupyter Notebookを立ち上げればよい。
あとは、最後までコードを実行すると、下図のように各スライドの日付ごとのPVが可視化される。また、UIを操作すれば、スライドごとのPVを比較することもできる。
おわりに
Speaker DeckのPVをロギングし、可視化する仕組みをなるべくコストを抑えて実現する方法について説明した。
自分で溜まったログを可視化した感想としては非常に役立っている。急上昇しているスライドがあった時、何が原因でそうなったのかを調べるのが楽しい。また、今日はPVが増えていないと思っていてもグラフで見ると1つ増えているのがわかったりする。
このようにグラフを確認することで、次の発表へのモチベーションにしている。
スポンサードリンク