特定のツイートをいいねしたらSlackに自動送信するPythonスクリプト


はじめに

Twitterで論文紹介など研究関連のツイートを見つけたら,とりあえずいいねした後,研究室のSlackで共有するというのをよくやります.
「いいねする→URLコピー→Slackに投稿」
という操作すら面倒臭く感じる体になってしまったので,「退屈なことはPythonにやらせよう」という名言に肖って自動化しました.各種APIやHerokuを使ってみたかったというちゃんとした理由もあります.

もっといい書き方や実装方法あったらぜひコメントください!

GitHub:https://github.com/takaya901/likes2slack

実行例

仕様

本当はいいねした瞬間に投稿するようにしたくて,こちらのブログを参考にやってたのですが,MyStreamのon_eventがどうやっても発動しなかったので,決まった時刻にまとめて投稿するようにしました.
この辺が関係しているのでしょうか.ご存じの方おられたらコメントいただけると助かります.

いいねした中から研究関連のツイートのみを投稿したいので,「github:」「arxiv:」「pdf:」みたいなワードを含むツイートや,特定の研究紹介系アカウントのツイートを抽出します.

  1. 毎朝9時に,自分がいいねしたツイートを新しい順に30件取得する
  2. その中から24時間以内に呟かれており(2重投稿防止),なおかつ特定のワードを含むor特定のアカウントで呟かれたツイートのURLを取得する
  3. URLをSlackの#interesting_paperチャンネルに投稿する

実装

作業環境

  • macOS Catalina
  • Python 3.7.7
  • Pipenv
  • Tweepy
  • Heroku Scheduler

Herokuにデプロイする場合,Pythonのバージョンは要確認です.
https://devcenter.heroku.com/articles/python-support

##APIのキーやトークンの取得
Twitter APIの各種キーと,Slack APIのトークンが必要です.取得方法については先人たちのありがたい記事が沢山ありますので,ここでは割愛させていただきます🙇🏻‍♂️

とりあえずTwitterはこんな感じです.

Tweepyのインストール

公式ドキュメントを参考にインストールします.
Getting startedにある以下のコードが動けばOKです.

import tweepy

consumer_key = 'xxx'
consumer_secret = 'xxx'
access_token = 'xxx'
access_token_secret = 'xxx'

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)

api = tweepy.API(auth)

public_tweets = api.home_timeline()
for tweet in public_tweets:
    print(tweet.text)

コードを書く

コード全体は最後に紹介します.

Slackへの投稿設定

slack_url = "https://slack.com/api/"
params = {'token': os.environ["SLACK_TOKEN"], 'channel': '#interesting_paper', 'text': '', 'as_user': 'true'}

トークンはHerokuの環境変数に設定しているため,os.environで取得しています.ローカルで動かす際はベタ書きでも構いません.'as_user':'true'とすることで,投稿主がbotではなく自分になり,後から編集したり削除したりできます.

投稿


#ツイートのURLを作成
def create_twitter_url(screen_name, id_str):
    return "https://twitter.com/"+screen_name+"/status/"+str(id_str)

words = ['github:', 'arxiv:', 'pdf:'] #検索ワード
ids = ['slam_hub', 'arxiv_cscv', 'shiropen2', 'ak92501', 'HCI_Comics'] #対象アカウントのid

for status in api.favorites(count=30):
    #検索ワードとidに該当しなければスキップ
    if not any((w in status.text) for w in words) and not any((id in status.user.screen_name) for id in ids):
        continue

    #24時間以内にツイートされていたらSlackにポスト
    yesterday = datetime.now() - timedelta(days=1)
    if status.created_at >= yesterday:
        params['text'] = create_twitter_url(status.user.screen_name, status.id)
        r = requests.post(slack_url + "chat.postMessage", params=params)

検索ワードと対象アカウントのリストはどこか外部に保存したほうがいいかもしれません.中に書くと,追加や削除したときにデプロイし直さないといけません.良い方法があれば教えて下さい.

api.favorites()でいいねしたツイートを取得できます.僕は1日10件くらいしかいいねしないので,ここでは30件のみ取得しています.ふぁぼ魔の人は増やしてください.取得した30件の中から,検索ワードを含んでいるか,もしくは対象のアカウントで呟かれたものを抽出します.

更に,重複投稿を防ぐために24時間以内にツイートされたもののみを抽出します.status.created_atはdatetime型なのでそのまま比較できます.

これらの条件を満たしたら,いよいよSlackにURLを投稿します.
ツイートのURLはこれで得られるっぽいのですが,


status.entities['urls'][0]['expanded_url']
#-> https://twitter.com/i/web/status/1276706344314130432

web用のURLしか取れず,スマホで開けなかったりクライアントアプリで開いてくれなかったりしました.そこでこちらのブログを参考にさせていただき,ユーザIDとツイートのIDからURLを作成する関数を導入しました.ここでややこしいのが,status.idで得られるIDはユーザID(@~)ではなく,ツイート自体に割り振られたIDです.ユーザIDはstatus.user.screen_nameです.
print(status)とすると,statusがどんなメンバを持っているか見れます.

全体

Herokuにデプロイ

こちらの記事を参考にさせていただきました.APIのキーやトークンはHerokuの環境変数に設定しておきます.Heroku SchedulerでDaily at 12:00 AM UTC,JSTで毎朝9時に実行されるよう設定しました.

利用時の注意

  • API経由でSlackに投稿するだけではTwitterのアカウントはバレませんが,投稿したツイートのいいね欄を覗かれるとバレる可能性があります。
  • 友人等のツイートが誤って検索ワードに引っかかって投稿される可能性もあるので,検索ワードよりもidを指定する方が安全です.もし誤って投稿されても、一応後から削除ができます.

おわりに

いいねするのは「後で読む」という意味もあって,結局読まずに他のいいねに埋もれてしまうことも多かったので,Slackに送ることで管理もしやすくなりました.
Herokuデプロイも初めてやりましたが,めっちゃ簡単で感動しました.