抽選botの作り方

· ☕ 4

昨日作った抽選botの解説とコード公開します!

最新のコードはこちら

抽選botの詳細はこちら

仕組み

前回のbotの進化系です。

以下の動作を10分置きに繰り返します。

抽選botの抽選ツイートを取得

既にリプライ済のツイートに再度リプライしないように、まず、自分のしたツイートを取得する。

安定稼働してきたら、このプログラムの履歴を信じて、あえて毎回twitterから取得しなくてもいいんだけど、今は信用ならないので、毎回取得しなおす。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    # botのツイートを取得
    # botのツイートを取得
    doneList = requests.get(
        f'https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name={SCREEN_NAME}&count=10',
        auth=getOauth()
    ).json()
    if "errors" in doneList:
        print(doneList)
        return
    doneList = list(map(lambda x: x["in_reply_to_status_id_str"], doneList))

募集ツイートを取得

まず募集ツイート。つまり、指定のタグ「#抽選bot」付きのtweetを取得します。

指定のタグ「#抽選bot」付きのtweetを取得

1
2
3
4
5
6
# 指定タグのツイートを取得
search = '%23抽選bot'
response = requests.get(
    f'https://api.twitter.com/1.1/search/tweets.json?q={search}&count=50&lang=ja&result_type=mixed&tweet_mode=extended',
    auth=getOauth()
).json()

こんな感じ。

リツイート、リプライを排除

上で取得した中からリツイート、リプライを排除します。

1
2
3
4
5
6
if "retweeted_status" in status:
    print("RT skip")
    continue
if status["in_reply_to_status_id_str"]:
    print("rep skip")
    continue

確立を取得

ツイートのテキストから確率を取得

1
2
3
lot_pro = re.findall(r'(\[.+?\]\(\d+)', main_text)
lot_pro = list(map(lambda x: {"name": re.findall(
    r'\[(.+)\]', x)[0], "pro": int(re.findall(r'(\d+)', x)[0])}, lot_pro))

↑正規表現で、[]()の中身を取得して、形を変換

↓取得した確率を確認のためにめっセージに展開しなおす。

1
2
3
4
lot_message = ""
for p in lot_pro:
    lot_message += f'{p["name"]}:{p["pro"]}%,'
data["lot_message"] = lot_message

募集ツイートにリプライ

まず、メッセージを作成する。

確率が取得できていれば、その確認メッセージ。

確率が取得できなければ、エラーメッセージ。

1
2
3
4
5
6
7
8
if "lot_pro" not in data:
    if len(lot_pro) == 0:
        message = f'#抽選bot のご利用ありがとうございます!\n申し訳ありませんが、確立を読み取れませんでした。\n正しい使い方などは↓のリンクをご覧ください。\nhttps://encr.jp/blog/posts/20200306_morning/\n\n※このツイートはbotからの自動送信です'
    else:
        data["lot_pro"] = lot_pro
        data["lot_message"] = lot_message
        message = f'#抽選bot のご利用ありがとうございます!\n{lot_message[:-1]}で抽選いたします。\nhttps://encr.jp/blog/posts/20200306_morning/\n\n※このツイートはbotからの自動送信です'
    data["main_reply_message"] = message

それをリプライ。

1
2
3
4
5
6
7
8
# リプライする
in_reply_to_status_id = tweet_id
replyResponse = requests.post(
    f'https://api.twitter.com/1.1/statuses/update.json',
    data={"status": message, "in_reply_to_status_id": int(in_reply_to_status_id),
            "auto_populate_reply_metadata": True},
    auth=getOauth()
).json()

応募ツイートを取得

募集ツイートをした人宛のリプライを取得

募集ツイートをした人宛のリプライを全て取得

1
2
3
4
5
6
# 指定タグのツイート者宛のリプライを取得
search = f"%40{status['user']['screen_name']}"
repResponse = requests.get(
    f'https://api.twitter.com/1.1/search/tweets.json?q={search}&count=10&lang=ja&result_type=mixed',
    auth=getOauth()
).json()

必要な応募ツイートのみに絞り込む

リツイートを排除

1
2
3
if "retweeted_status" in status:
    print("RT skip")
    continue

募集ツイートへのリプライ以外を排除

1
2
if rep_status['in_reply_to_status_id_str'] != tweet_id:
    continue

抽選botのリプライを排除。リプライ済の応募ツイートを排除

1
2
3
if rep_status['id_str'] in doneList or rep_status['user']['screen_name'] == SCREEN_NAME:
    print(f"{rep_status['user']['name']} reply done")
    continue

抽選してリプライ

抽選する

ちょっと雑ですが…。

0~100までの乱数を作って、確率を一つずつ足して、hitしたら当選。

最後までhitしなかったら落選。

1
2
3
4
5
6
7
8
9
# 抽選する
sump = 0
yourp = random.random() * 100
lot = None
for p in lot_pro:
    sump += p["pro"]
    if yourp <= sump:
        lot = p["name"]
        break

メッセージ作成

1
2
3
4
if lot is not None:
    message = f'{rep_status["user"]["name"]}さん、リプありがとうございます!\n「{lot}」が当選しました。\n\n※このツイートはbotからの自動送信です #抽選bot'
else:
    message = f'{rep_status["user"]["name"]}さん、リプありがとうございます!\n残念ながら、今回は落選してしまいました…\n\n※このツイートはbotからの自動送信です #抽選bot'

リプライ

1
2
3
4
5
6
replyResponse = requests.post(
    f'https://api.twitter.com/1.1/statuses/update.json',
    data={"status": message, "in_reply_to_status_id": in_reply_to_status_id,
            "auto_populate_reply_metadata": True},
    auth=getOauth()
).json()

独り言

うーん、思ったより、大変だったww

最新のコード全文はこちらです。

抽選botの詳細はこちら

フォロワー6000人企画が楽しみですww

ハッシュタグ付けて頂ければ誰でも使えるので、皆さんもぜひ使ってやってください!


るな
るな
エンジニア