ひさしぶりにがっつりプログラムをした3連休でした。
困っていたこと
はてなのアクセス解析とトップページの数値って、過去になるとわからなくなるんですよね。
こことか、
こことか
この画面、翌月1日の0時になると数値が0になります。月末の最終日の23時に現場を抑えないと、その月の数値が二度と取れないのです。 正確な数値が欲しい場合、月の最終日の夜にPCに張り付いてスクショをとるしかないわけです。忘れてしまったら無しです。
これはつらいです。人間がPCと時間に縛られるのは悲しい。
ということで、
「自動でPCの画面のスクショをとるプログラム」を作成しました。
作ったもの
はてなブログ管理画面の以下の2つの画面のスクショを自動でとるスクリプトです。
- はてなのサマリーの数値
- はてなのアクセス解析のページ
画面の余計な部分は除き、欲しいエリアをキャプチャーします。
さらに、撮ったスクショ画像に日付を入れてCloudinaryにアップロードします。
今回は、はてなブログを題材にしましたが、ブラウザを自動操作してキャプチャーをとる仕組みなのでいろいろと応用が効くと思います。
実際の作成した画像
こんな感じです。
管理画面
アクセス解析画面
これを毎日、自動で保存していきます。
動作の設計
今回は、node.js(JavaScript)で作られたバッチプログラムです。
処理の流れは、
- はてなブログの管理画面にログインします。(ログインのIDとパスワードが必要です)
- ログインしたあとは、管理画面のトップページのサマリー部分のキャプチャーをとります。
- そのあと、アクセス解析のページに遷移をしてアクセス解析のグラフ周辺をキャプチャーします。
- キャプチャーしたものをCloudinaryにアップロードします。
transformation
パラメータをセットすることで変換しつつアップロードできます。
CloudinaryはHeroku対策です。
Herokuを使うと自分で作ったファイルを置いておくことができず、再起動のタイミングで捨てられてしまします。作ったらすぐに外部ストレージに飛ばしておかないといけません。
せっかくなので、Cloudinaryの文字オーバーレイの仕組みを活用して撮影日を画像に書き込んでいます。
ちなみに、Windows環境で動かすだけならCloudinaryはなくても大丈夫です。
使ったもの
いつもどおりWindows環境で開発しました。
- Windows10
- node.js (v16.9.1)
- puppeteer
- Cloudinary (node.js SDK)
最終動作環境はHerokuの予定です。
コード
コードはこちらに置いてあります。100行くらいです。
https://github.com/kanaxx/hatena-autocapture
ローカルでの動かし方
簡単に動かし方をかいておきます。
# 好きなディレクトリに移動して、コード持ってくる(必要なのは2つだけ) cd xxx git clone https://github.com/kanaxx/hatena-autocapture.git # モジュールをインストール cd hatena-autocaputure npm install # 環境変数の設定(windowsはダブルクオート不要) # CLOUDINARYを使わないときは何もセットしなくてOK set hatena_id= set hatena_pass= set blog_admin_url= set CLOUDINARY_URL=cloudinary:// # 実行 node hatena-autocapture.js ログがたらたら出て終わります
完了すると、captures
フォルダにファイルが出来上がります。
環境変数
4つ必要な設定があるのでset
コマンドでセットする
変数名 | 内容 |
---|---|
hatena_id | ログイン用のID。はてなIDでもメールアドレスでもOK |
hatena_pass | パスワード |
blog_admin_url | ブログ管理画面のトップページURL。最後のスラッシュまで*1 |
CLOUDINARY_URL | Cloudinaryの環境変数。 CLOUDINARY_URL=cloudinary://xxx:yyy@zzz*2 |
はまったところ
ネットを調べながら作りましたが、日本語の資料も充実していたので、プログラム自体はそんなに難しくなかったです。 初めてPupetterを使ってので、少しだけハマりどころがありましたのでメモしておきます。
ログインができなった
はてなへの最初のログイン部分がうまくいきませんでした。Windows上で動かすとうまくいったのに、Herokuで動かすと全くといっていいほどうまくいかなかったです。
仮説ではあるのですけど、
- UserAgentを指定していなかったので、機械的なアクセスとみなされた
- 日本国外のIPアドレスからのアクセスだった怪しまれた
IPアドレスは変更できないので、ダメ元でUserAgentを明示的に付けてみたら、うまくいきました。謎です。
await page.setUserAgent( 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 ');
そんなこともあるんだ。まぁ、そんなもんです。
サイトが英語表記になる
Herokuからアクセスしてみたら、ログイン画面が英語で返ってきました。
普段使っているブラウザが日本語設定なので、日本人がこの現象に出くわすことは少ないですが、スクショをとってみたら英語だったので驚きました。
英語表記のはてなアクセス解析画面
はてなブログも複数言語のユーザを想定して外国語対応をしていたわけですね。知りませんでした。
おそらくAccept-Languageの設定を見て出し分けているのだろうと思い、以下の2か所に指定したら上手くいきました。
//puppeteerのlaunchにlangオプションを指定 args: ['--no-sandbox', '--disable-setuid-sandbox', '--lang=ja-JP,ja'],
//Accept-Languageヘッダーとユーザエージェントを指定 await page.setExtraHTTPHeaders({'Accept-Language': 'ja'});
キャプチャーが取れたり取れなかったり
完全に表示するまえにキャプチャーとっちゃってるときがある。無駄にスリープする感じにしたら、今のところうまくいった。
(マニュアルを読む限り、この指定はいらないみたいだけど)
await page.waitForTimeout(1000);
たまにログインが失敗する
いつもなるわけじゃないんですけど、ログイン失敗することがあります。スクショがこの画面になりました。
理由は不明だけど、はてな側の不正ログイン対策ですね。機械的なログインを何らかの判断基準によって弾いていると。
当初は完全に諦めていましたが、5回くらいログインを繰り返すようにプログラムを修正しました。5回やってダメだったらその日は諦めるロジックにしました。
ログインユーザを分離しておく対策
このスクリプトは、はてなにログインするために「ログインID」と「パスワード」を使います。
プログラム上に書く必要はないですが、システムのどこかに設定するということは、わずかにでも漏洩する可能性が発生します。 自分がメインで使っている「はてなID」と「パスワード」が漏れる大変です。急いでパスワードを変更しなくてはいけせんし、はてなの他のサービスを乗っ取られることになります。
メインアカウントだとブログ管理者になれてしまうので、ブログを丸ごと削除できてしまいます。 そうなるとと被害が甚大です。
そのための対策を少々しておきます。
完璧な対応ではないです。何かあったときの被害を最小に抑える対応です。
ブログメンバーの追加
はてなブログには「ブログメンバー」機能があります。他のはてなユーザを管理画面にアクセスできるようにし、共同編集ができる機能です。
この機能を使って、メインとは別のユーザ(サブ)を追加しておきます。サブのIDとパスワードでプログラムを動かすようにします。
仮に何か良くないことが起きていた場合には、ブログメンバーから外すだけでブログ管理画面にログイン不可にできます。
追加メンバーには「管理者」、「編集者」、「寄稿者」と3つの設定があります。 試したところ、今回の作業に必要なブログトップとアクセス解析を見るためには、少なくとも編集者である必要がありました。
なので編集者で登録しておきます。
はてなサブアカウントの追加
ブログメンバーに追加する際に、共同編集者の「はてなID」を指定する必要があります。
はてなIDを複数作ることもできますが、自分のメインアカウントの下にサブアカウントをぶら下げることができるので、それで対応します。
サブアカウントは5つまで作れるので、うまいこと使いわけてください。
さいごに
HeadlessブラウザであるPuppeteerを初めて使ってみました。 プログラムでブラウザを動かすのは大変だと思っていましたが、それほど難しくなかったですね。環境構築も難しくなかったです。
ただ、ブラウザをプログラム側から動かすので、どうしても癖というやコツが必要になります。その辺は慣れていくしかないんでしょうね。
今回はWindowsで動作確認まで。次回はHerokuに乗っけてガンガン回していく予定です。
参考にしたページ
ヘッドレス Chrome Node API 「Puppeteer」
https://qiita.com/bezeklik/items/c6448d50ff0efb45829e
HerokuにPuppeteerの実行環境を構築する
https://qiita.com/jerrywdlee/items/ffc988956eb75a99bc3c
はてなブログで「サブアカウントの作り方」
https://www.elppar.com/un-hatena-subaccount
*1:https://blog.hatena.ne.jp/kanaxx43/kanaxx.hatenablog.jp/
*2:Cloudinaryのダッシュボードに表示されているやつ