今回は自作プログラム勉強手帳です。Pythonを使ってRSS更新があれば、Blueskyに投稿するプログラムを作りましたよって話です。
成果物
予め成果物を示しておきますね。
ここに出来上がったものがあります。
一応、機能拡張は目論んでいますが、最低限の機能だけ実装しています。
コード自体はそれほど難しいものではなく、基本文法さえ押さえていれば書けますし、もしかしたらもっと賢いコードかけるかも知れない。その時はぜひプルリク送ってください。
【変更】
* 実行してみたら、古い順番で記事が投稿されたので、それを修正する変更を加えました。
アジェンダ
今回の記事は、大きく「プログラムの使用説明」「Blueskyへの投稿」「RSSの取得と差分考慮」という3つに分けて記述しています。目次機能を使って必要なところだけ見て言ってもらえればとおもいます。
考えた仕様
考えた仕様としては、crontabを利用して数時間おきに更新通知を実行することを前提としたプログラムです。常時取得するのが理想ではあるのですが、使っているサーバーがラズパイで常時プログラムが回るのがなんか嫌なので。大体1〜10時間程度おきに動作するように設定するつもりです。
RSSフィードはhttps://nishikiout.net/feed
で配信されているのでこれを利用し、タイトル・リンク・サマリーとはてなブログ全体のエントリーに振られているユニークIDを利用します。仕様がはてなブログに準拠しているので、はてなブログ+bsky.appの組み合わせの場合、ほぼURLを差し替えるだけで使えるはずです。
という感じ。
事前準備
認証情報の取得
プログラムの開発の前にアカウントの認証情報だけ確認しておきましょう。多分、Blueskyへのログインに使っているパスワードでも今回のプログラムの動作自体は可能だと思いますが、アプリ用パスワードを作成した方が安心しますね。
Blueskyのサイドバーにある「設定」を開き、若干下の方にある「アプリパスワード」をクリックすると、アプリパスワードを作る事が可能です。「Add App Password」を押してパスワードを控えておきましょう。
パッケージのインストール
今回は、AtProtocolとFeedparserを使いますので、予めインストールをよろしくお願いします。
pip install atproto pip install feedparser
Blueskyへの投稿
Blueskyへの投稿は、AtProtocolと同じように扱えるらしいですが、そもそもAtProtocolを触るのが今回が初めてなので、調べながらやりました。
まず、プレーンテキストを送信するコードを示します。
これだけでとりあえず、Blueskyへの投稿自体が可能です。ACCOUNTにはアカウントを、PASSWORDには先程取得したアプリパスワードを代入しておきましょう。もしGitなどで管理するなどがあれば環境変数を活用しましょう。
環境変数の使い方はこちら(GitHubのコードはこの方法で環境変数を別で管理しています)。
リンク付き投稿
Blueskyでは残念ながら、リンクから自動でカードを作ってはくれないようです。Web版でも自動でカードを作るボタンを押す必要があります。そのため、プレーンテキストにURLを含んだものを投稿したとしても、そもそもハイパーリンクすら貼られないという状態になりました。
なので、今回はリンクカード付きで投稿するプログラムにしています。
このように記述すると、リンクカードが埋め込まれます。
なんとなくおわかりいただけるかと思いますが、9~11行目を変更すれば、自由にリンクカードを作ることが可能です。この点ではかなり融通が効きます。自動でするなら、リンク先をスクレイピングして、Twitter向けのmetaタグを取得するのがいいと思いますが、今回はRSSフィードに全部書いてあるのでそれはしません。
フィードの受け取り
さて、ここからはRSSフィードの解剖について見ていきます。
フィードを受け取る
もう面倒なので、フィードを受け取って使いたい形にするfeedparse.pyの中身を全部見せて解説します。と言っても難しいことは全くしていません。
parse_feed
関数は、引数で受け取ったフィードのURLから取得したエントリの「タイトル」「リンク」「説明」「投稿日時」「ユニークID」をエントリごとにクラスに格納して、取得したエントリのクラスが格納されたリストを戻す関数です。
feedparserのおかげでフィードの扱いはとても簡単で、35行目でfeedparseによって形式を変換したもの使いやすいように変換してくれます。
あとは、for分を回してエントリごとにさっきクラスに格納すると言った各項目を取得するのみ。そして、クラスNH_entry
は、基本的にデータの保持しかしていません。
投稿差分を考慮する
feedparserは便利ですが、前回の確認から、今回の確認の間に投稿されたエントリだけを取得したいという要望には答えてくれません。つまり、前回と今回の投稿の差分を自ら確認する必要があります。
私は、前回の確認時点で最新の「ユニークID」をテキストファイルに保存しておくという方法を取っています。今回のプログラムの場合だと、基本的に最新から順番にエントリを取得していきますので、IDを照らし合わせて、前回の確認時点で最新のエントリのIDと一致すれば、そこで読み込みをやめるというプログラムになっています。もっと賢い方法はあると思いますが、私はこの方法でしました。
その確認をis_post
関数でしています。この関数ではもう一つ、確認時点から1日以内であることも確認しています。これは、何らかの影響で長い期間に渡って確認が行われなかった際の復旧時に、大量に投稿されることを防止するために実装しています。
〆
今回は、feedparserを使ってRSSをいい感じに整形して、AT ProtocolのPython向けのパッケージを使ってBlueskyに自動で更新通知を投稿するプログラムを作りました。
役に立つかはわかりませんが、いずれ私の役に立つので書いておきます。
AtProtocolを使ったとはいうものの、別にプロトコルをガッツリ意識する必要もなく、ちょっと変わったWebhookを使ってるな感覚でこのレベルなら書くことができます。