前提・実現したいこと
実現したいこと
GUI操作でtwitterのいいね、リツイート、フォローを自動実行するアプリ作成
シングルスレッド処理だと自動実行中にGUIがフリーズしてしまい、
停止ボタンによる処理の終了
結果表示ができないため
自動実行部分をスレッドに渡してGUI操作ができるようにしたい
twitter操作にはtweepy
GUIはpyqt5
スレッド処理はQThread
発生している問題・エラーメッセージ
自動実行部分をスレッド(QThread)に渡すと自動実行処理が実行されない
メインウィンドウpython↓
python
1from PyQt5.QtCore import * 2from PyQt5.QtGui import * 3from PyQt5.QtWidgets import * 4 5import MainWindow 6 7import sys 8 9from twitter import twitterApp 10 11class MainWindow(QDialog,MainWindow.Ui_MainWindow): 12 13 def __init__(self,parent=None): 14 super(MainWindow,self).__init__(parent) 15 self.setupUi(self) 16 self.tw_app = twitterApp(self) 17 self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=3) 18 self.setting = mngSetting() 19 self.init_stylesheet = "background-color: rgb(167, 167, 167);" 20 self.thread = QThread() 21 self.act_list = [] 22 23 24 def autorun(self): 25 # 自動実行が開始されたら自動実行ボタンをクリックできないようにする 26 self.changeBtnStatus(self.pushButton_2,self.pushButton) 27 self.tw_app.moveToThread(self.thread) 28 29 # スレッドからの紐づけ 30 self.tw_app.sendFlag.connect(self.outAction) 31 self.tw_app.sendMessage.connect(self.outLog) 32 self.tw_app.sendCount.connect(self.setCount) 33 self.thread.start() 34 35 36 37 def outAction(self,rt,like,follow): 38 if(rt): 39 rt_act = 'RT' 40 else: 41 rt_act = '-' 42 if(like): 43 like_act = 'Like' 44 else: 45 like_act = '-' 46 if(follow): 47 follow_act = 'Follow' 48 else: 49 follow_act = '-' 50 51 # action_listに今回作成したリストを追加していく 52 tmp_list = [rt_act,like_act,follow_act,datetime.datetime.now()] 53 54 self.act_list.append(tmp_list) 55 56 # 行数を追加していく必要があるため 57 # 行名は1から順に数字にしていく 58 self.tableWidget.setRowCount(len(self.act_list)) 59 tmpHeaders = list(range(1,len(self.act_list))) 60 verHeaders = [str(n) for n in tmpHeaders] 61 self.tableWidget.setVerticalHeaderLabels(verHeaders) 62 63 for n in range(len(self.act_list)): 64 for m in range(len(tmp_list)): 65 item = QTableWidgetItem(str(self.act_list[n][m])) 66 self.tableWidget.setItem(n, m, item) 67 68 def outLog(self,message): 69 log_message = '[' + str(datetime.datetime.now()) + '] ' + message 70 self.listWidget.addItem(log_message) 71 72 def setCount(self,like_count,rt_count,follow_count): 73 self.label_14.setText(str(like_count)) 74 self.label_17.setText(str(rt_count)) 75 self.label_18.setText(str(follow_count)) 76 77if __name__ == "__main__": 78 79 app = QApplication(sys.argv) 80 form = MainWindow() 81 form.show() 82 app.exec_()
twitter機能実装pythonファイル↓
python
1# twitterApp 2import tweepy 3from config import CONFIG 4from TwitterOauth import TwitterOauth 5from selenium import webdriver 6from selenium.webdriver.chrome.options import Options 7import time 8import oauth2 as oauth 9import json 10import datetime 11from PyQt5.QtWidgets import * 12from PyQt5.QtCore import * 13import schedule 14 15class twitterApp(QThread): 16 17 # twitterAPIを使用する設定 18 # APPを起動した際に初期化 19 MAX_COUNT = 10 20 sendCount = pyqtSignal(int,int,int) 21 sendFlag = pyqtSignal(bool,bool,bool) 22 sendMessage = pyqtSignal(str) 23 finished = pyqtSignal() 24 25 def __init__(self,host_window): 26 27 super(twitterApp,self).__init__() 28 self.CONSUMER_KEY = CONFIG["API_KEY"] 29 self.CONSUMER_SECRET = CONFIG["API_SECRET_KEY"] 30 self.twitterOauth = TwitterOauth(self.CONSUMER_KEY,self.CONSUMER_SECRET) 31 self.api ='' 32 self.window = host_window 33 self.follow_count = self.MAX_COUNT 34 self.retweet_count = self.MAX_COUNT 35 self.favorite_count = self.MAX_COUNT 36 37 def run(self): 38 """ 39 QThreadのrunメソッドのオーバーライド 40 """ 41 self.autoWrapper(self.window.checkBox_4.isChecked(),self.window.lineEdit_4.text(),self.window.checkBox.isChecked(),self.window.checkBox_2.isChecked(),self.window.checkBox_3.isChecked(),self.window.spinBox.value()) 42 43 44 #キーワード検索からtwitterの自動実行 45 def autoRunFromKeyWordSearch(self,word,favorite,retweet,follow,seconds): 46 """twitterキーワード検索から操作実行 47 48 チェックをつけてある動作をキーワード検索に基づいて自動実行する 49 50 Args: 51 word: 検索キーワード 52 favorite : いいねを実行するフラグ 53 retweet: リツイートを実行するフラグ 54 follow: フォローを実行するフラグ 55 seconds: 実行間隔(s) 56 """ 57 self.sendMessage.emit('キーワード検索に対する自動実行を開始!') 58 # self.outLog('キーワード検索に対する自動実行を開始!') 59 60 search_results = self.api.search(q=word,count=self.MAX_COUNT) 61 62 for result in search_results: 63 tweet_id = result.id 64 user_id = result.user._json['id'] 65 66 if(favorite and self.favorite_count > 0): 67 try: 68 self.api.create_favorite(tweet_id) 69 70 self.favorite_count -= 1 71 # self.window.label_14.setText(str(self.favorite_count)) 72 if(self.favorite_count <= 0): 73 break 74 except Exception as e: 75 favorite = False 76 print(e) 77 if(retweet and self.retweet_count > 0): 78 try: 79 self.api.retweet(tweet_id) 80 81 self.retweet_count -= 1 82 # self.window.label_17.setText(str(self.retweet_count)) 83 if(self.retweet_count <= 0): 84 break 85 except Exception as e: 86 retweet = False 87 print(e) 88 if(follow and self.follow_count >= 0): 89 try: 90 self.api.create_friendship(user_id) 91 # self.window.label_17.setText(str(self.retweet_count)) 92 self.follow_count -= 1 93 94 if(self.follow_count <= 0): 95 break 96 except Exception as e: 97 follow = False 98 print(e) 99 self.sendFlag.emit(retweet,favorite,follow) 100 self.sendCount(self.favorite_count,self.retweet_count,self.follow_count) 101 # self.outAction(retweet,favorite,follow) 102 103 QThread.sleep(seconds) 104 if(self.favorite_count <=0 and self.retweet_count <= 0): 105 self.stop() 106 107 self.sendMessage.emit('キーワード検索に対する自動実行を終了!') 108 # self.outLog('キーワード検索に対する自動実行を終了!') 109 self.window.changeBtnStatus(self.window.pushButton,self.window.pushButton_2) 110 111 112 113 #タイムラインによるtwitterの自動実行 114 def autoRunAgainstTimeLine(self,favorite,retweet,seconds): 115 """twitterタイムラインに対して操作実行 116 117 チェックをつけてある動作をタイムラインに基づいて自動実行する 118 119 Args: 120 favorite : いいねを実行するフラグ 121 retweet: リツイートを実行するフラグ 122 follow: フォローを実行するフラグ 123 seconds: 実行間隔(s) 124 125 """ 126 self.sendMessage.emit('フォロワーに対する自動実行を開始!') 127 # self.outLog('フォロワーに対する自動実行を開始!') 128 # タイムラインのツイートを取得 129 tl = self.api.home_timeline(count=self.MAX_COUNT) 130 for tweet in tl: 131 tweet_id = tweet.id 132 if(favorite and self.favorite_count >= 0): 133 try: 134 self.api.create_favorite(tweet_id) 135 self.favorite_count -= 1 136 # self.window.label_14.setText(str(self.favorite_count)) 137 138 except Exception as e: 139 favorite = False 140 print(e) 141 if(retweet and self.retweet_count >= 0): 142 try: 143 self.api.retweet(tweet_id) 144 self.retweet_count -= 1 145 # self.window.label_17.setText(str(self.retweet_count)) 146 except Exception as e: 147 retweet = False 148 print(e) 149 # self.outAction(retweet,favorite,False) 150 self.sendFlag.emit(retweet,favorite,False) 151 self.sendCount.emit(self.favorite_count,self.retweet_count,self.follow_count) 152 QThread.sleep(seconds) 153 if(self.favorite_count <=0 and self.retweet_count <= 0): 154 self.stop() 155 156 self.sendMessage.emit('フォロワーに対する自動実行を終了!') 157 158 self.window.changeBtnStatus(self.window.pushButton,self.window.pushButton_2) 159 def autoWrapper(self,is_tl,word,favorite,retweet,follow,seconds): 160 """ 161 @概要 162 自動実行する2つのメソッドのwrapper 163 @param 164 is_tl:タイムラインに対して自動実行するかのフラグ 165 @param 166 word:検索キーワード 167 @param 168 favorite:いいねフラグ 169 @param 170 retweet:リツイートフラグ 171 @param 172 follow:フォローフラグ 173 @seconds: 174 実行間隔フラグ 175 """ 176 if(is_tl): 177 self.autoRunAgainstTimeLine(favorite,retweets) 178 if(word): 179 self.autoRunFromKeyWordSearch(word,favorite,retweet,follow,seconds) 180
文字数の関係で関係ない箇所の処理を省いています。
ご了承ください。
MainWindowクラスのautorun()関数内で、threadがstartしたときの紐付けがなされていないのが原因かと思いますが、
signalとemitが書かれてあるであろう、twitterAppの内容が明らかにされていないので、はっきりしません。
twitter.py(twitterAppクラスが書かれてあるファイル)のコードも全部提示していただけないでしょうか。
あと現状のコードだと、autorun()関数(バックグラウンドでのtwitterのデータ取得処理?)自体は、MainWindow内部のどこからも呼び出されていないように見えますが、実際はMainWindowに何かボタンを実装して、そこをクリックしたら処理させるようなイメージなのでしょうか。
autorunをボタンと紐付けようとしています
'''
import tweepy
from config import CONFIG
from TwitterOauth import TwitterOauth
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
import oauth2 as oauth
import json
import datetime
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import schedule
class twitterApp(QThread):
# twitterAPIを使用する設定
# APPを起動した際に初期化
MAX_COUNT = 10
sendCount = pyqtSignal(int,int,int)
sendFlag = pyqtSignal(bool,bool,bool)
sendMessage = pyqtSignal(str)
finished = pyqtSignal()
def __init__(self,host_window):
super(twitterApp,self).__init__()
self.CONSUMER_KEY = CONFIG["API_KEY"]
self.CONSUMER_SECRET = CONFIG["API_SECRET_KEY"]
self.twitterOauth = TwitterOauth(self.CONSUMER_KEY,self.CONSUMER_SECRET)
self.api =''
self.window = host_window
self.follow_count = self.MAX_COUNT
self.retweet_count = self.MAX_COUNT
self.favorite_count = self.MAX_COUNT
def run(self):
"""
QThreadのrunメソッドのオーバーライド
"""
self.autoWrapper(self.window.checkBox_4.isChecked(),self.window.lineEdit_4.text(),self.window.checkBox.isChecked(),self.window.checkBox_2.isChecked(),self.window.checkBox_3.isChecked(),self.window.spinBox.value())
def login(self,login_id,password):
"""twitterにログイン
twitterにログインするメソッド
seleniumを利用してPINコードを取得→アクセストークンを取得する
Args:
login_id(str): twitterにログインするID @を付けること
password : twitterにログインするPW
Returns:
user_name: twitterのユーザー名
friends_count: フォロー数
follower_count: フォロワー数
Raises:
Examples:
Note:
PINコードが表示される時間によってエラーが発生する
"""
option = Options()
option.add_argument('--headless')
# 認証ページのURLを取得する
authenticate_url = self.twitterOauth.get_authenticate_url()
# driverを利用してログインする
# driver = webdriver.Chrome(options=option)
driver = webdriver.Chrome(options=option)
driver.get(authenticate_url)
time.sleep(3)
# 画面に表示されたPINコードを取得する
idForm = driver.find_element_by_id('username_or_email')
idForm.send_keys(login_id)
passForm = driver.find_element_by_id('password')
passForm.send_keys(password)
time.sleep(3)
loginButton = driver.find_element_by_id('allow')
loginButton.click()
pinCode = int(driver.find_element_by_tag_name('code').text)
#PINコードを基にアクセストークンを取得する
access_token_content = self.twitterOauth.get_access_token_content(pinCode)
access_token = access_token_content["oauth_token"][0]
access_token_secret = access_token_content["oauth_token_secret"][0]
auth = tweepy.OAuthHandler(self.CONSUMER_KEY,self.CONSUMER_SECRET)
auth.set_access_token(access_token,access_token_secret)
driver.close()
#tweepyのAPIを取得する
self.api = tweepy.API(auth)
# アカウント情報を取得する
user_me = self.api.me()
return [user_me.name,user_me.friends_count,user_me.followers_count]
#キーワード検索からtwitterの自動実行
def autoRunFromKeyWordSearch(self,word,favorite,retweet,follow,seconds):
"""twitterキーワード検索から操作実行
チェックをつけてある動作をキーワード検索に基づいて自動実行する
Args:
word: 検索キーワード
favorite : いいねを実行するフラグ
retweet: リツイートを実行するフラグ
follow: フォローを実行するフラグ
seconds: 実行間隔(s)
Returns:
Raises:
Examples:
Note:
"""
self.sendMessage.emit('キーワード検索に対する自動実行を開始!')
# self.outLog('キーワード検索に対する自動実行を開始!')
search_results = self.api.search(q=word,count=self.MAX_COUNT)
for result in search_results:
tweet_id = result.id
user_id = result.user._json['id']
if(favorite and self.favorite_count > 0):
try:
self.api.create_favorite(tweet_id)
self.favorite_count -= 1
if(self.favorite_count <= 0):
break
except Exception as e:
favorite = False
print(e)
if(retweet and self.retweet_count > 0):
try:
self.api.retweet(tweet_id)
self.retweet_count -= 1
if(self.retweet_count <= 0):
break
except Exception as e:
retweet = False
print(e)
if(follow and self.follow_count >= 0):
try:
self.api.create_friendship(user_id)
self.follow_count -= 1
if(self.follow_count <= 0):
break
except Exception as e:
follow = False
print(e)
self.sendFlag.emit(retweet,favorite,follow)
self.sendCount(self.favorite_count,self.retweet_count,self.follow_count)
QThread.sleep(seconds)
if(self.favorite_count <=0 and self.retweet_count <= 0):
self.stop()
self.sendMessage.emit('キーワード検索に対する自動実行を終了!')
self.window.changeBtnStatus(self.window.pushButton,self.window.pushButton_2)
#タイムラインによるtwitterの自動実行
def autoRunAgainstTimeLine(self,favorite,retweet,seconds):
"""twitterタイムラインに対して操作実行
チェックをつけてある動作をタイムラインに基づいて自動実行する
Args:
favorite : いいねを実行するフラグ
retweet: リツイートを実行するフラグ
follow: フォローを実行するフラグ
seconds: 実行間隔(s)
"""
self.sendMessage.emit('フォロワーに対する自動実行を開始!')
# タイムラインのツイートを取得
tl = self.api.home_timeline(count=self.MAX_COUNT)
for tweet in tl:
tweet_id = tweet.id
if(favorite and self.favorite_count >= 0):
try:
self.api.create_favorite(tweet_id)
self.favorite_count -= 1
except Exception as e:
favorite = False
print(e)
if(retweet and self.retweet_count >= 0):
try:
self.api.retweet(tweet_id)
self.retweet_count -= 1
except Exception as e:
retweet = False
print(e)
self.sendFlag.emit(retweet,favorite,False)
self.sendCount.emit(self.favorite_count,self.retweet_count,self.follow_count)
QThread.sleep(seconds)
if(self.favorite_count <=0 and self.retweet_count <= 0):
self.stop()
self.sendMessage.emit('フォロワーに対する自動実行を終了!')
self.window.changeBtnStatus(self.window.pushButton,self.window.pushButton_2)
def autoWrapper(self,is_tl,word,favorite,retweet,follow,seconds):
"""
@概要
自動実行する2つのメソッドのwrapper
@param
is_tl:タイムラインに対して自動実行するかのフラグ
@param
word:検索キーワード
@param
favorite:いいねフラグ
@param
retweet:リツイートフラグ
@param
follow:フォローフラグ
@seconds:
実行間隔フラグ
"""
if(is_tl):
self.autoRunAgainstTimeLine(favorite,retweets)
if(word):
self.autoRunFromKeyWordSearch(word,favorite,retweet,follow,seconds)
def calcAfterOneHour(self):
"""
@概要
関数を実行してから1時間後の時間を算出する
"""
dt_now = datetime.datetime.now()
dt_hour = dt_now + datetime.timedelta(minutes=1)
# スケジュールーラに登録する際に時間表記にする必要があるため
dt_hour = dt_hour.strftime('%H:%M')
return dt_hour
def resetCount(self):
"""
@概要
回数を最大回数に戻す
"""
self.follow_count = self.MAX_COUNT
self.retweet_count = MAX_COUNT
self.favorite_count = self.MAX_COUNT
self.window.label_14.setText(str(self.favorite_count))
self.window.label_17.setText(str(self.retweet_count))
self.window.label_17.setText(str(self.retweet_count))
quit = True
def stop(self):
self.window.outLog('指定回数を超えたため1時間後まで処理を停止します')
schedule.every().day.at(self.calcAfterOneHour()).do(self.resetCount)
while True:
schedule.run_pending()
if(quit):
self.outLog('自動実行を再開できます')
self.window.changeBtnStatus(self.window.pushButton,self.window.pushButton_2)
break
time.sleep(60)
'''
こちらがtwitter.pyの全体になります。
回答しました。なお、上のコメント欄にペーストしていただいているソース部分はインデントがないため考慮していません。