Tweepy retweet bot keeps looping - python

So I have been working on a twitter bot for a while now, and I am running into a problem with it. Every time I include the api.retweet() function it runs my function twice. To stop it all I have to do is comment it out. Every time it runs twice it causes an error and kills my program.
I fixed that part with a try except setup, but still it replies twice, and tries to like it twice. I don't understand why it would do it. If I take it out it fixes it completely.
I put print tags to tell me how the loop happens, and it enters the on_data function (Provided by tweepy to check if data has been received), then it enters my check_data (My function to check the data for phrases and tags I wish to filter out) then it goes to my retweet and like function. After it does those it continues back up to the end of my on_data. If there is no retweet, it ends there. If there is one, then it does it all once more before ending.
Streamer class:
class LEDStreamListener(tweepy.StreamListener):
def on_data(self, raw_data):
# with open("tweets.json", "w") as write_file:
# write_file.write(raw_data)
print('at the top boi')
data = json.loads(raw_data)
usr = data['user']['screen_name']
tweet_id = data['id']
if len(data['entities']['hashtags']) != 0:
tag = data['entities']['hashtags'][0]['text']
else:
tag = ''
data_check(usr, tweet_id, tag, counter)
print('here in on_data now')
Data check function:
def data_check(twitter_user, tweet, tag, count):
print('Entering data_check')
if tag == 'HUNTER_LED_OFF':
requests.get('http://192.168.1.172/off')
retweet_tweet(tweet)
api.update_status('I turned the led off for you', tweet)
print('off')
return
elif tag == 'HUNTER_LED_ON':
requests.get('http://192.168.1.172/on')
retweet_tweet(tweet)
api.update_status('I turned the led on for you', tweet)
print('on')
return
elif tag == 'led_test':
retweet_tweet(tweet)
api.update_status('Nice test bro *highfives* keep up the good work', tweet)
print('tested')
return
elif twitter_user == 'realDonaldTrump':
print('Make America Great Again!')
return
else:
return
Retweet function:
def retweet_tweet(tweet_id):
try:
print('re-tweeting')
api.retweet(tweet_id)
api.create_favorite(tweet_id)
print('done re-tweeting')
except tweepy.TweepError as e:
print(e)
Console output of a received tweet with retweets enabled
at the top boi
Entering data_check
re-tweeting
done re-tweeting
off
here in on_data now
at the top boi
Entering data_check
re-tweeting
[{'code': 327, 'message': 'You have already retweeted this Tweet.'}]
off(this is me editing this just says the state of the command it did to my robot)
here in on_data now
Console log of with out the retweet line in the retweet function
at the top boi
Entering data_check
re-tweeting
done re-tweeting
off(this is me editing this just says the state of the command it did to my robot)
here in on_data now

Ok so let's start this off by saying I'm mad at myself, and and currently not on speaking terms with my brain for this. Not sure I'll ever forgive the guy. Basically if you run into this error its because when you re tweet the tweet based on it hashtag, you make a post on your page with the hashtag on it. Tripping the bot to do things. To fix it I just set a variable
text = data['text']
Then in my if statements I checked if the text part of my json file that is now stored in the variable I just made starts with 'RT'. By saying
if tag = '(your hashtag)' and not text.startswith('RT')
I noticed while looking at the json files after I figured it out that they all do it.

Related

How do I make a python bot with selenium that checks when a new message has arrived from a Telegram channel?

I should start off mentioning I am pretty new to python and selenium, so I don't really know much about either of them.
what I am trying to do:
Check every second if a telegram channel I follow has sent out a new message. I have telegram web opened on a browser opened with custom flags so that I don't need to log in with telegram every single time.
So far what I did is see the class that has all the message's text inside of it
im_message_text, and get the last of them in the list.
Source Code
NOTE The "strong" tag is simply where the title is stored in side the text message, which is what i'm using to compare everything:
def getItemsInfo1(self):
try:
iteminfo1 = WebDriverWait(self.driver, 4).until(
EC.presence_of_element_located((By.CLASS_NAME, 'im_message_text')))
list3 = self.driver.find_elements_by_class_name("im_message_text")
list33 = list3[-1]
list4 = list33.find_element_by_tag_name("strong")
list4txt = list4.text
return list4txt
except:
print("Nothing is found")
What I do from here is I make another identical code which has a time.sleep(1) at the start to give the message time to appear, and i compare the 2 using the following while loop:
while Main.getItemsInfo1() == Main.getItemsInfo2():
print("No new messages. Try number ", count)
print(Main.getItemsInfo1(), Main.getItemsInfo2())
count += 1
So far, whilst as soon as there is a new message the code output highlights that the 2 methods have different text, it still does not end the while loop and it continues to say that there aren't any new messages.
Does anyone know how to help?
while Main.getItemsInfo1() == Main.getItemsInfo2():
print("No new messages. Try number ", count)
print(Main.getItemsInfo1(), Main.getItemsInfo2())
count += 1
When you call getItemsInfo1() you are calling the method again , so there is no guarantee that the value is get in print statement is same as what is there in while so use something like:
info1= Main.getItemsInfo1()
info2= Main.getItemsInfo2()
while info == Info2:
print("No new messages. Try number ", count)
info1= Main.getItemsInfo1()
info2= Main.getItemsInfo2()
print(info1,info2)
count += 1
The above code will make sure you are having same value, as you are storing the value to a variable and then validating it .
You don't even need to use telegram web or selenuim either, let's make it much more easier:
‍
from telethon import TelegramClient, events
client = TelegramClient(PHONE_NUMBER, API_ID, API_HASH)
#client.on(events.NewMessage("chanel name"))
def new_message_listener(event):
new_message = event.message.message
media_status = event.message.media
## DO what you like with new_messsage
Just remember to change the variables in the TelegramClient, You can receive API_ID, API_HASH from Telegram website.
They should be like this:
api_id = 1027347
api_hash = "c0e2cfefac982659a52da625b81e2a99"

I want to loop a bot in python

the code of my bot written in python
can someone tell me how to loop because I want to host on https://www.evennode.com/
#import modules
import tweepy
import time
auth = tweepy.OAuthHandler('','') #key
auth.set_access_token('', '') #token
api = tweepy.API(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True)
user = api.me()
search = '#Evangelion' #code
numeroDeTweets = 40 #code
for tweet in tweepy.Cursor(api.search, search).items(numeroDeTweets): #code
try:
print('') #code
tweet.retweet() #code
tweet.favorite() #code
time.sleep(45) #code
except tweepy.TweepError as e: #code
print(e.reason) #code
except StopIteration: #code
break #code
Oh, Evangelion is mentioned here, good. Really good. But jokes aside, as far as i understood you want to infinitely loop through twitter search result. If so, there are two methods which will do it but with the key difference.
If you want to itereate through:
I. Every result possible before updating search queue
If you wan to do so, you just have to remove numeroDeTweets variable from the items() argument and let it iterate:
for tweet in tweepy.Cursor(api.search, search).items(): # No more limits!
try:
# your stuff here
except:
# and here
II. First numeroDeTweets results and then search again
In that case you have to put for cycle into the while True loop to make it infinite and add a time.sleep() to add some cooldown.
So it will look something like that:
while True: # Doing it infinite amount of times
for tweet in tweepy.Cursor(api.search, search).items(numeroDeTweets): #There ARE limits!
try:
# your stuff here
except:
# and here
finally:
time.sleep(45) # Taking rest for search to update

replying to a tweet in tweepy

There's an issue with my code where no matter what I try, every time I reply to a tweet, it just posts as a regular status update on my timeline.
here is a snippet of the code
class StreamListener(tweepy.StreamListener):
def on_status(self, status):
tweetid = status.id
tweetnouser = status.text.replace("#CarlWheezerBot", "")
username = '#'+status.user.screen_name
user_tweet = gTTS(text=tweetnouser, lang='en', slow=False)
# Saving the converted audio
user_tweet.save("useraudio/text2speech.mp3")
# importing the audio and getting the audio all mashed up
text2speech = AudioFileClip("useraudio/text2speech.mp3")
videoclip = VideoFileClip("original_video/original_cut.mp4")
editedAudio = videoclip.audio
# splicing the original audio with the text2speech
compiledAudio = CompositeAudioClip([editedAudio.set_duration(3.8), text2speech.set_start(3.8)])
videoclip.audio = compiledAudio
# saving the completed video fie
videoclip.write_videofile("user_video/edited.mp4", audio_codec='aac')
upload_result = api.media_upload("user_video/edited.mp4")
api.update_status( status='#CarlWheezerBot',in_reply_to_status_id=[tweetid], media_ids=[upload_result.media_id_string], auto_populate_reply_metadata=True)
I have also tried it without any status, as well as using status.id_str. Nothing seems to work., I have done it without the metadata parameter as well. I am following the documentation word for word.
OKAY. for everyone reading this in the future
use this in_reply_to_status_id=tweetid
do not use the square brackets. Everything works perfectly now
While playing around with it, I also noticed that you should also mention author of the tweet you're replying to, especially if you're replying to an existing reply because it will still post it as status update. Line from documentation:
in_reply_to_status_id – The ID of an existing status that the update is in reply to. Note: This parameter will be ignored unless the author of the Tweet this parameter references is mentioned within the status text. Therefore, you must include #username, where username is the author of the referenced Tweet, within the update.

Not receiving a return message in python 2 code

I'm pretty new to python and just learning to ropes. In the code bellow I have a function taking several inputs from a json string. I'm attempting to have a return output in the specified strings. Problem? when I run the file I get nothing... I'm sure I'm missing something incredibly simply, but for the life of me I can't figure out what. I've attempted to use return as well as print at the end of the function. No cheese.
Help?
Here's what I've got so far:
import datetime, json
def jeeves(request): #defines the function
message=''
if request['type']=='maintainance':
message='Thank you tenant at unit'+str(request['unit'])+', your request for maintenance to deal with '+'"'+str(request['issue'])+'"'+' has been received #2 input'
elif request['type']=='purchase':
message='Thank you tenant at unit'+str(request['unit'])+'your request to purchase a'+str(request['commodity'])+ ' has been received'
elif request['type']=='reservation':
startTime=request['date'].split(" ")[1]
startTime=startTime.split('')
time=0;
num=[]
for item in startTime:
if isdigit(item):
num.append(item)
for index in range(len(num)):
time+=num[index]*10**(len(num)-index)
endTime=0
daySplit=''.join(startTime[-2:])
if time+int(request['duration'].split(' ')[0])>12:
endTime=time+int(request['duration'].split(' ')[0])-12
if daySplit=='AM':
endTime=str(endTime)+'PM'
else:
endTime=str(endTime)+'AM'
else:
endTime=endTime+int(request['duration'].split(' ')[0])
endTime=str(endTime)+daySplit
message='Thank you tenant at unit'+str(request['unit'])+'your request to reserve our '+str(request['location'])+' on '+str(request['date'].split(' ')[0])+' from '+str(request['date'].split(' ')[1])+' to '+ endTime+' has been received'
elif request['type']=='complaint':
message='Thank you tenant at unit'+str(request['unit'])+' we will have someone follow up on '+'"'+request['issue']+'"'+' in regards to our '+request['location']
return message
print message
json.dumps(jeeves({"type":"maintenance", "unit":221, "issue":"Air filter needs replacing"}))
ps: I'm new to coding in general. If there is a better, more productive way for me to ask questions, I'm open to feedback. Thank you in advanced.
You have to put return before the print function because when you use return it ends a function. You might also want to check out what return actually does here

Parsing tweets in json format to find tweeter users

I am reading a tweeter feed in json format to read the number of users.
Some lines in the input file might not be tweets, but messages that the Twitter server sent to the developer (such as limit notices). I need to ignore these messages.
These messages would not contain the created_at field and can be filtered out accordingly.
I have written the following piece of code, to extract the valid tweets, and then extract the user.id and the text.
def safe_parse(raw_json):
try:
json_object = json.loads(raw_json)
if 'created_at' in json_object:
return json_object
else:
return
except ValueError as error:
return
def get_usr_txt (line):
tmp = safe_parse(line)
if(tmp != None):
return ((tmp.get('user').get('id_str'),tmp.get('text')))
else:
return
My challenge is that I get one extra user called "None"
Here is a sample output (it is a large file)
('49838600', 'This is the temperament you look for in a guy who would
have access to our nuclear arsenal. ), None, ('2678507624', 'RT
#GrlSmile: #Ricky_Vaughn99 Yep, which is why in 1992 I switched from
Democrat to Republican to vote Pat Buchanan, who warned of all of
t…'),
I am struggling to find out, what I am doing wrong. There is no None in the tweeter file, hence I am assuming that I am reading the
{"limit":{"track":1,"timestamp_ms":"1456249416070"}} but the code above should not include it, unless I am missing something.
Any pointers? and thanks for the your help and your time.
Some lines in the input file might not be tweets, but messages that the Twitter server sent to the developer (such as limit notices). I need to ignore these messages.
That's not exactly what happens. If one of the following happens:
raw_json is not a valid JSON document
created_at is not in the parsed object.
you return with default value, which is None. If you want to ignore these, you can add filter step between two operations:
rdd.map(safe_parse).filter(lambda x: x).map(get_usr_txt)
You can also use flatMap trick to avoid filter and simplify your code (borrowed from this answer by zero323):
def safe_parse(raw_json):
try:
json_object = json.loads(raw_json)
except ValueError as error:
return []
else:
if 'created_at' in json_object:
yield json_object
rdd.flatMap(safe_parse).map(get_usr_txt)

Categories

Resources