はてなブックマークにノイズが多いのでオレオレはてなブックマーク「Neo's Hatebu」を作った

二度と視界に入れたくない記事。


僕は iPhone の「はてなブックマーク」アプリを見るのが日課なのだが、最近どうにもこうにも、見たくない話題に関する記事がホットエントリを占めるようになっていて、気分が乗らない。BTS とかいう知らない連中がどうしたとか、フェミニストがワーワー言ってるとか、そういうことはマジで興味がない。エントリ一覧でタイトルが見えるだけで不愉快になる。興味のない情報は一切視界に入れたくない。

しかし iPhone の「はてなブックマーク」アプリには NG 機能がない。外部サービスやブラウザのアドオンとしては NG 機能を実現するモノもあったのだが、自分が思ったそのものズバリなモノがなかったので、今回自分で作ってみることにした。その名も 「Neo's Hatebu」

(こういうのって所有格の「s」でいいのかいつも気になっているけど、2002年に「Neo's World」というサイトを立ち上げてしまったばっかりに、僕が作るモノは全て「Neo's」と付いている。)

Neo's Hatebu のサイトは以下のリンクより飛べるが、残念ながら皆様はこのウェブサービスを利用できない。僕しか使えないアプリなのだ。つまり今回の記事は一方的な報告に終始するのであしからず。

一応、環境さえ自分で作ればコピーサイトを立ち上げられるよう、Fork の手順だけ紹介しておく。

目次

はてなブックマークの記事をフィルタリングしたい

はてなブックマークの「新着エントリ」「人気エントリ」はどうも「はてブ特有の流行り」を感じていて、はてブ民がブコメで文句を書きたくなる記事が偏って現れることが多い。これがどうも不快で、その中に紛れている、自分が興味のあるエントリを見つける際のノイズになっている。

はてブ公式には、ユーザ単位での NG 機能はあるようだが、特定のワードなどでフィルタリングする機能は提供されていない。ネットで色々探してみると、はてなフィルターというウェブサイトがあり、コレはクッキーでフィルタしたいワードや URL を設定できるようだ。やりたいことはかなりコレに近いのだが、クッキーを使っている都合上、端末やブラウザが違うと設定が無効になる。僕は iPhone メインではてブを見るのだが、PC で見た時もノイズを減らしたいので、NG 設定はサーバサイドに持たせておく必要があった。

他に何かないかと思って探してみると、Firefox や Chrome の拡張機能で実現するモノが見つかった。

ブラウザ拡張機能なら、Google アカウントなり Sync アカウントなりに情報が同期されたりするかな?と思ったが、iPhone の Firefox・Chrome ブラウザでアドオンを使うことはできないので、これも却下。

やっぱり自分ではてなブックマークをコピーして、サーバサイドに NG 設定を保存できるような Web サービスを作るしかないか…。と思い至って、作った。

Neo's Hatebu アプリの概要

Neo's Hatebu は最近のブラウザで閲覧できる Web サービスとして立ち上げた。

トップページに遷移するとログイン画面が表示される。前述のとおり、このサイトは僕しかログインできない。

スマホでのログイン画面

僕がログインすると、最初は「総合 - 人気」カテゴリのエントリ一覧が表示される。この時、エントリ一覧は NG 設定した記事を除外した状態で表示されている。

記事一覧

ちなみに、PC で見るとこんな感じ。

PC 表示

で、各記事のサムネイル下に「削除する」というボタンがあり、コレを押すとエントリ一覧からその記事が消える。

削除するボタン

同時にサーバに「削除した記事の URL」を送っている。削除した記事の URL はフィルタ対象として記録され、以降二度とエントリ一覧に表示されなくなる。コレで、一度見かけた記事は二度と視界に入れなくて済む。

1カテゴリを見終わったところ

「削除する」ボタンで削除した記事は、サイドメニューより「NG URL 設定」画面に飛ぶと確認できる。

サイドメニュー

1日で全カテゴリに目を通すと、だいたい4・500件ぐらいの URL がココに溜まる。

削除したページの URL たち

以上で URL 単位でのフィルタリングはできるようになったが、流行りの話題で色々なページがヒットするのが気に食わない場合は、「NG ワード設定」を利用する。ココに除外したいキーワードを入れておくと、そのキーワードがタイトルや本文に含まれているエントリをフィルタリングできる。「豊洲市場」の話題全般もう知りたくない、と思えば、「NG ワード」に「豊洲市場」を入れておけば良い。

NG ワード

また、ホッテントリによく登場するが、一向に興味のない話題ばかり取り上げるブログサイトなんかが特定できていれば、「NG ドメイン設定」に追加する。https://hoge-blog.com/ みたいな URL を登録しておくと、その URL が含まれる記事をフィルタリングできる。

見たくない URL

一度見た記事は「削除する」ボタンより「NG URL」として登録してエントリ一覧から消していき、話題やサイト別に二度と見たくないモノは「NG ワード」や「NG ドメイン」に設定していく、というワケ。エントリ一覧を開いたら、記事タイトルを見ながら「削除する」ボタンをバンバン押していって、エントリ一覧が0件になるまで見まくるのだ。気に入らない話題が最初から視界に入らないし、一度見た記事は二度と出てこなくなるので、「消化した感」が得られて気持ちが良い。

サイトの使い勝手としてはこんな感じ。

ちなみに、一度ログインしたユーザのログイン情報は LocalStorage に記録されるので、再アクセスした時にその情報を利用して自動的に再ログインしてくれる。自分で明示的にログアウトするか、LocalStorage を削除するまでは、ログイン画面に戻ることなくアプリに戻れるというワケ。すんなりと自動再ログインできるのは我ながら便利だ。

バッチ処理も作った

Neo's Hatebu に表示されているエントリ一覧は、公式の Web ページをスクレイピングし、DB に投入して保持している。このスクレイピングの処理は、朝・昼・夜と1日3回実行するように設定したので、出社時の通勤電車内、昼休み中、帰りの電車内のタイミングで、新着エントリ (それもノイズ記事を除外した状態で!) を閲覧できるようになっている。

また、「削除する」ボタンを押下すると「NG URL」情報がサーバに溜まっていくのだが、コレが1日で4・500件くらいになる。ホッテントリも新着エントリも、だいたい4・5日もすればその記事は出てこなくなるから、「NG URL」情報を何ヶ月も溜めておく必要はない。そこで、スクレイピングを行うバッチ処理と同時に、「NG URL」情報を蓄えている DB から、登録日時が5日以上前のデータを一括削除するように設定した。

なお、Web アプリ上からでも強制的にスクレイピングさせたり、古い「NG URL」情報を一括削除したりする機能は用意してあるので、自分の好きなタイミングで、スケジューリングしたジョブと同等の操作を行えるようにしてある。

より技術的な話

サイトの見た目と、バックエンドの表面的な内容は以上のとおり。ココからはもう少し具体的な、技術的な話。

それぞれの内容で個別に1記事書けるぐらいにアレコレ試行錯誤したので、さらなる詳細は別記事にしていこうと思う。

Neo's Hatebu の Fork の仕方

今回作った Neo's Hatebu だが、一般公開するつもりはない。Heroku の無料枠に留めておきたいのが主な理由だ。お金は出したくない。

しかし、ソースコードは全て GitHub に公開しているので、皆様も Heroku の無料アカウントを取得して、GitHub リポジトリを Fork してちょっとだけ設定すれば、このアプリのクローンを作れる。使ってみたい方は、こんな Web アプリで良ければ、以下の手順で Fork してご利用ください。

  1. Heroku アカウントを取得し、Heroku プロジェクトを作成する
  2. Heroku Postgres アドオンをインストールする
  3. Heroku に以下の環境変数 (Config Vars) を設定する
    • DATABASE_URL : Herkou Postgres が自動設定
    • PGSSLMODE : allow
  4. Neo's Hatebu の GitHub リポジトリを Fork する
  5. client/environments/environment.prod.tsserverUrl に、取得した Heroku プロジェクトの URL を設定する
  6. Heroku プロジェクトに git push する
    • Web アプリ起動時に動作する Sequelize の sync() メソッドによって、Heroku Postgres 上に必要なテーブルを生成させる
  7. practices/insert-master-data.js 中の INSERT INTO useres 文に、ログインユーザの名前とパスワードの MD5 ハッシュ文字列を記述する
  8. $ node practices/insert-master-data.js を実行し、users テーブルと categories テーブルにマスタデータを投入する
  9. Heroku アプリにアクセスしてログインしてドウゾ!
  10. エントリ情報を定期的に自動更新するには、Heroku Scheduler アドオンをインストールし、任意のタイミングで $ node bin/crawl.js を実行するようジョブを設定する

はてブ公式ページをスクレイピングしているため、今後はてブの仕様変更により動かなくなる可能性は多分にある。あんまりこのアプリを Fork してバンバンリクエスト投げてスクレイピングしないように注意…。だから自分は Heorku Scheduler で1日3回に絞ってるのです…。Web アプリ上からもスクレイピングさせるボタンを作ってはあるけど普段は使わないのです…。

以上

2018年11月6日に「よっしゃ Heroku + Node.js (Express + Angular) で作るか」と思いたち、GitHub リポジトリを作って Heroku アカウントを登録した。1日3時間くらいこねこねしていって、2018年11月11日にひととおり動作する状態で Heorku にデプロイした。ということで初回リリースまでの開発期間は6日、実作業時間でいうと20時間程度となる。

その後もデザイン調整や操作性の向上などをチマチマいじり続けているものの、最低限やりたかった当初の目的を実現するのは1週間程度でなんとかなった、ということだ。

今回はサーバサイドもそれなりにいじれたし、セッション管理とかにも手を出してみたので、未経験な分野を個人開発で経験できたかなーと思う。勿論、express-session の本番利用はメモリリークの危険性があったりして推奨されておらず、一般公開する Web サービスではよりセキュアな実装が求められるワケだが、今回そうした課題を発見することができて良かったと思う。サーバサイドはまだまだだ。もっと勉強しよう。

Heroku を触ったのも初めてだったので、クラウドサービスにも興味が湧いた。実務で Azure や AWS にほんの少しだけ触る機会はあるのだが、個人開発では触ったことがなかったので、せめて無料枠内でできることはやってみようかな、と思った。

処女作にしてはやりたいことを全部詰め込めたし、自分一人が使うなら十分なモノになったので、まぁまぁよしとする。

参考

今回はてブをスクレイピングしてなんやらかんやらするサービスを作ろうと思った時に参考にした文献。各ライブラリの細かな使い方とかについては、今後詳細な記事を書こうと思うので、その時に紹介する。