twikitをLambdaで動かしてみる

Twitterの投稿を取得してMisskeyに流すコードをAWS Lambdaで動くようにしてみました。

# twikitとは

twikitについてはこちら（開発者様のQiitaです）

https://qiita.com/a_f1/items/342ad5fb7db2b4f907fe


# 環境
・Windows11
・Python 
・AWS Lambda


# アップロードファイルの作成

## 1. 外部ライブラリのインストール
requirements.txtを作成し、pipインストールを実行します。

```requirements.txt
twikit
requests
```

```PowerShell<!--.-->
pip install -r requirements.txt -t .
```

## 2. lambda_function.py の作成

全体的なコードはこちらを参考にさせていただきました。

https://zenn.dev/joulli/articles/2a2172331c6aac


```lambda_function.py
import os
import json
import requests
from twikit import Client

def lambda_handler(event, context):

    twitter_username = os.environ['TWITTER_USERNAME']
    twitter_email    = os.environ['TWITTER_EMAIL']
    twitter_password = os.environ['TWITTER_PASSWORD']

    # 言語指定
    client = Client('ja')

    # アカウントにログイン
    client.login(
        auth_info_1 = twitter_username ,
        auth_info_2 = twitter_email,
        password    = twitter_password
    )

    ### 最新ツイートを取得
    user = client.get_user_by_screen_name(twitter_username)
    tweets = user.get_tweets('Tweets', count=1)

    for tweet in tweets:
        print(tweet.text)

    # count=1にしていても20件取得されてしまうので最新のみ指定
    tweet_text = tweets[0].text


    if not tweets:
        raise Exception("No tweets found")

    ### Misskey認証情報
    mk_access_token = os.environ['MK_ACCESS_TOKEN']

    ### 投稿前準備完了
    print("投稿準備")
    print(f"投稿用テキスト: {tweet_text}")

    ### Misskeyへの投稿
    misskey_url  = "https://misskey.io/api/notes/create"
    misskey_headers  = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {mk_access_token}"
    }
    payload = {
        "text": tweet_text,
        "visibility": "home" #ホーム投稿にしたいため
    }


    # リクエスト内容をログに出力
    print("Posting to Misskey...")
    print(f"URL: {misskey_url}")
    print(f"Headers: {misskey_headers}")
    print(f"Payload: {json.dumps(payload, indent=2)}")

    misskey_response = requests.post(misskey_url, headers=misskey_headers, json=payload)

    if misskey_response.status_code == 200:
        print("Misskeyへの投稿が成功しました。")
    else:
        print("Misskeyへの投稿が失敗しました。")
        print(misskey_response.text)
        misskey_response.raise_for_status()

    print(misskey_response.text)
    print("投稿スクリプト完了")
    
```
Twikitではcookieが使用できますが、Lambdaで実行する場合エラーが出るので今回は使用していません。
（その代わり実行するたびにTwitterにログイン通知が来ます…）


## 3. zip化

フォルダ体系（例）
![スクリーンショット 2024-06-10 191709.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812570/5e4d1156-b436-5772-01dd-314defa7836a.png)


PowerShellより以下コマンドでzipファイルに固めます。
```PowerShell<!--.-->
Compress-Archive -Path .\* -DestinationPath upload.zip
```


## 4. AWS Lambda

次に、コードを動かすLambda側の設定をします。

「一から作成」を選択
関数名：[お好みで命名してください]
ランタイム：Python（今回はPythonを使用するため）
アーキテクチャ：x86_64
その他はデフォルトのまま
「関数の作成」を押下
![スクリーンショット 2024-06-10 163615.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812570/605a5be0-4246-5d9c-2203-e9b1beb31f66.png)


Lambda関数が作成されました。
直接編集が可能ですが、今回はPythonの外部ライブラリを使用するためここでコードの編集はしません。
![スクリーンショット 2024-06-10 164333.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812570/05195035-20d9-ebc5-edfc-1192d4e4af4c.png)

:::note warn
外部ライブラリをインポート後は、AWS上のエディタで編集をしデプロイを行ってもエラーを吐きます。
コードを修正した際は再度zipファイルに圧縮し、後述の手順で再アップロードをします。
:::

環境変数を作成します。（画像はtwikitの場合）
値にはMisskeyトークン、TwitterのID（@以降）、メールアドレス、パスワードを設定します。
![スクリーンショット 2024-06-10 192721.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812570/b6234c43-74f8-971c-185a-2f679cb26214.png)


アップロード元 > zipファイル を押下し、作成したzipファイルをアップロードします。
![スクリーンショット 2024-06-11 002718.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812570/49baa570-5379-28fc-020f-e52f1bf2d173.png)

![スクリーンショット 2024-06-11 001851.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812570/985b9a9b-ce9e-f3e5-0404-dbfff70d87a5.png)


twikitの場合はここで「テスト」を押下すれば即時実行されます。
![スクリーンショット 2024-06-11 010334.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812570/8cf002f1-646b-4eef-27da-9a587fd37c4f.png)

:::note info
タイムアウトエラーが出る場合
設定 > 一般設定 よりタイムアウト時間を変更して再実行
![スクリーンショット 2024-06-11 011319.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812570/ac967207-cfa2-83ab-4a4a-782a5e030cd9.png)

:::

今回は実装していませんが、定期的に実行したい場合は下記が参考になりそうなので置いておきます。（気力があったら実装したい）

https://qiita.com/daisuke_ishii/items/b6a5abb74384c9ed16c9


# おわり

IFTTTでBotを運用しているので代用策としてtwikitを試してみました。

twikitではストリーミングはできないそうですが、一定期間ごとに取得するのであればEventBridgeでできると思います。

twikitを実行するとその度ログイン通知が来るので、できればcookieを使いたいのですがLambdaだと`"errorMessage": "[Errno 30] Read-only file system: 'cookies.json'"`というエラーが出ます。

cookies.jsonの保存場所を指定できればzipに含めて持っていく…とかできるのかなと思ったんですがどうなんでしょうかね