ラズパイとTwythonを使った自動リツイートシステムの構築について③
ラズパイを使って特定ユーザーのツイートを自動でリツイートするシステムを紹介します。いくつかの記事に分けて掲載する予定です。
面倒くささを3段階で示しておきます。★の数が多いほど面倒くさいです。
②コーディング ☆☆☆
③定期実行の設定 ☆☆★
Twythonライブラリについて
TwitterAPIという仕組みを使いやすくしたライブラリです。
TwitterAPIそのものではありません。これがなくとも自動投稿はできますが非常に面倒くさいです。
まず全体像です。
2つの.pyファイルを作成します。
1つ目はTwitterAPIへのアクセスキーを記述したファイルです。
下記記事で作成した4つの文字列を記述します。
・API Key
・API Key Secret
・Access Token
auth.py
api_key = 'your key' api_key_secret = 'your key' access token = 'your access token' access_token_secret = 'your access token'
ouen.py
# -*- coding: utf-8 -*- from twython import Twython from auth import ( api_key, api_key_secret, access_token, access_token_secret ) import datetime import csv import pprint import os class Tweet: def __init__(self): self.twitter = Twython (api_key, api_key_secret, access_token, access_token_secret) folder_path = os.getcwd() self.TText_path = folder_path + '/TText' self.csv_path = folder_path + '/coume.csv' self.log_text_path = folder_path + '/log_data.txt' #create csv file and folder, if these don't exist. os.makedirs( self.TText_path, exist_ok = True) if os.path.exists(self.csv_path) == False: set_data = ['Wed Dec 28 09:27:18 +0000 2022', '1608031831169077248', self.TText_path + '/Text0.txt'] with open(self.csv_path, "w", encoding='utf-8') as f: writer = csv.writer(f) writer.writerow(set_data) def toko(self, user_name = 'dayukoume'): #record execution time to the log text file with open(self.log_text_path, "a") as f: f.write("[{}] :".format(datetime.datetime.now().strftime("%Y%m%d_%H:%M:%S"))) #read the previous data with open(self.csv_path, "r") as f: reader = csv.reader(f) preData = [row for row in reader] #get date to use from the user timeline user_timeline = self.twitter.get_user_timeline(screen_name = user_name, count = 5) buf = self.extract_data(user_timeline = user_timeline) #write the data to .csv with open(self.csv_path, "w") as f: writer = csv.writer(f) writer.writerows(buf) #Retweet num_RT = self.RT(ID = self.toko_check(preData = preData, nowData = buf), buf = buf) #update the logdata with open(self.log_text_path, "a") as f: f.write( str(num_RT) + '件リツイート!\n') def extract_data(self, user_timeline): buf = [[]] for i in range(len(user_timeline)): TTP = self.TText_path + '/TText' + str(i) + '.txt' #Tweet Text Path with open(TTP, "w") as f: f.write(user_timeline[i]['text']) buf.append([user_timeline[i]['created_at'],user_timeline[i]['id'],TTP]) buf.pop(0) return buf def toko_check(self, preData, nowData): toko_data = [i for i in range(len(nowData))] for i in range(len(nowData)): flag = 0 for j in range(len(preData)): if nowData[i][0] == preData[j][0]: flag = 1 if self.reject_check(textData_path = nowData[i][2], reject_word = 'RT @') == True: flag = 1 if flag == 1: toko_data.remove(i) return toko_data def reject_check(self, textData_path, reject_word = 'RT @'): with open(textData_path, "r") as f: textData = f.read() if reject_word in textData: return True return False def RT(self, ID, buf): if ID: for i in range(len(ID)): print(buf[i][1]) self.twitter.retweet(id = buf[i][1]) return len(ID) def main(): print('小梅太夫を応援します') twython_bot=Tweet() twython_bot.toko() print('successful!!') if __name__ == "__main__": main()
プログラムの実行前と実行後
実行前のフォルダ
ディレクトリを移動してプログラムの実行
出力ファイル3種
ログファイル:何件リツイートしたか記録
csvファイル:投稿時間とツイートIDとテキスト内容を記録したファイルのパスを記載
テキストファイル:ツイートのテキストを格納したファイル
プログラムの流れ
- main関数として呼び出されたらmain()という関数を呼び出します。(97~98行目)
- 処理に使うクラスをtwython_botという名前でインスタンス化します。(93行目)
- __init__というメソッドが呼び出されます。(15~29行目)
- ツイッターAPIを使うための準備をします。(16行目)
- 現在の作業ディレクトリを取得します。(18行目)
- 処理に使用するパスの定義をしておきます。(19~21行目)
- フォルダを再帰的に作成します。すでにある場合は無視されます。(24行目)
- csvファイルがなければ作成しておきます。処理内容の記録用のファイルです。(25~29行目)
- tokoというメソッドを呼び出します。今回は引数を与えません。(94行目)
- user_nameという引数を与えられます。ツイッターアカウントのユーザーネーム(@を除く)を指定します。(31行目)
- プログラムの起動時刻が記録されます。(33~34行目)
- 前回の処理内容を読み取っておきます。(37~39行目)
- timelineを取得します。(42行目)
- 取得したデータは情報量が多いため、必要な情報のみを抽出します。(43行目)
- timelineからツイートのテキストデータを抽出して、テキストファイルに保存します。(59~62行目)
- 投稿時刻とツイートID、テキストのパスを格納したリストを作成します。(63行目)
- 最初の要素は空なので消し飛ばします。(64行目)
- 読み取ったデータをcsvファイルに上書きします。(46~48行目)
- リツイートを行います。特定の条件のツイートIDをtoko_checkというメソッドで抽出してリツイートを行います。(51行目)
- 今回タイムラインから抽出したデータの要素番号を格納するリストを作成します。(68行目)
- 前回抽出したデータと総当たり戦を行います。投稿時刻が重複しているもの、テキストに"RT @"とついているものをリツイート対象から排除します。(69~74行目)
- テキストに"RT @"がついているかどうかはreject_checkというメソッドで行っています。(73行目)
- テキストファイルを読み取り、文字列に"RT @"が存在すればTrue、存在しなければFalseを返します。(77~82行目)
- リツイートするIDが抽出出来たら、実際に投稿します。(84~89行目)
- リツイートした数が返ってくるので、記録しておきます。(54~55行目)
取得するタイムラインデータの例
必要なデータを抽出しましょう。
[{'contributors': None, 'coordinates': None, 'created_at': 'Tue Jan 03 15:42:12 +0000 2023', 'entities': {'hashtags': [{'indices': [37, 47], 'text': 'まいにちチクショー'}], 'symbols': [], 'urls': [], 'user_mentions': []}, 'favorite_count': 351, 'favorited': False, 'geo': None, 'id': 1610300502587371524, 'id_str': '1610300502587371524', 'in_reply_to_screen_name': None, 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'is_quote_status': False, 'lang': 'ja', 'place': None, 'retweet_count': 50, 'retweeted': False, 'source': '<a href="http://twitter.com/download/android" ' 'rel="nofollow">Twitter for Android</a>', 'text': '湯の花かと思ったら~、\n\nロクロク首にピアスでした~。\n\nチクショー!!\u3000#まいにちチクショー', 'truncated': False, 'user': {'contributors_enabled': False, 'created_at': 'Sun Oct 16 08:15:54 +0000 2011', 'default_profile': True, 'default_profile_image': False, 'description': 'https://t.co/9RPGbBGxgg\n' '\n' 'チクポーレディオ\n' 'https://t.co/erHVqVbO5m\n' ' \n' 'コウメ太夫のクックショー!\n' 'https://t.co/H0jtfq3lIu', 'entities': {'description': {'urls': [{'display_url': 'instagram.com/koumedayu/', 'expanded_url': 'https://www.instagram.com/koumedayu/', 'indices': [0, 23], 'url': 'https://t.co/9RPGbBGxgg'}, {'display_url': 'youtube.com/user/shotti01/', 'expanded_url': 'http://youtube.com/user/shotti01/', 'indices': [34, 57], 'url': 'https://t.co/erHVqVbO5m'}, {'display_url': 'youtube.com/channel/UC0-bl…', 'expanded_url': 'https://www.youtube.com/channel/UC0-bl1zmCvGuOvHvhbC7bbw', 'indices': [81, 104], 'url': 'https://t.co/H0jtfq3lIu'}]}}, 'favourites_count': 44, 'follow_request_sent': False, 'followers_count': 183173, 'following': True, 'friends_count': 713, 'geo_enabled': True, 'has_extended_profile': True, 'id': 391900115, 'id_str': '391900115', 'is_translation_enabled': False, 'is_translator': False, 'lang': None, 'listed_count': 713, 'location': '', 'name': 'コウメ太夫', 'notifications': False, 'profile_background_color': 'C0DEED', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_tile': False, 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/391900115/1492515189', 'profile_image_url': 'http://pbs.twimg.com/profile_images/378800000865932105/orzBqjQ1_normal.jpeg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/378800000865932105/orzBqjQ1_normal.jpeg', 'profile_link_color': '1DA1F2', 'profile_sidebar_border_color': 'C0DEED', 'profile_sidebar_fill_color': 'DDEEF6', 'profile_text_color': '333333', 'profile_use_background_image': True, 'protected': False, 'screen_name': 'dayukoume', 'statuses_count': 5765, 'time_zone': None, 'translator_type': 'none', 'url': None, 'utc_offset': None, 'verified': False, 'withheld_in_countries': []}}]