Tweepyで作った画像を呟くBOTをGCPで定期実行させる（素人）


# 目次
1. [はじめに](#はじめに)
2. [TwitterAPIkeyを入手してTweepyでツイート](#twitterapikeyを入手してtweepyでツイート)
2.1 [TwitterAPIkeyを入手](#twitterapikeyを入手)
2.2 [Tweepyでツイート](#tweepyでツイート)
3. [GCPで定期実行](#gcpで定期実行)
3.1 [Cloud Functionにデプロイ](#cloud-functionにデプロイ)
3.2 [Cloud Schedularでデプロイしたプログラムを定期実行](#cloud-schedularでデプロイしたプログラムを定期実行)
4. [Cloud Function上にて画像つきでツイート](#cloud-function上にて画像つきでツイート)
4.1[Firebaseに画像を保存 その画像を読み取るkeyを生成](#firebaseに画像を保存-その画像を読み取るkeyを生成)
4.2[入手したkeyを用いて画像を読み取り一緒にツイート](#入手したkeyを用いて画像を読み取り一緒にツイート)
5. [参考にさせていただいたサイト](#参考にさせていただいたサイト)


# はじめに　
ド素人ですがTwitterのBOTを作成したので１から備忘録として書いておきます。
十分に説明できる能力があるか怪しいので、こんなことしたよ～といった記録的な感じです。


<font color="Red"> __注意点として__、</font>今回使っているGCPやFirebaseは従量課金のサービスとなっています。
新規Googleアカウントだとしばらくは無料枠が使えますが、プログラムを実行させる度に課金が進んでしまいます。

また、セキュリティに関する設定はほとんど触っていません。
そのため、最悪の場合だと
__改ざんされる→課金額が膨大になる__
となる危険性も考えられます。


参考にする際は自己責任でお願いします 。


# TwitterAPIkeyを入手してTweepyでツイート
(ここら辺は調べたら他に分かりやすい記事がたくさん出てきます）

### TwitterAPIkeyを入手
BOT用のGoogle・Twitterアカウントを作る。
(GCPやFirebaseを使うため、BOT用のGoogleアカウントがあった方が便利。GCP新規登録の無料枠も使える。)
(Googleアカウントを作る → そのアカウントでTwitterアカウントを作るのが楽。)

[Googleアカウント作成ページ](https://www.google.com/intl/ja/account/about/)
[Twitter](https://twitter.com/home)


TwitterDeveloperPlatformにTwitterアカウントでログイン・登録
メールアドレス・電話番号をTwitterアカウントに登録しておく必要あり
[Twitter Developer Platform](https://developer.twitter.com/)
<br>
登録できるとこんな風にkeyがもらえたが、ここのキーは使わない。
![スクリーンショット 2022-12-28 152828.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/e80cb7e2-5baf-b8cd-88bb-cc84ef75932a.png)
<br>
左のproject＆AppsからELEVATEDの申請
![スクリーンショット 2022-12-28 153537.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/a6efd90c-dfed-1a30-3103-add8ef023367.png)
色々と聞かれたが、適当に書いていいのか不明
酷いとELEVATEDを剥奪されたりするのかも
<br>

成功すると右上に"ELEVATED"の文字
![スクリーンショット 2022-12-28 154629.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/01af105a-a421-5528-9303-81d44c276965.png)
<br>

初めから作られているAppの設定をする
![スクリーンショット 2022-12-28 155422.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/1a695354-5c26-6595-bc3a-20f7d9e4120d.png)
![スクリーンショット 2022-12-28 160010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/bcf909cc-0c79-d64c-fb38-d34939e74e01.png)
<br>
ここは丁寧に入力した方が良さげ。
ただ今回は適当に遊ぶためだけなので何も考えず入力している。
![スクリーンショット 2022-12-28 160225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/1c720541-2820-521f-8286-46b3f9317216.png)
<br>
その後このRegenerateから各Keyが入手できる。
![スクリーンショット 2022-12-28 161157.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/693627a5-d6f7-87ed-2458-bc54cc528f90.png)

### Tweepyでツイート

入手したキーを使って簡単なプログラムを作成
```python:HalloWorld.py
#"Hello World"とツイートする
import tweepy
def get_twitter_api():

    #--------------------------------------------
    #ここを各々変える(↓のは例としてテキトーな英数字です)
    API_KEY = 'sadfhgkjhiuerg'
    API_SECRET = 'gjasgjas;lkgjasgjowi'
    ACCESS_TOKEN = 'fdgagadgdfgrjrjtj'
    ACCESS_TOKEN_SECRET = 'lhglytor6k'
    #--------------------------------------------
    auth = tweepy.OAuthHandler(API_KEY, API_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
    api = tweepy.API(auth)
    return api

api = get_twitter_api()
api.update_status('Hello World')
```

実行。ツイートできた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/fe07ef84-4531-5fc5-7a04-f5d679894a2a.png)

# GCPで定期実行

https://console.cloud.google.com/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/900f6c13-7562-0214-ef6b-cb7963ae969e.png)

### Cloud Functionにデプロイ
Cloud Functionを選択
![スクリーンショット 2022-12-28 175259.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/7c29c39f-89fc-7aaf-e372-96c0a6837d72.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/aa54f6de-2f45-3408-4f84-ef57ffa949c2.png)
有効にする
<br>

![スクリーンショット 2022-12-28 175612.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/88f5c195-b713-eb57-7051-1ce9d2b7826e.png)
関数の作成
・関数名　→　任意で設定
・トリガーのタイプ　→　Pub/Sub
・トピックを適当に名前を付けて作成、選択
<br>

![スクリーンショット 2022-12-28 180265.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/626bcfe4-5906-cc2a-c211-aa00d6ca7a8e.png)
ランタイム　→　今回はpythonを選択
ソースコード　→　インラインエディタ
エントリポイント　→　プログラムの開始位置(関数)

main.pyに実行したいプログラムを入れる。
```python:main.py
#デプロイ用
import tweepy
import random

def get_twitter_api():
    API_KEY = 'sadfhgkjhiuerg'
    API_SECRET = 'gjasgjas;lkgjasgjowi'
    ACCESS_TOKEN = 'fdgagadgdfgrjrjtj'
    ACCESS_TOKEN_SECRET = 'lhglytor6k'
    auth = tweepy.OAuthHandler(API_KEY, API_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
    api = tweepy.API(auth,wait_on_rate_limit=True)
    return api

def test(data,context):
    api = get_twitter_api()
    i = random.randint(0,1000)
    api.update_status('Hello World'+" "+f"{i}")
```
プログラムの開始位置として関数を指定する必要があるため、新しく関数を作っている。
__その関数の引数に(data,context)を与えておく__ ←今回1番嵌った
(トリガーがHTTPの場合は(request)を与える)
また、同じ内容のツイートを連続でするとエラーになるため1000までのランダムな整数を付け加えている。
<br>

requirements.txtの設定
![スクリーンショット 2022-12-28 182140.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/5960334b-fd16-2e54-41d1-5f160ccd7a20.png)
ローカルでプログラムを実行できたターミナルにて
```
pip freeze > requirements.txt
```
を実行したら生成されるのでそれをコピペ。

→デプロイ

失敗したら項目"ログ"から"ログエクスプローラーで表示"
ログ見ながらエラー修正して再度デプロイ
<br>

成功したら赤丸のようにチェックが付く
![スクリーンショット 2022-12-28 183129.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/dac3a890-b83c-9e98-a537-19413bad4bae.png)
<br>

デプロイに成功したら'テスト中'の項目の'関数をテストする'で実行
![スクリーンショット 2022-12-28 183309.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/83117e9b-ced9-186e-f5bb-bfb7cde6ad13.png)
<br>

![スクリーンショット 2022-12-28 183533.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/c016e9d0-ba65-386d-0082-bb61083c2fda.png)
うまくツイートできた。
<br>

### Cloud Schedularでデプロイしたプログラムを定期実行

左のメニューから'Cloud Schedular'を選択、ジョブを作成。
![スクリーンショット 2022-12-28 185438.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/804e32db-4f8d-4b87-eb15-3d48e1e9f6ca.png)
![スクリーンショット 2022-12-28 185638.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/ca097dc7-a725-ffda-fe20-7f55b9ca9888.png)
<br>

![スクリーンショット 2022-12-28 185833.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/d59ce4be-f68c-f7f8-4731-45edcab184e8.png)
名前　－　Cloud Functionの関数名と同じ必要あり??
頻度　－　cronコマンド形式で。今回は「* * * * *」で毎分実行するように設定
タイムゾーン　－　日本
ターゲットタイプ　－　Pub/Sub
トピック　－　Cloud Functionで作成、選択したトピックと同じやつ

入力し終わったら作成
<br>

このようにジョブが追加される
![スクリーンショット 2022-12-28 190543.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/5cdfa870-89e5-c44e-934a-94dfbffecb4b.png)


ツイートも問題なくされている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/fb6ad723-cf5c-59d1-b1f1-7fd07d9ea257.png)

# Cloud Function上にて画像つきでツイート
### Firebaseに画像を保存 その画像を読み取るkeyを生成

firebaseにGoogleアカウントを登録
https://console.firebase.google.com/


![スクリーンショット 2022-12-28 191353.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/4905f85e-d820-7f7b-0610-69aaf355a3db.png)
プロジェクトを作成しておく
<br>

メニューの構成→Storageを選択
![スクリーンショット 2022-12-28 191922.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/d9e81955-6d0e-fc48-8842-81e8457cbeab.png)
<br>

画像ファイルをアップロードしておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/6e96c3dc-3853-e81f-2832-e7df8f411d38.png)
<br>

Rulesを以下のように書き換え
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/62fd6dd5-a87a-f543-6add-d23adac9f19c.png)
```
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read;
    }
  }
}
```
__注意：このStorageは他ユーザーが見る・読み取ることを許可するように設定しています。
重要なファイルは置かないように__
<br>

ストレージ内のファイルを読み取るためのKEYを入手する。

左上のメニューからプロジェクトの管理→プロジェクトの設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/c62c3169-15b3-ec9b-c53f-0cfa4ce2ce31.png)
<br> 

pythonを選択して'新しい秘密鍵の生成'を押し、jsonファイルをDL
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/71b94d09-51e1-37d7-0cbf-86081ed02ad9.png)
<br>

### 入手したkeyを用いて画像を読み取り一緒にツイート



```python:pic_tweet.py
#このままデプロイ

import tweepy
import random
import firebase_admin
from firebase_admin import credentials
from firebase_admin import storage


def picDL():

    #投稿したい画像ファイル名を入れる
    fileName = "chipmunk-g5ada4a3c0_1920.jpg"

    #DLしたjsonファイル名を入れる
    credFilePath = "analog-medium-373008-firebase-adminsdk-ge0ro-dabc27337d.json"

    picPath = "/tmp/" + fileName
    cred = credentials.Certificate(credFilePath)
    default_app = firebase_admin.initialize_app(cred)

    #Storageのフォルダパスを入れる
    bucket = storage.bucket("analog-medium-373008.appspot.com", default_app)

    blob = bucket.blob(fileName)
    blob.make_public()
    blob.download_to_filename(picPath)

    return picPath

def get_twitter_api():
    API_KEY = 'sadfhgkjhiuerg'
    API_SECRET = 'gjasgjas;lkgjasgjowi'
    ACCESS_TOKEN = 'fdgagadgdfgrjrjtj'
    ACCESS_TOKEN_SECRET = 'lhglytor6k'
    auth = tweepy.OAuthHandler(API_KEY, API_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
    api = tweepy.API(auth)
    return api

def tweet(data,context):
     picPath = picDL()
     api = get_twitter_api()
     i = random.randint(0,1000)
     api.update_status_with_media('Hello World'+" "+f"{i}", filename = picPath)
```
<br>

#### プログラムの説明 

Storageのフォルダパスはこの部分
![スクリーンショット 2022-12-28 194810.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/996a3ae8-e25f-21cf-fce1-f2cc390deae4.png)
__'gs://'の部分は含めない__(4時間嵌った)

get_twitter_api() －　上のと同様

picDL()　－
firebaseのstorageのkeyを通して画像をtmpディレクトリにダウンロード
__Cloud Function上ではtmpディレクトリにしかDLができない__　←嵌った
そしてtmp内の画像ファイルのパスを返す

わざわざ一度DLする必要があるのかは分からない、絶対もっといいやり方がある。
課金が一気に進むのがこの部分なので気をつける。
<br>



上でやったのと同様にCloud Functionにブチ込む
![スクリーンショット 2022-12-28 201349.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/89ce84e0-b289-0730-4993-aa938904c436.png)
　↑　赤丸部分の＋から、firebase秘密鍵のjsonファイルを入力
<br> 

　![スクリーンショット 2022-12-28 201959.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/050ac2f7-16c8-9066-ce76-a48267847847.png)
requirements.txtの更新も忘れずに。デプロイして実行

ツイートできた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083922/659d3bd0-458b-1c1b-a34b-21ccfb930f45.png)

後は上と同様にCloud Schedularで定期実行してBOTの完成です。



# 参考にさせていただいたサイト
[【Python】苦闘、丸3日。Google Cloud Function (コード実行環境）を使って、Twitterの自動リツイートを実装した話。](https://qiita.com/naiveprince0507/items/a99bc1b52fca04858ff3)

[GCPでPythonプログラムを定期実行する【GCP/Python】](https://qiita.com/yyyyy__/items/5277dfa75e50c27dc032)

[Firebase: Cloud Firestore と Cloud Storage をPythonから使う](https://qiita.com/asu_mio_310/items/27db1746dffcf476fb42)