PythonでBlueskyのタイムラインと任意のポスト取得

BlueskyとAT Protocolを引き続き勉強中。
Pythonの勉強も同時並行で進めています。
ツッコミどころもあると思いますがよしなに。。。

今回は自分のアカウントのタイムラインを取得してみました。
仕様により最新から50投稿分しか取得できないのかも。

Flaskを使ってWebブラウザに表示してみたいと思います。

# 環境

OS macOS 14.2.1
Python 3.12.1
pip 24.0

AT Protocolと直接関係のない部分（HTMLやserver.py等）はこちらを参考にしてください
フォルダ・ファイル名はこちらに準じます。（この名前である必要はありません）

https://github.com/ynack/bsky_timeline.git

こちらも参考にしてください。

https://qiita.com/ynack/items/85ccf951727f8ac48c6c


# タイムラインの取得
ルーティング指定とメソッドの呼び出しを記述します。

```:.venv/bskytimeline/templates/views.py
from flask import render_template, request
from bskytimeline import app
from atproto import Client
from atproto_client.models.app.bsky.feed.get_timeline import Response

client = Client()
client.login('アカウント', 'パスワード')

@app.route('/')
def index():
    res = client.get_timeline()

    return render_template('bskytimeline/bsky_timeline.html', timeline = res)
```

初めの4行で必要なモジュールを読み込んでいます。
4行のうち下2行がタイムラインの取得に必要になります。

次の2行でAT ProtocolのClientクラスを初期化し、自身のアカウントでタイムラインを取得するためにログインしています。（自分のユーザ名とパスワードを入力してください）

*__@app/route('/')__*
ここからが呼び出されるメソッドです。
この場合、URL:Portにアクセスした場合、以下に書いたindex()メソッドを呼び出します。

*__res = client.get_timeline()__*
ログインしているユーザのタイムラインを取得して変数に代入しています。
get_timeline()のリミット値は50のようなので、最新から返信も含めて50個のポストが取得されます

*__return render_template('bskytimeline/bskay_timeline.html' timeline = res)__*
resに代入されているデータを「timeline」とい名前でbskytimelineフォルダ以下のbskay_timeline.htmlに渡します。


# タイムラインの表示
views.pyから渡されたデータHTMLとして表示します。
```:.venv/bskytimeline/templates/bskytimeline/bsky_timeline.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
    <h1>Bluesky タイムライン取得</h1>

    <p>{{ timeline }}</p>
</div>

{% endblock %}
```

*__{% extends 'layout.html' %}__*
*__{% block content %}__*
*__{% endblock %}}__*
HTMLの決まり文句の共通部分（\<!DOCTYPE html>等）を何度も書かなくて済むよう、layout.htmlにまとめて記述します。extendsで共通部分を読み込み、bock contentからendblockの間にこのファイルの内容を記述します。

*__\<p>{{ timeline }}\</p>__*
views.pyから受け取ったデータを表示します。
views.pyからはtimelineという名前でデータが渡されているのでそれをそのまま書きますが、pythonでデータを受け取る場合、{{ }}で囲います。
pタグはあってもなくても可。

これでサーバを起動させ、127.0.0.1:ポート番号等でブラウサからアクセスすればタイムラインの
生(?)データが表示れるはずです。

<img width="90%" alt="スクリーンショット 2024-02-17 19.52.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456861/b6e3b0ea-adeb-c2e1-8ffd-19c6878b4ec2.png">

# 特定のポストのみ取得
前項で取得したデータは画像の通りなので目がチカチカしてきますね。
この中の1つだけ取得できるようにしたいと思います。

views.pyの変数resはres.feedという形で配列のようにデータを取り出すことができます。
前項ではviews.pyからtimeline = resという形でbsky_timeline.htmlにデータを渡しましたが、
timeline = res.feedでも同じ結果が得られます。
これに添字を追記することで、特定のポストを取得することができます。
※ただし、timeline = res.feed[0]のような渡し方をするとエラーになるので、特定のポストのみ表示する場合は別途配列に代入した上で渡す必要があります。

今回はdict型の配列で渡します。

```:.venv/bskytimeline/templates/views.py(一部抜粋）
response = client.get_timeline()

tl = { 'feed': response.feed[0] }

return render_timelireturn render_template('bskytimeline/bsky_timeline.html', timeline = tl)
```

これで1つのポストだけ表示できます。
<img width='90%' alt="2024-02-18 13.42.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456861/22fe5fa5-ccc0-ce9a-1f40-3ae845f09553.png">

# 表示したいデータだけを表示させる
取得したポストの中から必要なデータだけを表示させることも可能です。
```:.venv/bskytimeline/templates/views.py(一部抜粋）
 tl = {
        'user': response.feed[0].post.author.handle,
        'did': response.feed[0].post.author.did,
        'icon': response.feed[0].post.author.avatar,
        'post': response.feed[0].post.record.text,
        'create': response.feed[0].post.record.created_at,
    }
```
dict型配列の中身を上記のように変えてみます。
上から
・ユーザ名
・ユーザのDID
・ユーザアイコンのURL
・投稿内容
・投稿日時
です。

bsly_timeline.htmlも以下のように変更します。
```:.venv/bskytimeline/templates/bskytimeline/bsky_timeline.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
    <h1>Bluesky タイムライン取得</h1>

    <p>{{ timeline.user }}</p>
    <p>{{ timeline.icon }}</p>
    <p>{{ timeline.did }}</p>
    <p>{{ timeline.post }}</p>
    <p>{{ timeline.create }}</p>
</div>

{% endblock %}
```
これでとても見やすくなりました。
<img width="100%" alt="スクリーンショット 2024-02-18 13.58.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456861/bc66c935-750e-7f61-17c3-b2b78c618d36.png">

そのほかにも「いいね」の数や、画像付き投稿であれば画像のURLやスケールサイズも表示できるようです。

今後はそちらも探っていきたいと思います。