Threads are quite difficult for me. I can't quite wrap my head around how to stop a thread when some event occurs. Its difficult for me, because in the event occurs at the end of a for loop and also involves a browser.
This method here is supposed to continuously check for a flag
def Stop(self, event):
myClass.worker.terminate = True
if myClass.worker != None:
while myClass.browser!=None:
if myClass.worker.taskfinished:
myClass.worker.stop()
myClass.browser.quit()
myClass.worker = None
break
else:
pass
This condition occurs at the bottom of this for loop which is part of a different method:
for i in range(scraperow, numrows):
myClass.taskfinished = False
domain = sheet.cell_value(i, 2)
prevdomain = sheet.cell_value(i-1,2)
name = sheet.cell_value(i,0)
result = ""
if domain==prevdomain and result=="CATCH-ALL":
worksheet.write(i, 3, "Catch all")
wbook.save(file)
else:
wait = WebDriverWait(self.browser, 500)
inputName = wait.until(EC.presence_of_element_located((By.ID, "form-search-name")))
inputName.send_keys(name)
inputDomain = wait.until(EC.presence_of_element_located((By.ID, "form-search-domain")))
inputDomain.send_keys(domain)
norbertsearch = wait.until(EC.presence_of_element_located((By.NAME, "search")))
norbertsearch.click()
starttime = time.time()
wait = WebDriverWait(self.browser, 500)
selector = "div[class=\"text-center displayed\"] h3"
rslt = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, (selector))))
result = rslt.text
if result == "SUCCESS":
waittwo = WebDriverWait(self.browser, 5)
email = rslt.find_element_by_xpath('following-sibling::div/a')
email = email.get_attribute('href')
email = email.split(":")[1]
worksheet.write(i, 3, email)
wbook.save(file)
elif result == "NOTHING FOUND":
worksheet.write(i, 3, "Nothing found")
wbook.save(file)
elif result == "I'M TIRED":
worksheet.write(i, 3, "Over search limit")
wbook.save(file)
dlg = wx.MessageBox("Norbert is tired and has exhausted his searches for the day. Try again later.", "Ask Alfred", wx.OK | wx.ICON_INFORMATION)
break
elif result == "OH MAN, I BROKE MY ANKLE":
worksheet.write(i, 3, "Server error")
wbook.save(file)
elif result == "CATCH-ALL":
worksheet.write(i, 3, "Catch-all")
wbook.save(file)
myClass.taskfinished = True
Unfortunately its blocking up the thread, making things kind of hairy. How can I gracefully have the thread wait until its gotten a result and then stop the thread?
Related
I'm really new to python and
I have a python selenium script
#Developed by github.com/useragents
#This script was made for educational purposes. I am not responsible for your actions using this script. This code is a few months old, hence why it may not appear as professional but still works to this day.
try:
from selenium import webdriver
import time, os, ctypes, requests
from colorama import Fore, init
import warnings, selenium, platform
except ImportError:
input("Error while importing modules. Please install the modules in requirements.txt")
init(convert = True, autoreset = True)
warnings.filterwarnings("ignore", category=DeprecationWarning)
clear = "clear"
if platform.system() == "Windows":
clear = "cls"
os.system(clear)
ascii_text = f"""{Fore.RED}
████████▀▀▀████
████████────▀██
████████──█▄──█
███▀▀▀██──█████
█▀──▄▄██──█████
█──█████──█████
█▄──▀▀▀──▄█████
███▄▄▄▄▄███████ github.com/useragents
"""
class automator:
def __init__(self):
options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors')
options.add_experimental_option("excludeSwitches", ["enable-logging"])
self.xpaths = {
"followers": "/html/body/div[4]/div[1]/div[3]/div/div[1]/div/button",
"likes": "/html/body/div[4]/div[1]/div[3]/div/div[2]/div/button",
"views": "/html/body/div[4]/div[1]/div[3]/div/div[4]/div/button",
"shares": "/html/body/div[4]/div[1]/div[3]/div/div[5]/div/button"
}
try:
self.driver = webdriver.Chrome(options = options)
except Exception as e:
self.error(f"Error trying to load web driver: {e}")
self.status = {}
self.sent = 0
self.cooldowns = 0
self.ratelimits = 0
def check_status(self):
for xpath in self.xpaths:
value = self.xpaths[xpath]
element = self.driver.find_element_by_xpath(value)
if not element.is_enabled():
self.status.update({xpath: "[OFFLINE]"})
else:
self.status.update({xpath: ""})
def check_for_captcha(self):
while True:
try:
if "Enter the word" not in self.driver.page_source:
return
except:
return
os.system(clear)
print(ascii_text)
print(f"{self.console_msg('Error')} Complete the CAPTCHA in the driver.")
time.sleep(1)
def console_msg(self, status):
colour = Fore.RED
if status == "Success":
colour = Fore.GREEN
return f" {Fore.WHITE}[{colour}{status}{Fore.WHITE}]"
def update_ascii(self):
options = f"""
{self.console_msg("1")} Follower Bot {Fore.RED}{self.status["followers"]}
{self.console_msg("2")} Like Video Bot {Fore.RED}{self.status["likes"]}
{self.console_msg("3")} View Bot {Fore.RED}{self.status["views"]}
{self.console_msg("4")} Share Bot {Fore.RED}{self.status["shares"]}
"""
return ascii_text + options
def check_url(self, url):
redirect = True
if "vm.tiktok.com/" in url:
redirect = False
if redirect:
if "/video/" not in url:
return False
session = requests.Session()
r = session.get(url, allow_redirects=redirect)
if redirect:
if r.status_code == 200:
return True
return False
location = r.headers["Location"]
if "/video" in location:
return True
return False
def convert(self, min, sec):
seconds = 0
if min != 0:
answer = int(min) * 60
seconds += answer
seconds += int(sec) + 15
return seconds
def check_submit(self, div):
remaining = f"/html/body/div[4]/div[{div}]/div/div/h4"
try:
element = self.driver.find_element_by_xpath(remaining)
except:
return None, None
if "READY" in element.text:
return True, True
if "seconds for your next submit" in element.text:
output = element.text.split("Please wait ")[1].split(" for")[0]
minutes = element.text.split("Please wait ")[1].split(" ")[0]
seconds = element.text.split("(s) ")[1].split(" ")[0]
sleep_duration = self.convert(minutes, seconds)
return sleep_duration, output
return element.text, None
def update_cooldown(self, sleep_time, bot, rl = False):
cooldown = sleep_time
while True:
time.sleep(1)
try:
cooldown -= 1
except TypeError:
break
self.update_title(bot, cooldown, rl)
if cooldown == 0:
break
def wait_for_ratelimit(self, arg, div):
time.sleep(1)
duration, output = self.check_submit(div)
if duration == True:
return
if output == None:
time.sleep(0.7)
self.wait_for_ratelimit(arg, div)
self.cooldowns += 1
self.update_cooldown(duration, arg)
def send_bot(self, video_url, bot, div):
try:
self.driver.find_element_by_xpath(self.xpaths[bot]).click()
time.sleep(0.5)
except:
pass
enter_link_xpath = f"/html/body/div[4]/div[{div}]/div/form/div/input"
link = self.driver.find_element_by_xpath(enter_link_xpath)
link.clear()
link.send_keys(video_url)
self.driver.find_element_by_xpath(f"/html/body/div[4]/div[{div}]/div/form/div/div/button").click() #Search button
time.sleep(0.8)
send_button_xpath = f"/html/body/div[4]/div[{div}]/div/div/div[1]/div/form/button"
try:
self.driver.find_element_by_xpath(send_button_xpath).click()
except selenium.common.exceptions.NoSuchElementException:
self.wait_for_ratelimit(bot, div)
self.driver.find_element_by_xpath(f"/html/body/div[4]/div[{div}]/div/form/div/div/button").click() #Search button
time.sleep(0.8)
self.driver.find_element_by_xpath(send_button_xpath).click()
time.sleep(3)
try:
s = self.driver.find_element_by_xpath(f"/html/body/div[4]/div[{div}]/div/div/span")
if "Too many requests" in s.text:
self.ratelimits += 1
self.update_cooldown(50, bot, True)
self.send_bot(video_url, bot, div)
elif "sent" in s.text:
sent = 100
if bot == "likes":
try:
sent = int(s.text.split(" Hearts")[0])
except IndexError:
sent = 30
if bot == "views":
sent = 2500
if bot == "shares":
sent = 500
self.sent += sent
else:
print(s.text)
except:
self.sent += sent
self.update_title(bot, "0")
self.wait_for_ratelimit(bot, div)
self.send_bot(video_url, bot, div)
def update_title(self, bot, remaining, rl = False):
if clear == "cls":
os.system(clear)
ctypes.windll.kernel32.SetConsoleTitleW(f"TikTok AIO | Sent: {self.sent} | Cooldown: {remaining}s | Developed by #useragents on Github")
print(ascii_text)
print(self.console_msg(self.sent) + f" Sent {bot}")
rl_cooldown = "0"
cooldown = "0"
if rl:
rl_cooldown = remaining
else:
cooldown = remaining
print(self.console_msg(self.cooldowns) + f" Cooldowns {Fore.WHITE}[{Fore.RED}{cooldown}s{Fore.WHITE}]")
print(self.console_msg(self.ratelimits) + f" Ratelimits {Fore.WHITE}[{Fore.RED}{rl_cooldown}s{Fore.WHITE}]")
def main(self):
if clear == "cls":
ctypes.windll.kernel32.SetConsoleTitleW("TikTok AIO | Developed by #useragents on Github")
self.driver.get("https://zefoy.com/")
time.sleep(2)
if "502 Bad Gateway" in self.driver.page_source:
os.system(clear)
print(ascii_text)
input(f"{self.console_msg('Error')} This website does not allow VPN or proxy services.")
os._exit(0)
self.check_for_captcha()
self.check_status()
self.start()
def error(self, error):
print(ascii_text)
print(f"{self.console_msg('Error')} {error}")
time.sleep(5)
os._exit(0)
def start(self):
os.system(clear)
print(self.update_ascii())
try:
option = int(input(f" {Fore.RED}> {Fore.WHITE}"))
except ValueError:
self.start()
if option == 1:
if self.status["followers"] != "":
return self.start()
div = 2
ver = "followers"
username = str(input(f"\n{self.console_msg('Console')} TikTok Username: #"))
print()
self.send_bot(username, ver, div)
return
elif option == 2:
if self.status["likes"] != "":
return self.start()
div = 3
ver = "likes"
elif option == 3:
if self.status["views"] != "":
return self.start()
div = 5
ver = "views"
elif option == 4:
if self.status["shares"] != "":
return self.start()
div = 6
ver = "shares"
else:
return self.start()
video_url = str(input(f"\n{self.console_msg('Console')} Video URL: "))
print()
check = self.check_url(video_url)
if not check:
return self.error("This URL does not exist.")
self.send_bot(video_url, ver, div)
obj = automator()
obj.main()
And tried to add https proxy with auth in this script
My proxy is 34.72.101.101:3127:user:BasAJSzAdAAWD
I tried to configure script to use proxy but it crashed one time and another time when I tried another way it worked but after some step proxy disappear
I have a program that is supposed to send a few data points over a serial connection to an arduino which will control some motors to move. I can send the control signals individually as well as by txt file which will run repeatedly until the file is complete. While running a txt file, I want to be able to exit the loop like a pause or stop button. I think the best way to do that is via a thread that I can close. I have never done any threading before and my rudimentary attempts have not worked. Here is the function that sends the file data.
def send_file():
# Global vars
global moto1pos
global motor2pos
# Set Ready value
global isready
# Get File location
program_file_name = file_list.get('active')
file_path = "/home/evan/Documents/bar_text_files/"
program_file = Path(file_path + program_file_name)
file = open(program_file)
pos1 = []
pos2 = []
speed1 = []
speed2 = []
accel1 = []
accel2 = []
for each in file:
vals = each.split()
pos1.append(int(vals[0]))
pos2.append(int(vals[1]))
speed1.append(int(vals[2]))
speed2.append(int(vals[3]))
accel1.append(int(vals[4]))
accel2.append(int(vals[5]))
# Send file values
try:
while isready == 1:
for i in range(len(pos1)):
print("Step: " + str(i+1))
data = struct.pack("!llhhhh", pos1[i], pos2[i], speed1[i], speed2[i], accel1[i], accel2[i])
ser.write(data)
try:
pos1time = abs(pos1[i]/speed1[i])
except:
pos1time = 0
try:
pos2time = abs(pos2[i]/speed2[i])
except:
pos2time = 0
time_array = (pos1time, pos2time)
time.sleep(max(time_array))
motor1pos = ser.readline()
motor2pos = ser.readline()
if i < (len(pos1)-1):
isready = ord(ser.read(1))
else:
isready = 0
except:
print("Error: data not sent. Check serial port is open")
Here is the threading command which I want the sendfile command to work from.
def thread():
try:
global isready
isready = 1
t = threading.Thread(name='sending_data', target=command)
t.start()
except:
print("Threading Error: you don't know what you are doing")
And here is the stop function I want the thread to be killed by:
def stop():
try:
global isready
isready = 0
t.kill()
except:
print("Error: thread wasn't killed")
I know you aren't supposed to kill a thread but the data isn't very important. Whats more important is to stop the motors before something breaks.
The button in tkinter is:
run_file_butt = tk.Button(master = file_frame, text = "Run File", command = thread)
When I click the button, the program runs but the stop function does nothing to stop the motion.
Question: run and kill a thread on a button press
There is no such a thing called .kill(....
Start making your def send_file(... a Thread object which is waiting your commands.
Note: As it stands, your inner while isready == 1: will not stop by using m.set_state('stop').
It's mandatory to start the Thread object inside:
if __name__ == '__main__':
m = MotorControl()
import threading, time
class MotorControl(threading.Thread):
def __init__(self):
super().__init__()
self.state = {'is_alive'}
self.start()
def set_state(self, state):
if state == 'stop':
state = 'idle'
self.state.add(state)
def terminate(self):
self.state = {}
# main function in a Thread object
def run(self):
# Here goes your initalisation
# ...
while 'is_alive' in self.state:
if 'start' in self.state:
isready = 1
while isready == 1:
# Here goes your activity
# Simulate activity
print('running')
time.sleep(2)
isready = 0
self.state = self.state - {'start'}
self.state.add('idle')
elif 'idle' in self.state:
print('idle')
time.sleep(1)
if __name__ == '__main__':
m = MotorControl()
time.sleep(2)
m.set_state('start')
time.sleep(3)
m.set_state('stop')
time.sleep(3)
m.set_state('start')
time.sleep(4)
m.terminate()
print('EXIT __main__')
Your tk.Button should look like:
tk.Button(text = "Run File", command = lambda:m.set_state('start'))
tk.Button(text = "Stop File", command = lambda:m.set_state('stop'))
tk.Button(text = "Terminate", command = m.terminate)
The answer I have gone with is simple due to my simple understanding of threading and unique circumstances with which I am using the threading. Instead of terminating the thread in a way I was hoping, I added another conditional statement to the sending line of the send_file function.
while isready == 1:
for i in range(len(pos1)):
if motorstop == False:
print("Step: " + str(i+1))
#data = struct.pack('!llllhhhhhhhh', pos1[i], pos2[i], pos3[i], pos4[i], speed1[i], speed2[i], speed3[i], speed[4], accel1[i], accel2[i], accel3[i], accel4[i])
data = struct.pack("!llhhhh", pos1[i], pos2[i], speed1[i], speed2[i], accel1[i], accel2[i])
ser.write(data)
else:
isready = 0
break
and I have updated my stop() func to the following:
def stop():
try:
global motorstop
global t
motorstop = True
t.join()
except:
print("Error: thread wasn't killed")
I'm not exactly sure how it works but it is much simpler than what was mentioned by #stovefl.
With this code, since the function is mostly just sleeping, it can run but it won't send any new information and then will .join() after the next iteration.
is there any way for ask question by if statement and after afew sec if user didnot give any answer , if state use a default answer?
inp = input("change music(1) or close the app(2)")
if inp = '1':
print("Music changed)
elif inp = '2':
print("good by")
in this case if user dont give any answer after 30 sec by default if statement choose number 3
from threading import Timer
out_of_time = False
def time_ran_out():
print ('You didn\'t answer in time') # Default answer
out_of_time = True
seconds = 5 # waiting time in seconds
t = Timer(seconds,time_ran_out)
t.start()
inp = input("change music(1) or close the app(2):\n")
if inp != None and not out_of_time:
if inp == '1':
print("Music changed")
elif inp == '2':
print("good by")
else:
print ("Wrong input")
t.cancel()
Timer Objects
This class represents an action that should be run only after a certain amount of time has passed — a timer. Timer is a
subclass of Thread and as such also functions as an example of
creating custom threads.
Timers are started, as with threads, by calling their start() method.
The timer can be stopped (before its action has begun) by calling the
cancel() method. The interval the timer will wait before executing its
action may not be exactly the same as the interval specified by the
user.
For example:
def hello():
print("hello, world")
t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
class threading.Timer(interval, function, args=None, kwargs=None)
Create a timer that will run function with arguments args and keyword
arguments kwargs, after interval seconds have passed. If args is None
(the default) then an empty list will be used. If kwargs is None (the
default) then an empty dict will be used.
cancel()
Stop the timer, and cancel the execution of the timer’s action. This will only work if the timer is still in its waiting
stage.
Here's an alternative way to do it (python 3), using multiprocessing. Note, to get the stdin to work in the child process, you have to re open it first. I'm also converting the input from string to int to use with the multiprocessing value, so you might want to error check there as well.
import multiprocessing as mp
import time
import sys
import os
TIMEOUT = 10
DEFAULT = 3
def get_input(resp: mp.Value, fn):
sys.stdin = os.fdopen(fn)
v = input('change music(1) or close the app (2)')
try:
resp.value = int(v)
except ValueError:
pass # bad input, maybe print error message, try again in loop.
# could also use another mp.Value to signal main to restart the timer
if __name__ == '__main__':
now = time.time()
end = now + TIMEOUT
inp = 0
resp = mp.Value('i', 0)
fn = sys.stdin.fileno()
p = mp.Process(name='Get Input', target=get_input, args=(resp, fn))
p.start()
while True:
t = end - time.time()
print('Checking for timeout: Time = {:.2f}, Resp = {}'.format(t, resp.value))
if t <= 0:
print('Timeout occurred')
p.terminate()
inp = DEFAULT
break
elif resp.value > 0:
print('Response received:', resp.value)
inp = resp.value
break
else:
time.sleep(1)
print()
if inp == 1:
print('Music Changed')
elif inp == 2:
print('Good Bye')
else:
print('Other value:', inp)
If you scroll to the bottom of below; I am trying to return to the first function at the end of my last function using process_records()
. My attempt returns Undefined variable 'process_records'pylint(undefined-variable)
def process_records(self, records, map_data, completed=None, errors=None):
"""Code to execute after webdriver initialization."""
series_not_null = False
try:
num_attempt = 0
for record in records.itertuples(): # not working
print(record)
series_not_null = True
self.navigate_to_search(num_attempt)
self.navigate_to_member(mrn)
self.navigate_to_assessment()
self.add_assessment(record, map_data)
self.driver.switch_to.parent_frame() # not working
sleep(.5)
except Exception as exc:
if series_not_null:
errors = self.process_series_error(exc)
return completed, errors
def navigate_to_search(self, num_attempt):
"""Uses webdriver to navigate to Search tab and select Member Status=All"""
if num_attempt == 0:
page_change_until(self.driver, By.XPATH, './/*[text()="Search"]')
wait_ready_state(self.driver)
else:
self.driver.switch_to.parent_frame()
elem = wait_until(self.driver, By.XPATH, './/*[text()="Search"]')
is_disp_n = 0
while True:
if elem.is_displayed():
break
else:
self.driver.switch_to.parent_frame()
is_disp_n += 1
sleep(1)
if is_disp_n == 20:
raise Exception('Could not find Search tab after 20 tries.')
num_attempt += 1
radio_locator = (By.XPATH, './/*[#type="RADIO"][#value="All"]')
while True:
break_while_timer = datetime.now()
if datetime.now() - break_while_timer > timedelta(seconds=20):
break_while = True
break
try:
if wait_until(self.driver, *radio_locator).is_selected():
pass
else:
wait_until(self.driver, *radio_locator).click()
break
except Exception:
sleep(1)
def navigate_to_member(self, mrn):
"""Finds member"""
wait_until(self.driver, By.XPATH, './/*[#name="MemberIdItem_1"]').clear()
wait_until(self.driver, By.XPATH, './/*[#name="MemberIdItem_1"]').send_keys(f'{mrn}'+Keys.ENTER)
page_change_until(self.driver, By.XPATH, f'.//*[text()="{mrn}"]')
wait_ready_state(self.driver)
def navigate_to_assessment(self):
"""Navigates to the appropriate contact log"""
self.driver.find_element_by_css_selector("div[eventproxy^='memberAssessment']").click() #clicks assessment icon
element = self.driver.find_element_by_xpath(f"//div[contains(text(), '{self.assessment_type}')]")
actions = ActionChains(self.driver)
actions.move_to_element(element).perform()
self.driver.find_element_by_xpath(f"//div[contains(text(), '{self.assessment_type}')]").click()
self.driver.find_element_by_css_selector("div[eventproxy^='createSelectedAssessmentsButton']").click()
def add_assessment(self, record, map_data):
"""Create contact log"""
qna_frame = self.driver.find_element_by_css_selector("iframe[id^='iccc']")
self.driver.switch_to.frame(qna_frame)
pages = self.driver.find_element_by_css_selector("ul[class='nav nav-pills nav-stacked qna-tabs']")
pages = pages.find_elements_by_css_selector("a")
for page in pages:
page.click()
# for record in records.itertuples(): #attempt
questions = self.driver.find_elements_by_css_selector("fieldset")
questions = [question for question in questions if question.text not in ("", " ", None)]
for question in questions[1:]:
q_text = question.find_element_by_css_selector("span[class='question-text ng-binding']").text
questionType = map_data.loc[map_data['question_text'] == q_text, 'question_type'].item()
answer = map_data.loc[map_data['question_text'] == q_text, 'map'].item()
answer = getattr(record, answer)
if answer not in ("", " ", "NaT", "NaN", None):
if questionType == 'checks':
self.choose_checks(question, answer)
else:
try:
if questionType == 'text':
self.driver.implicitly_wait(0)
(question.find_element_by_css_selector("textarea").send_keys(str(answer))
if
question.find_elements_by_css_selector("textarea")
else
question.find_element_by_css_selector("input").send_keys(answer))
self.driver.implicitly_wait(15)
elif questionType == 'date':
try:
answer = answer.strftime('%m/%d/%Y')
question.find_element_by_css_selector("input").send_keys(answer)
# page.click()
except Exception as e:
raise Errors.RequiredDataError('Issues with Assessment Date -- {}'.format(e))
elif questionType == 'radio':
question.find_element_by_css_selector("input[value='{}']".format(answer)).click()
except:
continue
else:
pass
self.driver.find_element_by_css_selector("#publishButton").click()
sleep(3)
WebDriverWait(self.driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".btn.btn-mini.btn-primary"))).click()
process_records()
I have also tried:
self.process_records()
This whole code-block seems to be inside a class. So you should be using self.process_records() to call the function.
The process_records method expects a few positional arguments (apart from self) - you'll probably need to pass those to the function too.
Reddit Bot Question: I'm trying to see if any comment has the phrase "Hello There." in it and if it doesn't have "Hello There." in it, I want it to print "Nothing Found." once and wait until a comment is found. It works like a charm but instead of printing "Nothing Found." once and waiting for another comment, it prints "Nothing Found." repeatedly for an infinite amount of time until a comment comes. I've tried multiple options and ways from multiple forums but I can't seem to get this correct. Here is the code:
def run_bot():
while True:
for comment in r.subreddit("test").comments(limit=10):
comment_text = comment.body.lower()
isMatch = any(string in comment_text for string in words_match)
if comment.id not in cache and isMatch and comment.author != r.user.me():
comment.reply("[GENERAL KENOBI!](https://youtu.be/rEq1Z0bjdwc)\n\n^(*I am a bot, and this action was performed automatically.*)")
print(comment.id)
cache.append(comment.id)
with open("commentcache.txt", "a") as f:
f.write(comment.id + "\n")
print("Resetting in:")
def countdown(n):
while n > 0:
print (n, "...")
n = n - 1
time.sleep(1)
if n ==0:
print("Reset Successful!")
time.sleep(1)
countdown(5)
else:
print("Nothing Found.")
def saved():
if not os.path.isfile("commentcache.txt"):
commentcache = []
else:
with open("commentcache.txt", "r") as f:
commentcache = f.read
commentcache = commentcache().split("\n")
commentcache = list(filter(None, commentcache))
return commentcache
cache = saved()
print(cache)
run_bot()
The trouble starts at:
else:
print("Nothing Found.")
it prints that infinitely.
The easiest way is probably a boolean flag:
print_status = True
while True:
...
if isMatch and ...:
comment.reply("[GENERAL KENOBI!] ...")
...
print_status = True
elif print_status:
print("Nothing found")
print_status = False