指定のキーワードを含むバズツイートに「いいね」をしているユーザーを抽出し、各ユーザーの最新ツイートに「いいね」をする。

:::note warn
警告
この記事にはTwitter社が禁止している「自動いいね」の内容が含まれます
https://help.twitter.com/ja/rules-and-policies/twitter-automation
:::

# この記事に書かれていること

Twitterを眺めていると、集客目的でTwitterを運用している方をよく見かけます。
自分のプロフィールに誘導することを目的に「いいね」を押して回っているのか、私もよく知らない人に押されます。

その人の「いいね」の一覧を見ると、自分のツイートに含まれていたキーワードと同じキーワードを含むツイートにいいねが押しているので「あ、指定のキーワードでツイートしている人を自動でいいねしてるんだな」と察したりします。
この方法でもある程度は効果が出そうですが、以下のデメリットがあるかなと思っています。
- 指定のキーワードで発信しているユーザーしか対象にできない
- いいねの対象が露骨に現れる

今回の記事に書いていることは、指定したキーワードのツイートにいいねするのではなく、
指定したキーワードのツイートに「いいね」をしているユーザーの最新ツイートに「いいね」をすることです。

この方法では以下のメリットがあります。
- 対象について発信はしないが興味は持っている潜在層にリーチできる
- 外側から見て「いいね」の規則性がわからない

実際に知人から上の要件で依頼されたので手伝ったのですが、
この記事内では例として「キータ観光」という旅行会社のTwitterアカウントが集客を目的に、旅行に興味を持っているユーザーに「いいね」をして回るケースで説明します。

# やること

- 「旅行」&&「航空券」のキーワードでツイートを検索
    - 「最新のツイート」ではなく「話題のツイート」で検索
    - APIの上限である100件を取得
    - リプライは除外
- 検索結果からいいね1000件以上のツイートに絞る
    - 質を担保するために1000件以上のいいねが集まっているプチバズツイートを対象にする
    - 5〜7件ほどに絞られる
- それらのツイートにいいねをしたユーザーを取得する
    - 各ツイートにつき上限の100ユーザーを取得
    - 500〜700ユーザーのリストができる
- 各ユーザーの最新ツイートにいいねをする
    - 大量にいいねをするとBANされる可能性があるので、ランダムで40ユーザーに絞っていいねをする
    - リプライは除外する（会話にいいねをするのは不審なため）
- この処理を1日3回実行する


# 事前準備

- APIの利用申請が必要です
- 加えてElevated（高度なアクセス）の利用申請も必要です

https://di-acc2.com/system/rpa/9688/

https://tensei-shinai.com/2022/04/27/twitter-api-elevated/

# コード

```
root
├ config.py
└ main.py
```

### config.py

複数アカウントを管理するために認証に使う設定を切り出しています。

```config.py
import os
from dotenv import load_dotenv
load_dotenv()


class Config_API:
    NAME = ''
    API_KEY = ''
    API_SECRET = ''
    ACCESS_TOKEN = ''
    ACCESS_SECRET = ''
    BEARER_TOKEN = ''

    def __init__(self, name):
        self.NAME = name
        self.API_KEY = os.getenv('API_KEY_{}'.format(name))
        self.API_SECRET = os.getenv('API_SECRET_{}'.format(name))
        self.ACCESS_TOKEN = os.getenv('ACCESS_TOKEN_{}'.format(name))
        self.ACCESS_SECRET = os.getenv('ACCESS_SECRET_{}'.format(name))
        self.BEARER_TOKEN = os.getenv('BEARER_TOKEN_{}'.format(name))
```

<details><summary>拡張について</summary>

今後「いいね」だけするアカウント、「リツイート」もするアカウントと分けて管理する必要が出た場合、以下のように拡張すると便利です。

```config.py
import os
from typing import Any
from dotenv import load_dotenv
load_dotenv()


class Config_API:
    NAME = ''
    API_KEY = ''
    API_SECRET = ''
    ACCESS_TOKEN = ''
    ACCESS_SECRET = ''
    BEARER_TOKEN = ''
    FAV = Any
    RETWEET = Any

    def __init__(self, name, fav, retweet):
        self.NAME = name
        self.API_KEY = os.getenv('API_KEY_{}'.format(name))
        self.API_SECRET = os.getenv('API_SECRET_{}'.format(name))
        self.ACCESS_TOKEN = os.getenv('ACCESS_TOKEN_{}'.format(name))
        self.ACCESS_SECRET = os.getenv('ACCESS_SECRET_{}'.format(name))
        self.BEARER_TOKEN = os.getenv('BEARER_TOKEN_{}'.format(name))
        self.FAV = fav
        self.RETWEET = retweet
```
</details>

### main.py

```main.py
import tweepy
from config import Config_API
import random
import time


# いいねして回るアカウントの一覧
accounts = [
    {'キータ観光 新宿本店': {'name': 'SHINJUKU'}},
    {'キータ観光 大阪支店': {'name': 'OSAKA'}},
    {'キータ観光 仙台支店': {'name': 'SENDAI'}},
]


for account in accounts:
    user_name = list(account.keys())[0]
    values = list(account.values())[0]
    config = Config_API(values['name'])

    # 認証
    auth = tweepy.OAuthHandler(config.API_KEY, config.API_SECRET)
    auth.set_access_token(config.ACCESS_TOKEN, config.ACCESS_SECRET)
    api = tweepy.API(auth)

    # クライアントを作成
    client = tweepy.Client(
        config.BEARER_TOKEN, config.API_KEY, config.API_SECRET, config.ACCESS_TOKEN, config.ACCESS_SECRET
    )

    # キーワード検索（話題ツイート）
    search_keywords = ['旅行', '海外']
    search_result = api.search_tweets(q=search_keywords, include_entities=False, result_type='popular', count=100)

    # 1000いいね以上のツイートのリストを作成
    SET_FAV_CNT = 1000
    tweet_id_list_to_extract_users_who_have_fav = []
    for tweet in search_result:
        # リプライは除外
        if tweet.in_reply_to_status_id is not None:
            continue
        if tweet.favorite_count < SET_FAV_CNT:
            continue
        tweet_id_list_to_extract_users_who_have_fav.append(tweet.id)

    # いいねしたユーザーを集める処理
    users_who_have_fav = []
    for id in tweet_id_list_to_extract_users_who_have_fav:
        res = client.get_liking_users(id).data
        for user in res:
            users_who_have_fav.append(user.id)

    # ランダムに並び替える
    random.shuffle(users_who_have_fav)

    # ユーザーそれぞれの最新ツイートをいいねして回る処理
    MAX_NUM_OF_TIME_TO_FAV = 40
    fav_count = 0
    for user in users_who_have_fav:
        if fav_count >= MAX_NUM_OF_TIME_TO_FAV:
            break
        # リプライとリツイートを除く最新ツイートを取得
        user_tweets = api.user_timeline(user_id=user, exclude_replies=True, include_rts=False, count=1)
        if len(user_tweets) == 0:
            continue
        latest_tweet = user_tweets[0]
        # ランダム秒数待機
        time.sleep(random.randint(1, 10))
        client.like(latest_tweet.id)
        fav_count += 1
        print("{} が 「{}」 というツイートをいいねしました".format(user_name, latest_tweet.text.replace('\n','')))

```

# デプロイ

この程度のスクリプトならHerokuが一番楽かなと思います。

https://qiita.com/1-row/items/80f89c8ada2e61f04446

https://qiita.com/seigo-pon/items/ca9951dac0b7fa29cce0

# おわりに

冒頭にメリットを書きましたが、ターゲットがたまにズレるというデメリットもあります。
例えばジャニーズタレントの「海外旅行に行きました〜」というツイートを拾った場合、旅行に興味を持っているユーザーではなくジャニーズのファンにいいねをして回ることになります。

これは実際に運用しながらキーワードの選定やフィルタリングの調整が必要そうです。
やや面倒ですが、比較的APIのルールがゆるいTwitterが自動いいねを禁止する意味を考えると「いいね」はそれほど大きい影響力を持っていると考えられますので、本気で集客を考えるならここはサボらずに向き合う必要がありそうですね（自己責任で）