I'm trying to create a Twitter bot with Tweepy that will search through the tweets on my timeline, and find tweets matching a particular keyword ("brexit"), and retweet those tweets. My developer account is the same account that I would like to do the retweeting.
I have followed everything, I believe, to the book. This is my code:
import tweepy
from tweepy import OAuthHandler
import time
auth = tweepy.OAuthHandler("XXX", "XXX")
auth.set_access_token("XXX", "XXX")
api = tweepy.API(auth)
class listener(tweepy.StreamListener):
def on_status(self, status):
print("Tweet arrived!")
print("Authors name: %s" % status.author.screen_name)
status.retweet()
time.sleep(10)
def on_error(selfself, status_code):
if status_code == 420:
return False
keywords = ["brexit"]
def search_tweets():
api = tweepy.API(auth)
tweetlistener = listener()
stream = tweepy.Stream(tweepy.api.home_timeline(), listener = tweetlistener)
stream.filter(track=keywords)
search_tweets()
However, I am getting the following error message:
Traceback (most recent call last):
File "C:/Users/borde/Documents/PythonProjects/brexitbot/botcode.py", line 29, in <module>
search_tweets()
File "C:/Users/borde/Documents/PythonProjects/brexitbot/botcode.py", line 26, in search_tweets
stream = tweepy.Stream(tweepy.api.home_timeline(), listener = tweetlistener)
File "C:\Users\borde\AppData\Local\Programs\Python\Python37-32\lib\site-packages\tweepy\binder.py", line 245, in _call
method = APIMethod(args, kwargs)
File "C:\Users\borde\AppData\Local\Programs\Python\Python37-32\lib\site-packages\tweepy\binder.py", line 44, in __init__
raise TweepError('Authentication required!')
tweepy.error.TweepError: Authentication required!
I've tried resetting the keys, to make sure that they hadn't been timed out, but it still isn't working. I also tried changing the listener class so that it just prints out the found tweets, as opposed to retweeting them.
I'm completely new to this, and any help would be appreciated.
Thank you.
If you look at the documentation, you'll see that the first argument to that Stream call should be your instantiated api object's auth attribute:
myStream = tweepy.Stream(auth = api.auth, listener=myStreamListener)
You just instantiated your api TWICE and not using it at all. Delete that duplicate line from search_tweets and instantiate stream like this:
stream = tweepy.Stream(auth=api.auth, listener = tweetlistener)
P.S. you're passing an instance instead of class, c/p the following instead of your function:
def search_tweets():
stream = tweepy.Stream(auth=api.auth, listener=listener)
stream.filter(track=keywords)
Btw, you should name your classes starting with uppercase letter, change class listener(tweepy.StreamListener): to class Listener(tweepy.StreamListener): and in that code I just provided: listener=Listener.
Related
#!/usr/bin/env python
# twitterbots/bots/favretweet.py
import tweepy
import logging
from config import create_api
import seacret
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger()
#stream = tweepy.Stream(seacret.KEY, seacret.SECRET, seacret.TOKEN, seacret.TOKEN_SECRET)
class FavRetweetListener(tweepy.Stream):
def __init__(self, api):
self.api = api
self.user = api.get_user(screen_name='MyGasAndEnergy1')
def on_status(self, tweet):
logger.info(f"Prosessing tweet id {tweet.id}")
if tweet.in_reply_to_status_id is not None or tweet.user.id == self.user.user_id:
return
if not tweet.favorite:
try:
tweet.favorite()
except Exception as e:
logger.error("Error on Fav", exc_info=True)
if not tweet.retweeted:
try:
tweet.retweet()
except Exception as e:
logger.error("Error on vav and retweet", exc_info=True)
def on_error(self, status):
logger.error(status)
def main(keywords):
api = create_api()
tweets_listener = FavRetweetListener(api)
#new way to auth
stream = tweepy.Stream(seacret.KEY, seacret.SECRET, seacret.TOKEN, seacret.TOKEN_SECRET)
#old way to auto + important tweets_listener for actions
stream = tweepy.Stream(api.auth, tweets_listener)
stream.filter(track=keywords, languages=["en"])
if __name__ == "__main__":
main(["Python", "Tweepy"])
I have older code for editing for my use. But this part I can not figure, because of my noobines. Code is suppose to fav and retweet in twitter if it founds suitable keyword.
New code needs:
stream = tweepy.Stream(seacret.KEY, seacret.SECRET, seacret.TOKEN, seacret.TOKEN_SECRET)
Old code needs:
tweets_listener = FavRetweetListener(api)
stream = tweepy.Stream(api.auth, tweets_listener)
But new tweepy don't work with older api.auth method but want all secret tokens to be in tweepy.Stream() and that mean that I can not launch rest of my code via tweets_listener becauce it wont accept anything more.
How can I continue. I haven't found solution for this after googling or/and can not ask proper questions to move on with this problem.
Tweepy is python module/packet for working twitter-things. This script is originally from realpython.com. Problem is that I don't want to downgrade tweepy.
So I need include FavRetweetListener, but I don't have knowledge how I have to refactor code.
I switched to tweepy.Cursor and get it working. Thanks to all. Better question next time.
https://docs.tweepy.org/en/stable/v1_pagination.html#tweepy.Cursor
That's my code. Every thing works well, but when the Twitter Stream should start there comes the following error: Stream encountered HTTP Error: 406
With the normal stream it works well, but with the asynchronous stream it doesn't. Where is my mistake?
import discord
import tweepy
import tweepy.asynchronous
class Stream(tweepy.asynchronous.AsyncStream):
async def on_connect(self):
print("connected")
async def on_status(self, status):
print(status.text)
async def on_exception(self, exception):
print(exception)
print("!exception")
"""async def on_request_error(self, status_code):
print(status_code)"""
#If An error occurs then the programm should be restartet
"""await restart(discord_client=client, twitter_stream = self)"""
async def on_closed(self, resp):
print(resp)
class Client(discord.Client):
async def on_ready(self):
#creating stream
stream = Stream(keys + tokens)
#creating api
auth = tweepy.OAuthHandler(keys)
auth.set_access_token(tokens)
api = tweepy.API(auth)
#getting specific users which the stream should follow
follow_list = [screen_name]
follower_ids = []
for _ in follow_list:
follow = int(api.get_user(screen_name = _).id)
print(follow)
follower_ids.append(follow)
print(str(follower_ids))
#starting Stream
stream.filter(follow = follow_list)
print("start")
client = Client()
client.run(token)
This is likely because you're passing invalid IDs for AsyncStream.filter's follow parameter.
follow_list seems to be a list with a single screen name or a list of screen names, not a list of user IDs. It seems like you might have intended to use follower_ids instead.
A 406 Not Acceptable HTTP Error means:
At least one request parameter is invalid. For example, the filter endpoint returns this status if:
The track keyword is too long or too short.
An invalid bounding box is specified.
Neither the track nor follow parameter are specified.
The follow user ID is not valid.
https://developer.twitter.com/en/docs/twitter-api/v1/tweets/filter-realtime/guides/connecting
I've tried to make a python script that can delete / undo favorite all my twitter favorites for me. I have seen MATHEW INKSON's post to do the job. I don't need to delete my tweets, just want to clear the favorites. Besides that script is almost two years old and incompatible with latest python. So I've edited a little to run it with python 3.6.0 and my script look like this:
import tweepy
from datetime import datetime, timedelta
test_mode = False
verbose = False
delete_favs = True
days_to_keep = 7
consumer_key = 'my consumer key'
consumer_secret = 'my consumer secret'
access_token = 'my access token'
access_token_secret = 'my access token secret'
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)
cutoff_date = datetime.utcnow() - timedelta(days=days_to_keep)
if delete_favs:
print ("Retrieving favorited tweets")
favorites = tweepy.Cursor(api.favorites).items()
unfav_count = 0
kept_count = 0
for tweet in favorites:
if tweet.created_at < cutoff_date:
if verbose:
print ("Unfavoring %d: [%s] %s % (tweet.created_at,tweet.text)")
if not test_mode:
api.destroy_favorite(tweet.id)
unfav_count += 1
else:
kept_count += 1
print ("Unfavored %d tweets, ignored %d" % (unfav_count, kept_count))
But, everytime by running the script on my windows command I am getting this following error:
Traceback (most recent call last):
File "C:\Users\xyz\Desktop\New folder\Unfavorite.py", line 25, in <module>
for tweet in favorites:
File "C:\Users\xyz\AppData\Local\Programs\Python\Python36\lib\site-packages\tweepy-3.6.0-py3.6.egg\tweepy\cursor.py", line 49, in __next__
File "C:\Users\xyz\AppData\Local\Programs\Python\Python36\lib\site-packages\tweepy-3.6.0-py3.6.egg\tweepy\cursor.py", line 197, in next
File "C:\Users\xyz\AppData\Local\Programs\Python\Python36\lib\site-packages\tweepy-3.6.0-py3.6.egg\tweepy\cursor.py", line 108, in next
File "C:\Users\xyz\AppData\Local\Programs\Python\Python36\lib\site-packages\tweepy-3.6.0-py3.6.egg\tweepy\binder.py", line 250, in _call
File "C:\Users\xyz\AppData\Local\Programs\Python\Python36\lib\site-packages\tweepy-3.6.0-py3.6.egg\tweepy\binder.py", line 234, in execute
tweepy.error.TweepError: Twitter error response: status code = 429
I am using Python 3.6, my app's permissions are all correct. Everything is fine with my twitter app. I guess something is wrong with my script.
Please someone help fix my code. I've seen some other script too. Those didn't work out. Suggestions will be appreciated.
Thanks is advance.
As per Twitter response codes, Code 429 is Returned in when a request cannot be served due to the application’s rate limit having been exhausted for the resource. Which means your app has made too many requests and you have to look into API Rate limits.
While running this program to retrieve Twitter data using Python 2.7.8 :
#imports
from tweepy import Stream
from tweepy import OAuthHandler
from tweepy.streaming import StreamListener
#setting up the keys
consumer_key = '…………...'
consumer_secret = '………...'
access_token = '…………...'
access_secret = '……………..'
class TweetListener(StreamListener):
# A listener handles tweets are the received from the stream.
#This is a basic listener that just prints received tweets to standard output
def on_data(self, data):
print (data)
return True
def on_error(self, status):
print (status)
#printing all the tweets to the standard output
auth = OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_secret)
stream = Stream(auth, TweetListener())
t = u"سوريا"
stream.filter(track=[t])
after running this program for 5 hours i got this Error message:
Traceback (most recent call last):
File "/Users/Mona/Desktop/twitter.py", line 32, in <module>
stream.filter(track=[t])
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/tweepy/streaming.py", line 316, in filter
self._start(async)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/tweepy/streaming.py", line 237, in _start
self._run()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/tweepy/streaming.py", line 173, in _run
self._read_loop(resp)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/tweepy/streaming.py", line 225, in _read_loop
next_status_obj = resp.read( int(delimited_string) )
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 543, in read
return self._read_chunked(amt)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 612, in _read_chunked
value.append(self._safe_read(chunk_left))
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 660, in _safe_read
raise IncompleteRead(''.join(s), amt)
IncompleteRead: IncompleteRead(0 bytes read, 976 more expected)
>>>
Actually i don't know what to do with this problem !!!
You should check to see if you're failing to process tweets quickly enough using the stall_warnings parameter.
stream.filter(track=[t], stall_warnings=True)
These messages are handled by Tweepy (check out implementation here) and will inform you if you're falling behind. Falling behind means that you're unable to process tweets as quickly as the Twitter API is sending them to you. From the Twitter docs:
Setting this parameter to the string true will cause periodic messages to be delivered if the client is in danger of being disconnected. These messages are only sent when the client is falling behind, and will occur at a maximum rate of about once every 5 minutes.
In theory, you should receive a disconnect message from the API in this situation. However, that is not always the case:
The streaming API will attempt to deliver a message indicating why a stream was closed. Note that if the disconnect was due to network issues or a client reading too slowly, it is possible that this message will not be received.
The IncompleteRead could also be due to a temporary network issue and may never happen again. If it happens reproducibly after about 5 hours though, falling behind is a pretty good bet.
I've just had this problem. The other answer is factually correct, in that it's almost certainly:
Your program isn't keeping up with the stream
you get a stall warning if that's the case.
In my case, I was reading the tweets into postgres for later analysis, across a fairly dense geographic area, as well as keywords (London, in fact, and about 100 keywords). It's quite possible that, even though you're just printing it, your local machine is doing a bunch of other things, and system processes get priority, so the tweets will back up until Twitter disconnects you. (This is typically manifests as an apparent memory leak - the program increases in size until it gets killed, or twitter disconnects - whichever is first.)
The thing that made sense here was to push off the processing to a queue. So, I used a redis and django-rq solution - it took about 3 hours to implement on dev and then my production server, including researching, installing, rejigging existing code, being stupid about my installation, testing, and misspelling things as I went.
Install redis on your machine
Start the redis server
Install Django-RQ (or just Install RQ if you're working solely in python)
Now, in your django directory (where appropriate - ymmv for straight python applications) run:
python manage.py rqworker &
You now have a queue! You can add jobs to that like by changing your handler like this:
(At top of file)
import django_rq
Then in your handler section:
def on_data(self, data):
django_rq.enqueue(print, data)
return True
As an aside - if you're interested in stuff emanating from Syria, rather than just mentioning Syria, then you could add to the filter like this:
stream.filter(track=[t], locations=[35.6626, 32.7930, 42.4302, 37.2182]
That's a very rough geobox centred on Syria, but which will pick up bits of Iraq/Turkey around the edges. Since this is an optional extra, it's worth pointing this out:
Bounding boxes do not act as filters for other filter parameters. For
example track=twitter&locations=-122.75,36.8,-121.75,37.8 would match
any tweets containing the term Twitter (even non-geo tweets) OR coming
from the San Francisco area.
From this answer, which helped me, and the twitter docs.
Edit: I see from your subsequent posts that you're still going down the road of using Twitter API, so hopefully you got this sorted anyway, but hopefully this will be useful for someone else! :)
This worked for me.
l = StdOutListener()
auth = OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
stream = Stream(auth, l)
while True:
try:
stream.filter(track=['python', 'java'], stall_warnings=True)
except (ProtocolError, AttributeError):
continue
A solution is restarting the stream immediately after catching exception.
# imports
from tweepy import Stream
from tweepy import OAuthHandler
from tweepy.streaming import StreamListener
# setting up the keys
consumer_key = "XXXXX"
consumer_secret = "XXXXX"
access_token = "XXXXXX"
access_secret = "XXXXX"
# printing all the tweets to the standard output
auth = OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_secret)
class TweetListener(StreamListener):
# A listener handles tweets are the received from the stream.
# This is a basic listener that just prints received tweets to standard output
def on_data(self, data):
print(data)
return True
def on_exception(self, exception):
print('exception', exception)
start_stream()
def on_error(self, status):
print(status)
def start_stream():
stream = Stream(auth, TweetListener())
t = u"سوريا"
stream.filter(track=[t])
start_stream()
For me the back end application to which the URL is pointing is directly returning the string
I changed it to
return Response(response=original_message, status=200, content_type='application/text')
in the start I just returned text like
return original_message
I think this answer works only for my case
I am attempting to retrieve data from Twitter, using Tweepy for a username typed at the command line. I'm wanting to extract quite a bit of data about the status and user,so have come up with the following:
Note that I am importing all the required modules ok and have oauth + keys (just not included it here) and filename is correct, just been changed:
# define user to get tweets for. accepts input from user
user = tweepy.api.get_user(input("Please enter the twitter username: "))
# Display basic details for twitter user name
print (" ")
print ("Basic information for", user.name)
print ("Screen Name:", user.screen_name)
print ("Name: ", user.name)
print ("Twitter Unique ID: ", user.id)
print ("Account created at: ", user.created_at)
timeline = api.user_timeline(screen_name=user, include_rts=True, count=100)
for tweet in timeline:
print ("ID:", tweet.id)
print ("User ID:", tweet.user.id)
print ("Text:", tweet.text)
print ("Created:", tweet.created_at)
print ("Geo:", tweet.geo)
print ("Contributors:", tweet.contributors)
print ("Coordinates:", tweet.coordinates)
print ("Favorited:", tweet.favorited)
print ("In reply to screen name:", tweet.in_reply_to_screen_name)
print ("In reply to status ID:", tweet.in_reply_to_status_id)
print ("In reply to status ID str:", tweet.in_reply_to_status_id_str)
print ("In reply to user ID:", tweet.in_reply_to_user_id)
print ("In reply to user ID str:", tweet.in_reply_to_user_id_str)
print ("Place:", tweet.place)
print ("Retweeted:", tweet.retweeted)
print ("Retweet count:", tweet.retweet_count)
print ("Source:", tweet.source)
print ("Truncated:", tweet.truncated)
I would like this eventually to iterate through all of a user's tweets (up to the 3200 limit). First things first though. So far though I have two problems, I get the following error message regarding retweets:
Please enter the twitter username: barackobamaTraceback (most recent call last):
File " usertimeline.py", line 64, in <module>
timeline = api.user_timeline(screen_name=user, count=100, page=1)
File "C:\Python32\lib\site-packages\tweepy-1.4-py3.2.egg\tweepy\binder.py", line 153, in _call
raise TweepError(error_msg)
tweepy.error.TweepError: Twitter error response: status code = 401
Traceback (most recent call last):
File "usertimeline.py", line 42, in <module>
user = tweepy.api.get_user(input("Please enter the twitter username: "))
File "C:\Python32\lib\site-packages\tweepy-1.4-py3.2.egg\tweepy\binder.py", line 153, in _call
raise TweepError(error_msg)
tweepy.error.TweepError: Twitter error response: status code = 404
Passing the username as a variable seems to be a problem also:
Traceback (most recent call last):
File " usertimleline.py", line 64, in <module>
timeline = api.user_timeline(screen_name=user, count=100, page=1)
File "C:\Python32\lib\site-packages\tweepy-1.4-py3.2.egg\tweepy\binder.py", line 153, in _call
raise TweepError(error_msg)
tweepy.error.TweepError: Twitter error response: status code = 401
I've isolated both these errors, i.e. they aren't working together.
Forgive my ignorance, I am not too hot with Twitter APIs but am learning pretty rapidly. Tweepy documentation really does suck and I've done loads of reading round on the net, just can't seem to get this fixed. If I can get this sorted, i'll be posting up some documentation.
I know how to transfer the data into an MySQL db once extracted (it will do that, rather than print to screen) and manipulate it so that I can do stuff with it, it is just getting it out that I am having the problems with. Does anyone have any ideas or is there another method I should be considering?
Any help really appreciated. Cheers
EDIT:
Following on from #Eric Olson's suggestion this morning; I did the following.
1) Created a completely brand new set of Oauth credentials to test.
2) Copied code across to a new script as follows:
Oauth
consumer_key = "(removed)"
consumer_secret = "(removed)"
access_key="88394805-(removed)"
access_secret="(removed)"
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_key, access_secret)
api=tweepy.API(auth)
# confirm account being used for OAuth
print ("API NAME IS: ", api.me().name)
api.update_status("Using Tweepy from the command line")
The first time i run the script, it works fine and updates my status and returns the API name as follows:
>>>
API NAME IS: Chris Howden
Then from that point on I get this:
Traceback (most recent call last):
File "C:/Users/Chris/Dropbox/Uni_2012-3/6CC995 - Independent Studies/Scripts/get Api name and update status.py", line 19, in <module>
api.update_status("Using Tweepy frm the command line")
File "C:\Python32\lib\site-packages\tweepy-1.4-py3.2.egg\tweepy\binder.py", line 153, in _call
raise TweepError(error_msg)
tweepy.error.TweepError: Twitter error response: status code = 403
The only reason I can see for it doing something like this is that it is rejecting the generated access token. I shouldn't need to renew the access token should I?
If you're open to trying another library, you could give rauth a shot. There's already a Twitter example but if you're feeling lazy and just want a working example, here's how I'd modify that demo script:
from rauth import OAuth1Service
# Get a real consumer key & secret from https://dev.twitter.com/apps/new
twitter = OAuth1Service(
name='twitter',
consumer_key='J8MoJG4bQ9gcmGh8H7XhMg',
consumer_secret='7WAscbSy65GmiVOvMU5EBYn5z80fhQkcFWSLMJJu4',
request_token_url='https://api.twitter.com/oauth/request_token',
access_token_url='https://api.twitter.com/oauth/access_token',
authorize_url='https://api.twitter.com/oauth/authorize',
base_url='https://api.twitter.com/1/')
request_token, request_token_secret = twitter.get_request_token()
authorize_url = twitter.get_authorize_url(request_token)
print 'Visit this URL in your browser: ' + authorize_url
pin = raw_input('Enter PIN from browser: ')
session = twitter.get_auth_session(request_token,
request_token_secret,
method='POST',
data={'oauth_verifier': pin})
params = {'screen_name': 'github', # User to pull Tweets from
'include_rts': 1, # Include retweets
'count': 10} # 10 tweets
r = session.get('statuses/user_timeline.json', params=params)
for i, tweet in enumerate(r.json(), 1):
handle = tweet['user']['screen_name'].encode('utf-8')
text = tweet['text'].encode('utf-8')
print '{0}. #{1} - {2}'.format(i, handle, text)
You can run this as-is, but be sure to update the credentials! These are meant for demo purposes only.
Full disclosure, I am the maintainer of rauth.
You're getting 401 response, which means "Unauthorized." (see HTTP status codes)
Your code looks good. Using api.user_timeline(screen_name="some_screen_name") works for me in the old example I have lying around.
I'm guessing you either need to authorize the app, or there is some problem with your OAuth setup.
Maybe you found this already, but here is the short code example that I started from: https://github.com/nloadholtes/tweepy/blob/nloadholtes-examples/examples/oauth.py